Skip to content

Commit 1be7513

Browse files
committed
Fix 1.67 ground polygon regression
The performance improvements #8630 did not take into account the limitation that ground primitives that overlap cannot be batched together. This change uses the `RectangleCollisionChecker` already implemented for `StaticGroundGeometryMaterialBatch` and performs the same check in `StaticGroundGeometryColorBatch`.
1 parent f36a25c commit 1be7513

File tree

2 files changed

+117
-69
lines changed

2 files changed

+117
-69
lines changed

Source/DataSources/StaticGroundGeometryColorBatch.js

+40-29
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ import ShowGeometryInstanceAttribute from '../Core/ShowGeometryInstanceAttribute
88
import GroundPrimitive from '../Scene/GroundPrimitive.js';
99
import BoundingSphereState from './BoundingSphereState.js';
1010
import Property from './Property.js';
11+
import RectangleCollisionChecker from '../Core/RectangleCollisionChecker.js';
1112

1213
var colorScratch = new Color();
1314
var distanceDisplayConditionScratch = new DistanceDisplayCondition();
1415
var defaultDistanceDisplayCondition = new DistanceDisplayCondition();
1516

16-
function Batch(primitives, classificationType, color, key, zIndex) {
17+
function Batch(primitives, classificationType, color, zIndex) {
1718
this.primitives = primitives;
1819
this.zIndex = zIndex;
1920
this.classificationType = classificationType;
2021
this.color = color;
21-
this.key = key;
2222
this.createPrimitive = false;
2323
this.waitingOnCreate = false;
2424
this.primitive = undefined;
@@ -31,13 +31,19 @@ import Property from './Property.js';
3131
this.showsUpdated = new AssociativeArray();
3232
this.itemsToRemove = [];
3333
this.isDirty = false;
34+
this.rectangleCollisionCheck = new RectangleCollisionChecker();
3435
}
3536

37+
Batch.prototype.overlapping = function(rectangle) {
38+
return this.rectangleCollisionCheck.collides(rectangle);
39+
};
40+
3641
Batch.prototype.add = function(updater, instance) {
3742
var id = updater.id;
3843
this.createPrimitive = true;
3944
this.geometry.set(id, instance);
4045
this.updaters.set(id, updater);
46+
this.rectangleCollisionCheck.insert(id, instance.geometry.rectangle);
4147
if (!updater.hasConstantFill || !updater.fillMaterialProperty.isConstant || !Property.isConstant(updater.distanceDisplayConditionProperty)) {
4248
this.updatersWithAttributes.set(id, updater);
4349
} else {
@@ -52,8 +58,10 @@ import Property from './Property.js';
5258

5359
Batch.prototype.remove = function(updater) {
5460
var id = updater.id;
61+
var geometryInstance = this.geometry.get(id);
5562
this.createPrimitive = this.geometry.remove(id) || this.createPrimitive;
5663
if (this.updaters.remove(id)) {
64+
this.rectangleCollisionCheck.remove(id, geometryInstance.geometry.rectangle);
5765
this.updatersWithAttributes.remove(id);
5866
var unsubscribe = this.subscriptions.get(id);
5967
if (defined(unsubscribe)) {
@@ -227,33 +235,39 @@ import Property from './Property.js';
227235
* @private
228236
*/
229237
function StaticGroundGeometryColorBatch(primitives, classificationType) {
230-
this._batches = new AssociativeArray();
238+
this._batches = [];
231239
this._primitives = primitives;
232240
this._classificationType = classificationType;
233241
}
234242

235243
StaticGroundGeometryColorBatch.prototype.add = function(time, updater) {
236244
var instance = updater.createFillGeometryInstance(time);
237245
var batches = this._batches;
238-
// zIndex is a batch breaker, so we'll use that for the key
239246
var zIndex = Property.getValueOrDefault(updater.zIndex, 0);
240-
var batchKey = zIndex;
241247
var batch;
242-
if (batches.contains(batchKey)) {
243-
batch = batches.get(batchKey);
244-
} else {
245-
batch = new Batch(this._primitives, this._classificationType, instance.attributes.color.value, batchKey, zIndex);
246-
batches.set(batchKey, batch);
248+
var length = batches.length;
249+
for (var i = 0; i < length; ++i) {
250+
var item = batches[i];
251+
if (item.zIndex === zIndex &&
252+
!item.overlapping(instance.geometry.rectangle)) {
253+
batch = item;
254+
break;
255+
}
256+
}
257+
258+
if (!defined(batch)) {
259+
batch = new Batch(this._primitives, this._classificationType, instance.attributes.color.value, zIndex);
260+
batches.push(batch);
247261
}
248262
batch.add(updater, instance);
249263
return batch;
250264
};
251265

252266
StaticGroundGeometryColorBatch.prototype.remove = function(updater) {
253-
var batchesArray = this._batches.values;
254-
var count = batchesArray.length;
267+
var batches = this._batches;
268+
var count = batches.length;
255269
for (var i = 0; i < count; ++i) {
256-
if (batchesArray[i].remove(updater)) {
270+
if (batches[i].remove(updater)) {
257271
return;
258272
}
259273
}
@@ -266,15 +280,14 @@ import Property from './Property.js';
266280
//Perform initial update
267281
var isUpdated = true;
268282
var batches = this._batches;
269-
var batchesArray = batches.values;
270-
var batchCount = batchesArray.length;
283+
var batchCount = batches.length;
271284
for (i = 0; i < batchCount; ++i) {
272-
isUpdated = batchesArray[i].update(time) && isUpdated;
285+
isUpdated = batches[i].update(time) && isUpdated;
273286
}
274287

275288
//If any items swapped between batches we need to move them
276289
for (i = 0; i < batchCount; ++i) {
277-
var oldBatch = batchesArray[i];
290+
var oldBatch = batches[i];
278291
var itemsToRemove = oldBatch.itemsToRemove;
279292
var itemsToMoveLength = itemsToRemove.length;
280293
for (var j = 0; j < itemsToMoveLength; j++) {
@@ -287,27 +300,25 @@ import Property from './Property.js';
287300
}
288301

289302
//If we moved anything around, we need to re-build the primitive and remove empty batches
290-
var batchesArrayCopy = batchesArray.slice();
291-
var batchesCopyCount = batchesArrayCopy.length;
292-
for (i = 0; i < batchesCopyCount; ++i) {
293-
var batch = batchesArrayCopy[i];
303+
for (i = batchCount - 1; i >= 0; --i) {
304+
var batch = batches[i];
294305
if (batch.isDirty) {
295-
isUpdated = batchesArrayCopy[i].update(time) && isUpdated;
306+
isUpdated = batches[i].update(time) && isUpdated;
296307
batch.isDirty = false;
297308
}
298309
if (batch.geometry.length === 0) {
299-
batches.remove(batch.key);
310+
batches.splice(i, 1);
300311
}
301312
}
302313

303314
return isUpdated;
304315
};
305316

306317
StaticGroundGeometryColorBatch.prototype.getBoundingSphere = function(updater, result) {
307-
var batchesArray = this._batches.values;
308-
var batchCount = batchesArray.length;
318+
var batches = this._batches;
319+
var batchCount = batches.length;
309320
for (var i = 0; i < batchCount; ++i) {
310-
var batch = batchesArray[i];
321+
var batch = batches[i];
311322
if (batch.contains(updater)) {
312323
return batch.getBoundingSphere(updater, result);
313324
}
@@ -317,10 +328,10 @@ import Property from './Property.js';
317328
};
318329

319330
StaticGroundGeometryColorBatch.prototype.removeAllPrimitives = function() {
320-
var batchesArray = this._batches.values;
321-
var batchCount = batchesArray.length;
331+
var batches = this._batches;
332+
var batchCount = batches.length;
322333
for (var i = 0; i < batchCount; ++i) {
323-
batchesArray[i].removeAllPrimitives();
334+
batches[i].removeAllPrimitives();
324335
}
325336
};
326337
export default StaticGroundGeometryColorBatch;

Specs/DataSources/StaticGroundGeometryColorBatchSpec.js

+77-40
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { ApproximateTerrainHeights } from '../../Source/Cesium.js';
22
import { Cartesian3 } from '../../Source/Cesium.js';
33
import { Color } from '../../Source/Cesium.js';
4-
import { defaultValue } from '../../Source/Cesium.js';
54
import { DistanceDisplayCondition } from '../../Source/Cesium.js';
65
import { JulianDate } from '../../Source/Cesium.js';
76
import { Math as CesiumMath } from '../../Source/Cesium.js';
@@ -37,10 +36,6 @@ describe('DataSources/StaticGroundGeometryColorBatch', function() {
3736
ApproximateTerrainHeights._terrainHeights = undefined;
3837
});
3938

40-
function computeKey(zIndex) {
41-
return defaultValue(zIndex, 0);
42-
}
43-
4439
it('updates color attribute after rebuilding primitive', function() {
4540
if (!GroundPrimitive.isSupported(scene)) {
4641
return;
@@ -72,13 +67,10 @@ describe('DataSources/StaticGroundGeometryColorBatch', function() {
7267
var primitive = scene.groundPrimitives.get(0);
7368
var attributes = primitive.getGeometryInstanceAttributes(entity);
7469
var red = [255, 0, 0, 255];
75-
var redKey = computeKey();
7670
expect(attributes.color).toEqual(red);
7771

78-
// Verify we have 1 batch with the key for red
72+
// Verify we have 1 batch
7973
expect(batch._batches.length).toEqual(1);
80-
expect(batch._batches.contains(redKey)).toBe(true);
81-
expect(batch._batches.get(redKey).key).toEqual(redKey);
8274

8375
entity.ellipse.material = Color.GREEN;
8476
updater._onEntityPropertyChanged(entity, 'ellipse');
@@ -94,19 +86,55 @@ describe('DataSources/StaticGroundGeometryColorBatch', function() {
9486
var primitive = scene.groundPrimitives.get(0);
9587
var attributes = primitive.getGeometryInstanceAttributes(entity);
9688
var green = [0, 128, 0, 255];
97-
var greenKey = computeKey();
9889
expect(attributes.color).toEqual(green);
9990

10091
// Verify we have 1 batch with the key for green
10192
expect(batch._batches.length).toEqual(1);
102-
expect(batch._batches.contains(greenKey)).toBe(true);
103-
expect(batch._batches.get(greenKey).key).toEqual(greenKey);
10493

10594
batch.removeAllPrimitives();
10695
});
10796
});
10897
});
10998

99+
it('batches overlapping geometry separately', function() {
100+
if (!GroundPrimitive.isSupported(scene)) {
101+
return;
102+
}
103+
104+
var batch = new StaticGroundGeometryColorBatch(scene.groundPrimitives, ClassificationType.BOTH);
105+
var entity = new Entity({
106+
position : new Cartesian3(1234, 5678, 9101112),
107+
ellipse : {
108+
semiMajorAxis : 2,
109+
semiMinorAxis : 1,
110+
show : new CallbackProperty(function() {
111+
return true;
112+
}, false),
113+
material : Color.RED
114+
}
115+
});
116+
117+
var entity2 = new Entity({
118+
position : new Cartesian3(1234, 5678, 9101112),
119+
ellipse : {
120+
semiMajorAxis : 2,
121+
semiMinorAxis : 1,
122+
show : new CallbackProperty(function() {
123+
return true;
124+
}, false),
125+
material : Color.RED
126+
}
127+
});
128+
129+
var updater = new EllipseGeometryUpdater(entity, scene);
130+
batch.add(time, updater);
131+
132+
var updater2 = new EllipseGeometryUpdater(entity2, scene);
133+
batch.add(time, updater2);
134+
135+
expect(batch._batches.length).toEqual(2);
136+
});
137+
110138
it('updates with sampled distance display condition out of range', function() {
111139
var validTime = JulianDate.fromIso8601('2018-02-14T04:10:00+1100');
112140
var outOfRangeTime = JulianDate.fromIso8601('2018-02-14T04:20:00+1100');
@@ -205,18 +233,6 @@ describe('DataSources/StaticGroundGeometryColorBatch', function() {
205233
}
206234

207235
var batch = new StaticGroundGeometryColorBatch(scene.groundPrimitives, ClassificationType.BOTH);
208-
function buildEntity() {
209-
return new Entity({
210-
position : new Cartesian3(1234, 5678, 9101112),
211-
ellipse : {
212-
semiMajorAxis : 2,
213-
semiMinorAxis : 1,
214-
height : 0,
215-
outline : true,
216-
outlineColor : Color.RED.withAlpha(0.5)
217-
}
218-
});
219-
}
220236

221237
function renderScene() {
222238
scene.initializeFrame();
@@ -225,8 +241,25 @@ describe('DataSources/StaticGroundGeometryColorBatch', function() {
225241
return isUpdated;
226242
}
227243

228-
var entity1 = buildEntity();
229-
var entity2 = buildEntity();
244+
var entity1 = new Entity({
245+
position : new Cartesian3(1234, 5678, 9101112),
246+
ellipse : {
247+
semiMajorAxis : 0.2,
248+
semiMinorAxis : 0.1,
249+
outline : true,
250+
outlineColor : Color.RED.withAlpha(0.5)
251+
}
252+
});
253+
254+
var entity2 = new Entity({
255+
position : new Cartesian3(1234, 4678, 9101112),
256+
ellipse : {
257+
semiMajorAxis : 0.2,
258+
semiMinorAxis : 0.1,
259+
outline : true,
260+
outlineColor : Color.RED.withAlpha(0.5)
261+
}
262+
});
230263

231264
var updater1 = new EllipseGeometryUpdater(entity1, scene);
232265
var updater2 = new EllipseGeometryUpdater(entity2, scene);
@@ -272,18 +305,6 @@ describe('DataSources/StaticGroundGeometryColorBatch', function() {
272305
}
273306

274307
var batch = new StaticGroundGeometryColorBatch(scene.groundPrimitives, ClassificationType.BOTH);
275-
function buildEntity() {
276-
return new Entity({
277-
position : new Cartesian3(1234, 5678, 9101112),
278-
ellipse : {
279-
semiMajorAxis : 2,
280-
semiMinorAxis : 1,
281-
height : 0,
282-
outline : true,
283-
outlineColor : Color.RED.withAlpha(0.5)
284-
}
285-
});
286-
}
287308

288309
function renderScene() {
289310
scene.initializeFrame();
@@ -292,11 +313,27 @@ describe('DataSources/StaticGroundGeometryColorBatch', function() {
292313
return isUpdated;
293314
}
294315

295-
var entity1 = buildEntity();
316+
var entity1 = new Entity({
317+
position : new Cartesian3(1234, 5678, 9101112),
318+
ellipse : {
319+
semiMajorAxis : 0.2,
320+
semiMinorAxis : 0.1,
321+
outline : true,
322+
outlineColor : Color.RED.withAlpha(0.5)
323+
}
324+
});
296325
var updater1 = new EllipseGeometryUpdater(entity1, scene);
297326
batch.add(time, updater1);
298327

299-
var entity2 = buildEntity();
328+
var entity2 = new Entity({
329+
position : new Cartesian3(1234, 4678, 9101112),
330+
ellipse : {
331+
semiMajorAxis : 0.2,
332+
semiMinorAxis : 0.1,
333+
outline : true,
334+
outlineColor : Color.RED.withAlpha(0.5)
335+
}
336+
});
300337
var updater2 = new EllipseGeometryUpdater(entity2, scene);
301338

302339
return pollToPromise(renderScene)

0 commit comments

Comments
 (0)