Skip to content

Commit 981273b

Browse files
committed
Fix #7120 by picking through primitives that don't write depth for sampleHeight and clampToHeight
1 parent eaa858b commit 981273b

File tree

2 files changed

+119
-41
lines changed

2 files changed

+119
-41
lines changed

Source/Scene/Scene.js

+47-41
Original file line numberDiff line numberDiff line change
@@ -3529,16 +3529,7 @@ define([
35293529
return result;
35303530
};
35313531

3532-
function isExcluded(object, objectsToExclude) {
3533-
if (!defined(objectsToExclude) || objectsToExclude.length === 0) {
3534-
return false;
3535-
}
3536-
return (objectsToExclude.indexOf(object) > -1) ||
3537-
(objectsToExclude.indexOf(object.primitive) > -1) ||
3538-
(objectsToExclude.indexOf(object.id) > -1);
3539-
}
3540-
3541-
function drillPick(limit, pickCallback, objectsToExclude) {
3532+
function drillPick(limit, pickCallback) {
35423533
// PERFORMANCE_IDEA: This function calls each primitive's update for each pass. Instead
35433534
// we could update the primitive once, and then just execute their commands for each pass,
35443535
// and cull commands for picked primitives. e.g., base on the command's owner.
@@ -3556,6 +3547,7 @@ define([
35563547
while (defined(pickedResult)) {
35573548
var object = pickedResult.object;
35583549
var position = pickedResult.position;
3550+
var exclude = pickedResult.exclude;
35593551

35603552
if (defined(position) && !defined(object)) {
35613553
result.push(pickedResult);
@@ -3566,7 +3558,7 @@ define([
35663558
break;
35673559
}
35683560

3569-
if (!isExcluded(object, objectsToExclude)) {
3561+
if (!exclude) {
35703562
result.push(pickedResult);
35713563
if (0 >= --limit) {
35723564
break;
@@ -3645,7 +3637,9 @@ define([
36453637
var object = that.pick(windowPosition, width, height);
36463638
if (defined(object)) {
36473639
return {
3648-
object : object
3640+
object : object,
3641+
position : undefined,
3642+
exclude : false
36493643
};
36503644
}
36513645
};
@@ -3744,7 +3738,16 @@ define([
37443738
});
37453739
}
37463740

3747-
function getRayIntersection(scene, ray, async) {
3741+
function isExcluded(object, objectsToExclude) {
3742+
if (!defined(object) || !defined(objectsToExclude) || objectsToExclude.length === 0) {
3743+
return false;
3744+
}
3745+
return (objectsToExclude.indexOf(object) > -1) ||
3746+
(objectsToExclude.indexOf(object.primitive) > -1) ||
3747+
(objectsToExclude.indexOf(object.id) > -1);
3748+
}
3749+
3750+
function getRayIntersection(scene, ray, objectsToExclude, async, requirePosition) {
37483751
var context = scene._context;
37493752
var uniformState = context.uniformState;
37503753
var frameState = scene._frameState;
@@ -3798,40 +3801,45 @@ define([
37983801
if (defined(object) || defined(position)) {
37993802
return {
38003803
object : object,
3801-
position : position
3804+
position : position,
3805+
exclude : (!defined(position) && requirePosition) || isExcluded(object, objectsToExclude)
38023806
};
38033807
}
38043808
}
38053809

3806-
function getRayIntersections(scene, ray, limit, objectsToExclude, async) {
3810+
function getRayIntersections(scene, ray, limit, objectsToExclude, async, requirePosition) {
38073811
//>>includeStart('debug', pragmas.debug);
38083812
Check.defined('ray', ray);
38093813
if (scene._mode !== SceneMode.SCENE3D) {
38103814
throw new DeveloperError('Ray intersections are only supported in 3D mode.');
38113815
}
38123816
//>>includeEnd('debug');
38133817
var pickCallback = function() {
3814-
return getRayIntersection(scene, ray, async);
3818+
return getRayIntersection(scene, ray, objectsToExclude, async, requirePosition);
38153819
};
3816-
return drillPick(limit, pickCallback, objectsToExclude);
3820+
return drillPick(limit, pickCallback);
38173821
}
38183822

3819-
function pickFromRay(scene, ray, objectsToExclude, async) {
3820-
var results = getRayIntersections(scene, ray, 1, objectsToExclude, async);
3823+
function pickFromRay(scene, ray, objectsToExclude, async, requirePosition) {
3824+
var results = getRayIntersections(scene, ray, 1, objectsToExclude, async, requirePosition);
38213825
if (results.length > 0) {
38223826
return results[0];
38233827
}
38243828
}
38253829

3826-
function drillPickFromRay(scene, ray, limit, objectsToExclude, async) {
3827-
return getRayIntersections(scene, ray, limit, objectsToExclude, async);
3830+
function drillPickFromRay(scene, ray, limit, objectsToExclude, async, requirePosition) {
3831+
return getRayIntersections(scene, ray, limit, objectsToExclude, async, requirePosition);
38283832
}
38293833

38303834
/**
38313835
* Returns an object containing the first object intersected by the ray and the position of intersection,
38323836
* or <code>undefined</code> if there were no intersections. The intersected object has a <code>primitive</code>
38333837
* property that contains the intersected primitive. Other properties may be set depending on the type of primitive
38343838
* and may be used to further identify the picked object. The ray must be given in world coordinates.
3839+
* <p>
3840+
* This function only picks globe tiles and 3D Tiles that are rendered in the current view. Picks all other
3841+
* primitives regardless of their visibility.
3842+
* </p>
38353843
*
38363844
* @private
38373845
*
@@ -3842,7 +3850,7 @@ define([
38423850
* @exception {DeveloperError} Ray intersections are only supported in 3D mode.
38433851
*/
38443852
Scene.prototype.pickFromRay = function(ray, objectsToExclude) {
3845-
return pickFromRay(this, ray, objectsToExclude, false);
3853+
return pickFromRay(this, ray, objectsToExclude, false, false);
38463854
};
38473855

38483856
/**
@@ -3851,6 +3859,10 @@ define([
38513859
* properties may also be set depending on the type of primitive and may be used to further identify the picked object.
38523860
* The primitives in the list are ordered by first intersection to last intersection. The ray must be given in
38533861
* world coordinates.
3862+
* <p>
3863+
* This function only picks globe tiles and 3D Tiles that are rendered in the current view. Picks all other
3864+
* primitives regardless of their visibility.
3865+
* </p>
38543866
*
38553867
* @private
38563868
*
@@ -3862,7 +3874,7 @@ define([
38623874
* @exception {DeveloperError} Ray intersections are only supported in 3D mode.
38633875
*/
38643876
Scene.prototype.drillPickFromRay = function(ray, limit, objectsToExclude) {
3865-
return drillPickFromRay(this, ray, limit, objectsToExclude, false);
3877+
return drillPickFromRay(this, ray, limit, objectsToExclude, false, false);
38663878
};
38673879

38683880
/**
@@ -3882,7 +3894,7 @@ define([
38823894
ray = Ray.clone(ray);
38833895
objectsToExclude = objectsToExclude.slice();
38843896
return launchAsyncLoader(this, ray, objectsToExclude, function() {
3885-
return pickFromRay(that, ray, objectsToExclude, true);
3897+
return pickFromRay(that, ray, objectsToExclude, true, false);
38863898
});
38873899
};
38883900

@@ -3904,7 +3916,7 @@ define([
39043916
ray = Ray.clone(ray);
39053917
objectsToExclude = objectsToExclude.slice();
39063918
return launchAsyncLoader(this, ray, objectsToExclude, function() {
3907-
return drillPickFromRay(that, ray, limit, objectsToExclude, true);
3919+
return drillPickFromRay(that, ray, limit, objectsToExclude, true, false);
39083920
});
39093921
};
39103922

@@ -3945,7 +3957,7 @@ define([
39453957
function sampleHeightMostDetailed(scene, position, objectsToExclude) {
39463958
var ray = getRayForSampleHeight(scene, position);
39473959
return launchAsyncLoader(scene, ray, objectsToExclude, function() {
3948-
var pickResult = pickFromRay(scene, ray, objectsToExclude, true);
3960+
var pickResult = pickFromRay(scene, ray, objectsToExclude, true, true);
39493961
if (defined(pickResult)) {
39503962
return getHeightFromCartesian(scene, pickResult.position);
39513963
}
@@ -3955,7 +3967,7 @@ define([
39553967
function clampToHeightMostDetailed(scene, cartesian, objectsToExclude) {
39563968
var ray = getRayForClampToHeight(scene, cartesian);
39573969
return launchAsyncLoader(scene, ray, objectsToExclude, function() {
3958-
var pickResult = pickFromRay(scene, ray, objectsToExclude, true);
3970+
var pickResult = pickFromRay(scene, ray, objectsToExclude, true, true);
39593971
if (defined(pickResult)) {
39603972
return pickResult.position;
39613973
}
@@ -3989,7 +4001,7 @@ define([
39894001
}
39904002
//>>includeEnd('debug');
39914003
var ray = getRayForSampleHeight(this, position);
3992-
var pickResult = pickFromRay(this, ray, objectsToExclude, false);
4004+
var pickResult = pickFromRay(this, ray, objectsToExclude, false, true);
39934005
if (defined(pickResult)) {
39944006
return getHeightFromCartesian(this, pickResult.position);
39954007
}
@@ -4024,7 +4036,7 @@ define([
40244036
}
40254037
//>>includeEnd('debug');
40264038
var ray = getRayForClampToHeight(this, cartesian);
4027-
var pickResult = pickFromRay(this, ray, objectsToExclude, false);
4039+
var pickResult = pickFromRay(this, ray, objectsToExclude, false, true);
40284040
if (defined(pickResult)) {
40294041
return Cartesian3.clone(pickResult.position, result);
40304042
}
@@ -4034,9 +4046,9 @@ define([
40344046
* Initiates an asynchronous {@link Scene#sampleHeight} request using the maximum level of detail for 3D Tilesets
40354047
* regardless of visibility.
40364048
*
4037-
* @param {Cartographic|Cartographic[]} positions The cartographic position(s) to sample height from.
4049+
* @param {Cartographic[]} positions The cartographic positions to sample height from.
40384050
* @param {Object[]} [objectsToExclude] A list of primitives, entities, or features to not sample height from.
4039-
* @returns {Promise.<Number|Number[]>} A promise that resolves to the height(s), or <code>undefined</code> if there was no scene geometry to sample height from.
4051+
* @returns {Promise.<Number[]>} A promise that resolves to the heights, or <code>undefined</code> if there was no scene geometry to sample height from.
40404052
*
40414053
* @see Scene#sampleHeight
40424054
*
@@ -4051,24 +4063,21 @@ define([
40514063
}
40524064
//>>includeEnd('debug');
40534065
objectsToExclude = defined(objectsToExclude) ? objectsToExclude.slice() : objectsToExclude;
4054-
positions = isArray(positions) ? positions : [positions];
40554066
var length = positions.length;
40564067
var promises = new Array(length);
40574068
for (var i = 0; i < length; ++i) {
40584069
promises[i] = sampleHeightMostDetailed(this, positions[i], objectsToExclude);
40594070
}
4060-
return when.all(promises).then(function(heights) {
4061-
return (length === 1) ? heights[0] : heights;
4062-
});
4071+
return when.all(promises);
40634072
};
40644073

40654074
/**
40664075
* Initiates an asynchronous {@link Scene#clampToHeight} request using the maximum level of detail for 3D Tilesets
40674076
* regardless of visibility.
40684077
*
4069-
* @param {Cartesian3} cartesians The cartesian positions.
4078+
* @param {Cartesian3[]} cartesians The cartesian positions.
40704079
* @param {Object[]} [objectsToExclude] A list of primitives, entities, or features to not clamp to.
4071-
* @returns {Promise.<Cartesian3|Cartesian3[]>} A promise that resolves to the clamped cartesian position(s), or <code>undefined</code> if there was no scene geometry to clamp to.
4080+
* @returns {Promise.<Cartesian3[]>} A promise that resolves to the clamped cartesian positions, or <code>undefined</code> if there was no scene geometry to clamp to.
40724081
*
40734082
* @see Scene#clampToHeight
40744083
*
@@ -4083,15 +4092,12 @@ define([
40834092
}
40844093
//>>includeEnd('debug');
40854094
objectsToExclude = defined(objectsToExclude) ? objectsToExclude.slice() : objectsToExclude;
4086-
cartesians = isArray(cartesians) ? cartesians : [cartesians];
40874095
var length = cartesians.length;
40884096
var promises = new Array(length);
40894097
for (var i = 0; i < length; ++i) {
40904098
promises[i] = clampToHeightMostDetailed(this, cartesians[i], objectsToExclude);
40914099
}
4092-
return when.all(promises).then(function(cartesians) {
4093-
return (length === 1) ? cartesians[0] : cartesians;
4094-
});
4100+
return when.all(promises);
40954101
};
40964102

40974103
/**

Specs/Scene/PickSpec.js

+72
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ defineSuite([
1717
'Scene/Cesium3DTileStyle',
1818
'Scene/EllipsoidSurfaceAppearance',
1919
'Scene/Globe',
20+
'Scene/PointPrimitiveCollection',
2021
'Scene/Primitive',
2122
'Scene/Scene',
2223
'Scene/SceneMode',
@@ -43,6 +44,7 @@ defineSuite([
4344
Cesium3DTileStyle,
4445
EllipsoidSurfaceAppearance,
4546
Globe,
47+
PointPrimitiveCollection,
4648
Primitive,
4749
Scene,
4850
SceneMode,
@@ -541,6 +543,19 @@ defineSuite([
541543
}, primitiveRay);
542544
});
543545

546+
it('picks primitive that doesn\'t write depth', function() {
547+
var collection = scene.primitives.add(new PointPrimitiveCollection());
548+
var point = collection.add({
549+
position : Cartographic.fromRadians(0.0, 0.0, 100.0),
550+
disableDepthTestDistance : Number.POSITIVE_INFINITY
551+
});
552+
553+
expect(scene).toPickFromRayAndCall(function(result) {
554+
expect(result.object.primitive).toBe(point);
555+
expect(result.position).toBeUndefined();
556+
}, primitiveRay);
557+
});
558+
544559
it('throws if ray is undefined', function() {
545560
expect(function() {
546561
scene.pickFromRay(undefined);
@@ -889,6 +904,35 @@ defineSuite([
889904
}, cartographic, [rectangle2, rectangle3]);
890905
});
891906

907+
it('excludes objects that don\'t write depth', function() {
908+
if (!scene.sampleHeightSupported) {
909+
return;
910+
}
911+
912+
var rectangle = createSmallRectangle(0.0);
913+
914+
var height = 100.0;
915+
var cartographic = new Cartographic(0.0, 0.0, height);
916+
var collection = scene.primitives.add(new PointPrimitiveCollection());
917+
var point = collection.add({
918+
position : Cartographic.toCartesian(cartographic)
919+
});
920+
921+
expect(scene).toSampleHeightAndCall(function(height) {
922+
expect(height).toEqualEpsilon(height, CesiumMath.EPSILON3);
923+
}, cartographic);
924+
925+
point.disableDepthTestDistance = Number.POSITIVE_INFINITY;
926+
expect(scene).toSampleHeightAndCall(function(height) {
927+
expect(height).toEqualEpsilon(0.0, CesiumMath.EPSILON3);
928+
}, cartographic);
929+
930+
rectangle.show = false;
931+
expect(scene).toSampleHeightAndCall(function(height) {
932+
expect(height).toBeUndefined();
933+
}, cartographic);
934+
});
935+
892936
it('throws if position is undefined', function() {
893937
if (!scene.sampleHeightSupported) {
894938
return;
@@ -1027,6 +1071,34 @@ defineSuite([
10271071
}, cartesian, [rectangle2, rectangle3]);
10281072
});
10291073

1074+
it('excludes objects that don\'t write depth', function() {
1075+
if (!scene.clampToHeightSupported) {
1076+
return;
1077+
}
1078+
1079+
var rectangle = createSmallRectangle(0.0);
1080+
1081+
var cartesian = Cartesian3.fromRadians(0.0, 0.0, 100.0);
1082+
var collection = scene.primitives.add(new PointPrimitiveCollection());
1083+
var point = collection.add({
1084+
position : cartesian
1085+
});
1086+
1087+
expect(scene).toClampToHeightAndCall(function(clampedCartesian) {
1088+
expect(clampedCartesian).toEqualEpsilon(cartesian, CesiumMath.EPSILON3);
1089+
}, cartesian);
1090+
1091+
point.disableDepthTestDistance = Number.POSITIVE_INFINITY;
1092+
expect(scene).toClampToHeightAndCall(function(clampedCartesian) {
1093+
expect(clampedCartesian).toEqualEpsilon(cartesian, CesiumMath.EPSILON3);
1094+
}, cartesian);
1095+
1096+
rectangle.show = false;
1097+
expect(scene).toClampToHeightAndCall(function(clampedCartesian) {
1098+
expect(clampedCartesian).toBeUndefined();
1099+
}, cartesian);
1100+
});
1101+
10301102
it('throws if cartesian is undefined', function() {
10311103
if (!scene.clampToHeightSupported) {
10321104
return;

0 commit comments

Comments
 (0)