Skip to content

Commit debd74e

Browse files
authored
Merge pull request #9961 from DanielLeone/fastPickingWithOctree
Fast terrain picking (via quadtree)
2 parents a1419b2 + d063514 commit debd74e

18 files changed

+1432
-204
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#### Additions :tada:
1212

1313
- Added `scene.pickAsync` for non GPU blocking picking using WebGL2 [#12983](https://github.com/CesiumGS/cesium/pull/12983)
14+
- Improves performance of terrain picks via new terrain picking quadtrees [#8481](https://github.com/CesiumGS/cesium/issues/8481)
1415

1516
## 1.135 - 2025-11-03
1617

packages/engine/Source/Core/AxisAlignedBoundingBox.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,30 @@ AxisAlignedBoundingBox.intersectPlane = function (box, plane) {
222222
return Intersect.INTERSECTING;
223223
};
224224

225+
/**
226+
* Determines whether two axis aligned bounding boxes intersect.
227+
*
228+
* @param {AxisAlignedBoundingBox} box first box
229+
* @param {AxisAlignedBoundingBox} other second box
230+
* @returns {boolean} <code>true</code> if the boxes intersect; otherwise, <code>false</code>.
231+
*/
232+
AxisAlignedBoundingBox.intersectAxisAlignedBoundingBox = function (box, other) {
233+
//>>includeStart('debug', pragmas.debug);
234+
Check.defined("box", box);
235+
Check.defined("other", other);
236+
//>>includeEnd('debug');
237+
238+
// This short circuits in favor of AABBs that do not intersect.
239+
return (
240+
box.minimum.x <= other.maximum.x &&
241+
box.maximum.x >= other.minimum.x &&
242+
box.minimum.y <= other.maximum.y &&
243+
box.maximum.y >= other.minimum.y &&
244+
box.minimum.z <= other.maximum.z &&
245+
box.maximum.z >= other.minimum.z
246+
);
247+
};
248+
225249
/**
226250
* Duplicates this AxisAlignedBoundingBox instance.
227251
*
@@ -245,6 +269,18 @@ AxisAlignedBoundingBox.prototype.intersectPlane = function (plane) {
245269
return AxisAlignedBoundingBox.intersectPlane(this, plane);
246270
};
247271

272+
/**
273+
* Determines whether some other axis aligned bounding box intersects this box.
274+
*
275+
* @param {AxisAlignedBoundingBox} other The other axis aligned bounding box.
276+
* @returns {boolean} <code>true</code> if the boxes intersect; otherwise, <code>false</code>.
277+
*/
278+
AxisAlignedBoundingBox.prototype.intersectAxisAlignedBoundingBox = function (
279+
other,
280+
) {
281+
return AxisAlignedBoundingBox.intersectAxisAlignedBoundingBox(this, other);
282+
};
283+
248284
/**
249285
* Compares this AxisAlignedBoundingBox against the provided AxisAlignedBoundingBox componentwise and returns
250286
* <code>true</code> if they are equal, <code>false</code> otherwise.

packages/engine/Source/Core/Cesium3DTilesTerrainData.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ Cesium3DTilesTerrainData.prototype.createMesh = function (options) {
305305
vertexCountWithoutSkirts,
306306
minimumHeight,
307307
maximumHeight,
308+
rectangle,
308309
boundingSphere,
309310
horizonOcclusionPoint,
310311
encoding.stride,
@@ -831,6 +832,7 @@ function upsampleMesh(
831832
vertexCountWithoutSkirts,
832833
minimumHeight,
833834
maximumHeight,
835+
upsampleRectangle,
834836
boundingSphere,
835837
horizonOcclusionPoint,
836838
stride,

packages/engine/Source/Core/Cesium3DTilesTerrainGeometryProcessor.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ Cesium3DTilesTerrainGeometryProcessor.createMesh = async function (options) {
384384
vertexCountWithoutSkirts,
385385
minimumHeight,
386386
maximumHeight,
387+
rectangle,
387388
BoundingSphere.clone(boundingSphere, new BoundingSphere()),
388389
Cartesian3.clone(horizonOcclusionPoint, new Cartesian3()),
389390
tempBufferStride,
@@ -1063,6 +1064,7 @@ Cesium3DTilesTerrainGeometryProcessor.upsampleMesh = function (options) {
10631064
upsampledVertexCountWithoutSkirts,
10641065
minimumHeight,
10651066
maximumHeight,
1067+
upsampleRectangle,
10661068
BoundingSphere.clone(boundingSphere),
10671069
Cartesian3.clone(horizonOcclusionPoint),
10681070
upsampledVertexBufferStride,

packages/engine/Source/Core/GoogleEarthEnterpriseTerrainData.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ GoogleEarthEnterpriseTerrainData.prototype.createMesh = function (options) {
210210
result.vertexCountWithoutSkirts,
211211
result.minimumHeight,
212212
result.maximumHeight,
213+
rectangleScratch,
213214
BoundingSphere.clone(result.boundingSphere3D),
214215
Cartesian3.clone(result.occludeePointInScaledSpace),
215216
result.numberOfAttributes,

packages/engine/Source/Core/HeightmapTerrainData.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ HeightmapTerrainData.prototype.createMesh = function (options) {
283283
vertexCountWithoutSkirts,
284284
result.minimumHeight,
285285
result.maximumHeight,
286+
rectangle,
286287
BoundingSphere.clone(result.boundingSphere3D),
287288
Cartesian3.clone(result.occludeePointInScaledSpace),
288289
result.numberOfAttributes,
@@ -389,6 +390,7 @@ HeightmapTerrainData.prototype._createMeshSync = function (options) {
389390
vertexCountWithoutSkirts,
390391
result.minimumHeight,
391392
result.maximumHeight,
393+
rectangle,
392394
result.boundingSphere3D,
393395
result.occludeePointInScaledSpace,
394396
result.encoding.stride,

packages/engine/Source/Core/IntersectionTests.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,86 @@ IntersectionTests.rayEllipsoid = function (ray, ellipsoid) {
495495
return undefined;
496496
};
497497

498+
const scratchRayIntervalX = new Interval();
499+
const scratchRayIntervalY = new Interval();
500+
const scratchRayIntervalZ = new Interval();
501+
502+
/**
503+
* Computes the intersection points of a ray with an axis-aligned bounding box. (axis-aligned in the same space as the ray)
504+
*
505+
* @param {Ray} ray The ray.
506+
* @param {AxisAlignedBoundingBox} box The axis-aligned bounding box.
507+
* @param {Interval | undefined} result The interval containing scalar points along the ray or undefined if there are no intersections.
508+
*/
509+
IntersectionTests.rayAxisAlignedBoundingBox = function (ray, box, result) {
510+
//>>includeStart('debug', pragmas.debug);
511+
if (!defined(ray)) {
512+
throw new DeveloperError("ray is required.");
513+
}
514+
if (!defined(box)) {
515+
throw new DeveloperError("box is required.");
516+
}
517+
//>>includeEnd('debug');
518+
519+
if (!defined(result)) {
520+
result = new Interval();
521+
}
522+
523+
const tx = rayIntervalAlongAABBAxis(
524+
ray.origin.x,
525+
ray.direction.x,
526+
box.minimum.x,
527+
box.maximum.x,
528+
scratchRayIntervalX,
529+
);
530+
const ty = rayIntervalAlongAABBAxis(
531+
ray.origin.y,
532+
ray.direction.y,
533+
box.minimum.y,
534+
box.maximum.y,
535+
scratchRayIntervalY,
536+
);
537+
const tz = rayIntervalAlongAABBAxis(
538+
ray.origin.z,
539+
ray.direction.z,
540+
box.minimum.z,
541+
box.maximum.z,
542+
scratchRayIntervalZ,
543+
);
544+
545+
result.start = tx.start > ty.start ? tx.start : ty.start; //Get Greatest Min
546+
result.stop = tx.stop < ty.stop ? tx.stop : ty.stop; //Get Smallest Max
547+
548+
if (tx.start > ty.stop || ty.start > tx.stop) {
549+
return undefined;
550+
}
551+
552+
if (result.start > tz.stop || tz.start > result.stop) {
553+
return undefined;
554+
}
555+
556+
if (tz.start > result.start) {
557+
result.start = tz.start;
558+
}
559+
if (tz.stop < result.stop) {
560+
result.stop = tz.stop;
561+
}
562+
563+
return result;
564+
};
565+
566+
function rayIntervalAlongAABBAxis(origin, direction, min, max, result) {
567+
result.start = (min - origin) / direction;
568+
result.stop = (max - origin) / direction;
569+
if (result.stop < result.start) {
570+
const tmp = result.stop;
571+
result.stop = result.start;
572+
result.start = tmp;
573+
}
574+
575+
return result;
576+
}
577+
498578
function addWithCancellationCheck(left, right, tolerance) {
499579
const difference = left + right;
500580
if (

packages/engine/Source/Core/QuantizedMeshTerrainData.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ QuantizedMeshTerrainData.prototype.createMesh = function (options) {
349349
vertexCountWithoutSkirts,
350350
minimumHeight,
351351
maximumHeight,
352+
rectangle,
352353
boundingSphere,
353354
occludeePointInScaledSpace,
354355
stride,

0 commit comments

Comments
 (0)