diff --git a/Source/Core/EllipsoidalOccluder.js b/Source/Core/EllipsoidalOccluder.js
index 8a2c1edc6a66..68320b5c2555 100644
--- a/Source/Core/EllipsoidalOccluder.js
+++ b/Source/Core/EllipsoidalOccluder.js
@@ -4,6 +4,7 @@ import Check from './Check.js';
import defaultValue from './defaultValue.js';
import defined from './defined.js';
import defineProperties from './defineProperties.js';
+import Ellipsoid from './Ellipsoid.js';
import Rectangle from './Rectangle.js';
/**
@@ -116,35 +117,39 @@ import Rectangle from './Rectangle.js';
* occluder.isScaledSpacePointVisible(scaledSpacePoint); //returns true
*/
EllipsoidalOccluder.prototype.isScaledSpacePointVisible = function(occludeeScaledSpacePosition) {
- // See https://cesium.com/blog/2013/04/25/Horizon-culling/
- var cv = this._cameraPositionInScaledSpace;
- var vhMagnitudeSquared = this._distanceToLimbInScaledSpaceSquared;
- var vt = Cartesian3.subtract(occludeeScaledSpacePosition, cv, scratchCartesian);
- var vtDotVc = -Cartesian3.dot(vt, cv);
- // If vhMagnitudeSquared < 0 then we are below the surface of the ellipsoid and
- // in this case, set the culling plane to be on V.
- var isOccluded = vhMagnitudeSquared < 0 ? vtDotVc > 0 : (vtDotVc > vhMagnitudeSquared &&
- vtDotVc * vtDotVc / Cartesian3.magnitudeSquared(vt) > vhMagnitudeSquared);
- return !isOccluded;
+ return isScaledSpacePointVisible(occludeeScaledSpacePosition, this._cameraPositionInScaledSpace, this._distanceToLimbInScaledSpaceSquared);
};
+ var scratchCameraPositionInScaledSpaceShrunk = new Cartesian3();
+
/**
- * Computes a point that can be used for horizon culling from a list of positions. If the point is below
- * the horizon, all of the positions are guaranteed to be below the horizon as well. The returned point
- * is expressed in the ellipsoid-scaled space and is suitable for use with
- * {@link EllipsoidalOccluder#isScaledSpacePointVisible}.
+ * Similar to {@link EllipsoidalOccluder#isScaledSpacePointVisible} except tests against an
+ * ellipsoid that has been shrunk by the minimum height when the minimum height is below
+ * the ellipsoid. This is intended to be used with points generated by
+ * {@link EllipsoidalOccluder#computeHorizonCullingPointPossiblyUnderEllipsoid} or
+ * {@link EllipsoidalOccluder#computeHorizonCullingPointFromVerticesPossiblyUnderEllipsoid}.
*
- * @param {Cartesian3} directionToPoint The direction that the computed point will lie along.
- * A reasonable direction to use is the direction from the center of the ellipsoid to
- * the center of the bounding sphere computed from the positions. The direction need not
- * be normalized.
- * @param {Cartesian3[]} positions The positions from which to compute the horizon culling point. The positions
- * must be expressed in a reference frame centered at the ellipsoid and aligned with the
- * ellipsoid's axes.
- * @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance.
- * @returns {Cartesian3} The computed horizon culling point, expressed in the ellipsoid-scaled space.
+ * @param {Cartesian3} occludeeScaledSpacePosition The point to test for visibility, represented in the scaled space of the possibly-shrunk ellipsoid.
+ * @returns {Boolean} true
if the occludee is visible; otherwise false
.
*/
- EllipsoidalOccluder.prototype.computeHorizonCullingPoint = function(directionToPoint, positions, result) {
+ EllipsoidalOccluder.prototype.isScaledSpacePointVisiblePossiblyUnderEllipsoid = function(occludeeScaledSpacePosition, minimumHeight) {
+ var ellipsoid = this._ellipsoid;
+ if (defined(minimumHeight) && minimumHeight < 0.0 && ellipsoid.minimumRadius > -minimumHeight) {
+ var cameraPositionInScaledSpaceShrunk = Cartesian3.fromElements(
+ this._cameraPosition.x / (ellipsoid.radii.x + minimumHeight),
+ this._cameraPosition.y / (ellipsoid.radii.y + minimumHeight),
+ this._cameraPosition.z / (ellipsoid.radii.z + minimumHeight),
+ scratchCameraPositionInScaledSpaceShrunk
+ );
+
+ var distanceToLimbInScaledSpaceSquaredShrunk = Cartesian3.magnitudeSquared(cameraPositionInScaledSpaceShrunk) - 1.0;
+ return isScaledSpacePointVisible(occludeeScaledSpacePosition, cameraPositionInScaledSpaceShrunk, distanceToLimbInScaledSpaceSquaredShrunk);
+ }
+
+ return isScaledSpacePointVisible(occludeeScaledSpacePosition, this._cameraPositionInScaledSpace, this._distanceToLimbInScaledSpaceSquared);
+ };
+
+ function computeHorizonCullingPoint(ellipsoid, directionToPoint, positions, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object('directionToPoint', directionToPoint);
Check.defined('positions', positions);
@@ -154,7 +159,6 @@ import Rectangle from './Rectangle.js';
result = new Cartesian3();
}
- var ellipsoid = this._ellipsoid;
var scaledSpaceDirectionToPoint = computeScaledSpaceDirectionToPoint(ellipsoid, directionToPoint);
var resultMagnitude = 0.0;
@@ -165,9 +169,7 @@ import Rectangle from './Rectangle.js';
}
return magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result);
- };
-
- var positionScratch = new Cartesian3();
+ }
/**
* Computes a point that can be used for horizon culling from a list of positions. If the point is below
@@ -179,15 +181,41 @@ import Rectangle from './Rectangle.js';
* A reasonable direction to use is the direction from the center of the ellipsoid to
* the center of the bounding sphere computed from the positions. The direction need not
* be normalized.
- * @param {Number[]} vertices The vertices from which to compute the horizon culling point. The positions
- * must be expressed in a reference frame centered at the ellipsoid and aligned with the
- * ellipsoid's axes.
- * @param {Number} [stride=3]
- * @param {Cartesian3} [center=Cartesian3.ZERO]
+ * @param {Cartesian3[]} positions The positions from which to compute the horizon culling point. The positions
+ * must be expressed in a reference frame centered at the ellipsoid and aligned with the
+ * ellipsoid's axes.
* @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance.
* @returns {Cartesian3} The computed horizon culling point, expressed in the ellipsoid-scaled space.
*/
- EllipsoidalOccluder.prototype.computeHorizonCullingPointFromVertices = function(directionToPoint, vertices, stride, center, result) {
+ EllipsoidalOccluder.prototype.computeHorizonCullingPoint = function(directionToPoint, positions, result) {
+ return computeHorizonCullingPoint(this._ellipsoid, directionToPoint, positions, result);
+ };
+
+ /**
+ * Similar to {@link EllipsoidalOccluder#computeHorizonCullingPoint} except computes the culling
+ * point relative to an ellipsoid that has been shrunk by the minimum height when the minimum height is below
+ * the ellipsoid. The returned point is expressed in the possibly-shrunk ellipsoid-scaled space and is suitable
+ * for use with {@link EllipsoidalOccluder#isScaledSpacePointVisiblePossiblyUnderEllipsoid}.
+ *
+ * @param {Cartesian3} directionToPoint The direction that the computed point will lie along.
+ * A reasonable direction to use is the direction from the center of the ellipsoid to
+ * the center of the bounding sphere computed from the positions. The direction need not
+ * be normalized.
+ * @param {Cartesian3[]} positions The positions from which to compute the horizon culling point. The positions
+ * must be expressed in a reference frame centered at the ellipsoid and aligned with the
+ * ellipsoid's axes.
+ * @param {Number} [minimumHeight] The minimum height of all positions. If this value is undefined, all positions are assumed to be above the ellipsoid.
+ * @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance.
+ * @returns {Cartesian3} The computed horizon culling point, expressed in the possibly-shrunk ellipsoid-scaled space.
+ */
+ EllipsoidalOccluder.prototype.computeHorizonCullingPointPossiblyUnderEllipsoid = function(directionToPoint, positions, minimumHeight, result) {
+ var possiblyShrunkEllipsoid = getPossiblyShrunkEllipsoid(this._ellipsoid, minimumHeight);
+ return computeHorizonCullingPoint(possiblyShrunkEllipsoid, directionToPoint, positions, result);
+ };
+
+ var positionScratch = new Cartesian3();
+
+ function computeHorizonCullingPointFromVertices(ellipsoid, directionToPoint, vertices, stride, center, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object('directionToPoint', directionToPoint);
Check.defined('vertices', vertices);
@@ -198,8 +226,8 @@ import Rectangle from './Rectangle.js';
result = new Cartesian3();
}
+ stride = defaultValue(stride, 3);
center = defaultValue(center, Cartesian3.ZERO);
- var ellipsoid = this._ellipsoid;
var scaledSpaceDirectionToPoint = computeScaledSpaceDirectionToPoint(ellipsoid, directionToPoint);
var resultMagnitude = 0.0;
@@ -213,6 +241,52 @@ import Rectangle from './Rectangle.js';
}
return magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, result);
+ }
+
+ /**
+ * Computes a point that can be used for horizon culling from a list of positions. If the point is below
+ * the horizon, all of the positions are guaranteed to be below the horizon as well. The returned point
+ * is expressed in the ellipsoid-scaled space and is suitable for use with
+ * {@link EllipsoidalOccluder#isScaledSpacePointVisible}.
+ *
+ * @param {Cartesian3} directionToPoint The direction that the computed point will lie along.
+ * A reasonable direction to use is the direction from the center of the ellipsoid to
+ * the center of the bounding sphere computed from the positions. The direction need not
+ * be normalized.
+ * @param {Number[]} vertices The vertices from which to compute the horizon culling point. The positions
+ * must be expressed in a reference frame centered at the ellipsoid and aligned with the
+ * ellipsoid's axes.
+ * @param {Number} [stride=3]
+ * @param {Cartesian3} [center=Cartesian3.ZERO]
+ * @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance.
+ * @returns {Cartesian3} The computed horizon culling point, expressed in the ellipsoid-scaled space.
+ */
+ EllipsoidalOccluder.prototype.computeHorizonCullingPointFromVertices = function(directionToPoint, vertices, stride, center, result) {
+ return computeHorizonCullingPointFromVertices(this._ellipsoid, directionToPoint, vertices, stride, center, result);
+ };
+
+ /**
+ * Similar to {@link EllipsoidalOccluder#computeHorizonCullingPointFromVertices} except computes the culling
+ * point relative to an ellipsoid that has been shrunk by the minimum height when the minimum height is below
+ * the ellipsoid. The returned point is expressed in the possibly-shrunk ellipsoid-scaled space and is suitable
+ * for use with {@link EllipsoidalOccluder#isScaledSpacePointVisiblePossiblyUnderEllipsoid}.
+ *
+ * @param {Cartesian3} directionToPoint The direction that the computed point will lie along.
+ * A reasonable direction to use is the direction from the center of the ellipsoid to
+ * the center of the bounding sphere computed from the positions. The direction need not
+ * be normalized.
+ * @param {Number[]} vertices The vertices from which to compute the horizon culling point. The positions
+ * must be expressed in a reference frame centered at the ellipsoid and aligned with the
+ * ellipsoid's axes.
+ * @param {Number} [stride=3]
+ * @param {Cartesian3} [center=Cartesian3.ZERO]
+ * @param {Number} [minimumHeight] The minimum height of all vertices. If this value is undefined, all vertices are assumed to be above the ellipsoid.
+ * @param {Cartesian3} [result] The instance on which to store the result instead of allocating a new instance.
+ * @returns {Cartesian3} The computed horizon culling point, expressed in the possibly-shrunk ellipsoid-scaled space.
+ */
+ EllipsoidalOccluder.prototype.computeHorizonCullingPointFromVerticesPossiblyUnderEllipsoid = function(directionToPoint, vertices, stride, center, minimumHeight, result) {
+ var possiblyShrunkEllipsoid = getPossiblyShrunkEllipsoid(this._ellipsoid, minimumHeight);
+ return computeHorizonCullingPointFromVertices(possiblyShrunkEllipsoid, directionToPoint, vertices, stride, center, result);
};
var subsampleScratch = [];
@@ -246,6 +320,35 @@ import Rectangle from './Rectangle.js';
return this.computeHorizonCullingPoint(bs.center, positions, result);
};
+ var scratchEllipsoidShrunkRadii = new Cartesian3();
+ var scratchEllipsoidShrunk = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
+
+ function getPossiblyShrunkEllipsoid(ellipsoid, minimumHeight) {
+ if (defined(minimumHeight) && minimumHeight < 0.0 && ellipsoid.minimumRadius > -minimumHeight) {
+ var ellipsoidShrunkRadii = Cartesian3.fromElements(
+ ellipsoid.radii.x + minimumHeight,
+ ellipsoid.radii.y + minimumHeight,
+ ellipsoid.radii.z + minimumHeight,
+ scratchEllipsoidShrunkRadii
+ );
+ ellipsoid = Ellipsoid.fromCartesian3(ellipsoidShrunkRadii, scratchEllipsoidShrunk);
+ }
+ return ellipsoid;
+ }
+
+ function isScaledSpacePointVisible(occludeeScaledSpacePosition, cameraPositionInScaledSpace, distanceToLimbInScaledSpaceSquared) {
+ // See https://cesium.com/blog/2013/04/25/Horizon-culling/
+ var cv = cameraPositionInScaledSpace;
+ var vhMagnitudeSquared = distanceToLimbInScaledSpaceSquared;
+ var vt = Cartesian3.subtract(occludeeScaledSpacePosition, cv, scratchCartesian);
+ var vtDotVc = -Cartesian3.dot(vt, cv);
+ // If vhMagnitudeSquared < 0 then we are below the surface of the ellipsoid and
+ // in this case, set the culling plane to be on V.
+ var isOccluded = vhMagnitudeSquared < 0 ? vtDotVc > 0 : (vtDotVc > vhMagnitudeSquared &&
+ vtDotVc * vtDotVc / Cartesian3.magnitudeSquared(vt) > vhMagnitudeSquared);
+ return !isOccluded;
+ }
+
var scaledSpaceScratch = new Cartesian3();
var directionScratch = new Cartesian3();
diff --git a/Source/Core/HeightmapTessellator.js b/Source/Core/HeightmapTessellator.js
index 2f240f46a003..e4f9eef6933c 100644
--- a/Source/Core/HeightmapTessellator.js
+++ b/Source/Core/HeightmapTessellator.js
@@ -396,7 +396,7 @@ import WebMercatorProjection from './WebMercatorProjection.js';
var occludeePointInScaledSpace;
if (hasRelativeToCenter) {
var occluder = new EllipsoidalOccluder(ellipsoid);
- occludeePointInScaledSpace = occluder.computeHorizonCullingPoint(relativeToCenter, positions);
+ occludeePointInScaledSpace = occluder.computeHorizonCullingPointPossiblyUnderEllipsoid(relativeToCenter, positions, minimumHeight);
}
var aaBox = new AxisAlignedBoundingBox(minimum, maximum, relativeToCenter);
diff --git a/Source/Core/QuantizedMeshTerrainData.js b/Source/Core/QuantizedMeshTerrainData.js
index 5c0c5ea14b0e..38086459e4d4 100644
--- a/Source/Core/QuantizedMeshTerrainData.js
+++ b/Source/Core/QuantizedMeshTerrainData.js
@@ -310,7 +310,7 @@ import TerrainMesh from './TerrainMesh.js';
var maximumHeight = result.maximumHeight;
var boundingSphere = defaultValue(BoundingSphere.clone(result.boundingSphere), that._boundingSphere);
var obb = defaultValue(OrientedBoundingBox.clone(result.orientedBoundingBox), that._orientedBoundingBox);
- var occlusionPoint = Cartesian3.clone(that._horizonOcclusionPoint);
+ var occludeePointInScaledSpace = defaultValue(Cartesian3.clone(result.occludeePointInScaledSpace), that._horizonOcclusionPoint);
var stride = result.vertexStride;
var terrainEncoding = TerrainEncoding.clone(result.encoding);
@@ -326,7 +326,7 @@ import TerrainMesh from './TerrainMesh.js';
minimumHeight,
maximumHeight,
boundingSphere,
- occlusionPoint,
+ occludeePointInScaledSpace,
stride,
obb,
terrainEncoding,
diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js
index 01daa926b967..36595c12a8f9 100644
--- a/Source/Scene/GlobeSurfaceTileProvider.js
+++ b/Source/Scene/GlobeSurfaceTileProvider.js
@@ -599,7 +599,7 @@ import TileSelectionResult from './TileSelectionResult.js';
return intersection;
}
- if (occluders.ellipsoid.isScaledSpacePointVisible(occludeePointInScaledSpace)) {
+ if (occluders.ellipsoid.isScaledSpacePointVisiblePossiblyUnderEllipsoid(occludeePointInScaledSpace, tileBoundingRegion.minimumHeight)) {
return intersection;
}
@@ -802,17 +802,17 @@ import TileSelectionResult from './TileSelectionResult.js';
var cornerPositionsScratch = [new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3()];
- function computeOccludeePoint(tileProvider, center, rectangle, height, result) {
+ function computeOccludeePoint(tileProvider, center, rectangle, minimumHeight, maximumHeight, result) {
var ellipsoidalOccluder = tileProvider.quadtree._occluders.ellipsoid;
var ellipsoid = ellipsoidalOccluder.ellipsoid;
var cornerPositions = cornerPositionsScratch;
- Cartesian3.fromRadians(rectangle.west, rectangle.south, height, ellipsoid, cornerPositions[0]);
- Cartesian3.fromRadians(rectangle.east, rectangle.south, height, ellipsoid, cornerPositions[1]);
- Cartesian3.fromRadians(rectangle.west, rectangle.north, height, ellipsoid, cornerPositions[2]);
- Cartesian3.fromRadians(rectangle.east, rectangle.north, height, ellipsoid, cornerPositions[3]);
+ Cartesian3.fromRadians(rectangle.west, rectangle.south, maximumHeight, ellipsoid, cornerPositions[0]);
+ Cartesian3.fromRadians(rectangle.east, rectangle.south, maximumHeight, ellipsoid, cornerPositions[1]);
+ Cartesian3.fromRadians(rectangle.west, rectangle.north, maximumHeight, ellipsoid, cornerPositions[2]);
+ Cartesian3.fromRadians(rectangle.east, rectangle.north, maximumHeight, ellipsoid, cornerPositions[3]);
- return ellipsoidalOccluder.computeHorizonCullingPoint(center, cornerPositions, result);
+ return ellipsoidalOccluder.computeHorizonCullingPointPossiblyUnderEllipsoid(center, cornerPositions, minimumHeight, result);
}
/**
@@ -860,7 +860,7 @@ import TileSelectionResult from './TileSelectionResult.js';
tile.tilingScheme.ellipsoid,
surfaceTile.orientedBoundingBox);
- surfaceTile.occludeePointInScaledSpace = computeOccludeePoint(this, surfaceTile.orientedBoundingBox.center, tile.rectangle, tileBoundingRegion.maximumHeight, surfaceTile.occludeePointInScaledSpace);
+ surfaceTile.occludeePointInScaledSpace = computeOccludeePoint(this, surfaceTile.orientedBoundingBox.center, tile.rectangle, tileBoundingRegion.minimumHeight, tileBoundingRegion.maximumHeight, surfaceTile.occludeePointInScaledSpace);
}
}
diff --git a/Source/Scene/TerrainFillMesh.js b/Source/Scene/TerrainFillMesh.js
index c63f735a2946..9b579c2f8983 100644
--- a/Source/Scene/TerrainFillMesh.js
+++ b/Source/Scene/TerrainFillMesh.js
@@ -655,7 +655,7 @@ import TileSelectionResult from './TileSelectionResult.js';
minimumHeight,
maximumHeight,
BoundingSphere.fromOrientedBoundingBox(obb),
- computeOccludeePoint(tileProvider, obb.center, rectangle, maximumHeight),
+ computeOccludeePoint(tileProvider, obb.center, rectangle, minimumHeight, maximumHeight),
encoding.getStride(),
obb,
encoding,
@@ -1183,16 +1183,16 @@ import TileSelectionResult from './TileSelectionResult.js';
var cornerPositionsScratch = [new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3()];
- function computeOccludeePoint(tileProvider, center, rectangle, height, result) {
+ function computeOccludeePoint(tileProvider, center, rectangle, minimumHeight, maximumHeight, result) {
var ellipsoidalOccluder = tileProvider.quadtree._occluders.ellipsoid;
var ellipsoid = ellipsoidalOccluder.ellipsoid;
var cornerPositions = cornerPositionsScratch;
- Cartesian3.fromRadians(rectangle.west, rectangle.south, height, ellipsoid, cornerPositions[0]);
- Cartesian3.fromRadians(rectangle.east, rectangle.south, height, ellipsoid, cornerPositions[1]);
- Cartesian3.fromRadians(rectangle.west, rectangle.north, height, ellipsoid, cornerPositions[2]);
- Cartesian3.fromRadians(rectangle.east, rectangle.north, height, ellipsoid, cornerPositions[3]);
+ Cartesian3.fromRadians(rectangle.west, rectangle.south, maximumHeight, ellipsoid, cornerPositions[0]);
+ Cartesian3.fromRadians(rectangle.east, rectangle.south, maximumHeight, ellipsoid, cornerPositions[1]);
+ Cartesian3.fromRadians(rectangle.west, rectangle.north, maximumHeight, ellipsoid, cornerPositions[2]);
+ Cartesian3.fromRadians(rectangle.east, rectangle.north, maximumHeight, ellipsoid, cornerPositions[3]);
- return ellipsoidalOccluder.computeHorizonCullingPoint(center, cornerPositions, result);
+ return ellipsoidalOccluder.computeHorizonCullingPointPossiblyUnderEllipsoid(center, cornerPositions, minimumHeight, result);
}
export default TerrainFillMesh;
diff --git a/Source/WorkersES6/createVerticesFromGoogleEarthEnterpriseBuffer.js b/Source/WorkersES6/createVerticesFromGoogleEarthEnterpriseBuffer.js
index 3781c0279e26..1431da04d195 100644
--- a/Source/WorkersES6/createVerticesFromGoogleEarthEnterpriseBuffer.js
+++ b/Source/WorkersES6/createVerticesFromGoogleEarthEnterpriseBuffer.js
@@ -372,7 +372,7 @@ import createTaskProcessorWorker from './createTaskProcessorWorker.js';
}
var occluder = new EllipsoidalOccluder(ellipsoid);
- var occludeePointInScaledSpace = occluder.computeHorizonCullingPoint(relativeToCenter, positions);
+ var occludeePointInScaledSpace = occluder.computeHorizonCullingPointPossiblyUnderEllipsoid(relativeToCenter, positions, minHeight);
var aaBox = new AxisAlignedBoundingBox(minimum, maximum, relativeToCenter);
var encoding = new TerrainEncoding(aaBox, skirtOptions.hMin, maxHeight, fromENU, false, includeWebMercatorT);
diff --git a/Source/WorkersES6/createVerticesFromQuantizedTerrainMesh.js b/Source/WorkersES6/createVerticesFromQuantizedTerrainMesh.js
index 7719829b4e66..c65af0f91aca 100644
--- a/Source/WorkersES6/createVerticesFromQuantizedTerrainMesh.js
+++ b/Source/WorkersES6/createVerticesFromQuantizedTerrainMesh.js
@@ -6,6 +6,7 @@ import Cartesian3 from '../Core/Cartesian3.js';
import Cartographic from '../Core/Cartographic.js';
import defined from '../Core/defined.js';
import Ellipsoid from '../Core/Ellipsoid.js';
+import EllipsoidalOccluder from '../Core/EllipsoidalOccluder.js';
import IndexDatatype from '../Core/IndexDatatype.js';
import CesiumMath from '../Core/Math.js';
import Matrix4 from '../Core/Matrix4.js';
@@ -132,11 +133,18 @@ import createTaskProcessorWorker from './createTaskProcessorWorker.js';
var boundingSphere;
if (exaggeration !== 1.0) {
- // Bounding volumes and horizon culling point need to be recomputed since the tile payload assumes no exaggeration.
+ // Bounding volumes need to be recomputed since the tile payload assumes no exaggeration.
boundingSphere = BoundingSphere.fromPoints(positions);
orientedBoundingBox = OrientedBoundingBox.fromRectangle(rectangle, minimumHeight, maximumHeight, ellipsoid);
}
+ var occludeePointInScaledSpace;
+ if (exaggeration !== 1.0 || minimumHeight < 0.0) {
+ // Horizon culling point needs to be recomputed since the tile payload assumes no exaggeration.
+ var occluder = new EllipsoidalOccluder(ellipsoid);
+ occludeePointInScaledSpace = occluder.computeHorizonCullingPointPossiblyUnderEllipsoid(center, positions, minimumHeight);
+ }
+
var hMin = minimumHeight;
hMin = Math.min(hMin, findMinMaxSkirts(parameters.westIndices, parameters.westSkirtHeight, heights, uvs, rectangle, ellipsoid, toENU, minimum, maximum));
hMin = Math.min(hMin, findMinMaxSkirts(parameters.southIndices, parameters.southSkirtHeight, heights, uvs, rectangle, ellipsoid, toENU, minimum, maximum));
@@ -218,6 +226,7 @@ import createTaskProcessorWorker from './createTaskProcessorWorker.js';
maximumHeight : maximumHeight,
boundingSphere : boundingSphere,
orientedBoundingBox : orientedBoundingBox,
+ occludeePointInScaledSpace : occludeePointInScaledSpace,
encoding : encoding,
skirtIndex : parameters.indices.length
};
diff --git a/Source/WorkersES6/upsampleQuantizedTerrainMesh.js b/Source/WorkersES6/upsampleQuantizedTerrainMesh.js
index 1939127b11e9..8048ce886d8d 100644
--- a/Source/WorkersES6/upsampleQuantizedTerrainMesh.js
+++ b/Source/WorkersES6/upsampleQuantizedTerrainMesh.js
@@ -269,7 +269,7 @@ import createTaskProcessorWorker from './createTaskProcessorWorker.js';
var orientedBoundingBox = OrientedBoundingBox.fromRectangle(rectangle, minimumHeight, maximumHeight, ellipsoid, orientedBoundingBoxScratch);
var occluder = new EllipsoidalOccluder(ellipsoid);
- var horizonOcclusionPoint = occluder.computeHorizonCullingPointFromVertices(boundingSphere.center, cartesianVertices, 3, boundingSphere.center, horizonOcclusionPointScratch);
+ var horizonOcclusionPoint = occluder.computeHorizonCullingPointFromVerticesPossiblyUnderEllipsoid(boundingSphere.center, cartesianVertices, 3, boundingSphere.center, minimumHeight, horizonOcclusionPointScratch);
var heightRange = maximumHeight - minimumHeight;
diff --git a/Specs/Core/EllipsoidalOccluderSpec.js b/Specs/Core/EllipsoidalOccluderSpec.js
index 0d677094926e..4c1c2d3d4422 100644
--- a/Specs/Core/EllipsoidalOccluderSpec.js
+++ b/Specs/Core/EllipsoidalOccluderSpec.js
@@ -39,6 +39,34 @@ describe('Core/EllipsoidalOccluder', function() {
expect(occluder.isScaledSpacePointVisible(scaledSpacePoint)).toEqual(true);
});
+ it('isScaledSpacePointVisiblePossiblyUnderEllipsoid example works as claimed', function() {
+ // Tests points that are halfway inside a unit sphere:
+ // 1) on the diagonal
+ // 2) on the +y-axis
+ // The camera is on the +z-axis so it will be able to see the diagonal point but not the +y-axis point.
+
+ var cameraPosition = new Cartesian3(0, 0, 1.0);
+ var ellipsoid = new Ellipsoid(1.0, 1.0, 1.0);
+ var occluder = new EllipsoidalOccluder(ellipsoid, cameraPosition);
+ var height = -0.5;
+
+ var direction = Cartesian3.normalize(new Cartesian3(1.0, 1.0, 1.0), new Cartesian3());
+ var point = Cartesian3.multiplyByScalar(direction, 0.5, new Cartesian3());
+ var scaledSpacePoint = occluder.computeHorizonCullingPoint(point, [point]);
+ var scaledSpacePointShrunk = occluder.computeHorizonCullingPointPossiblyUnderEllipsoid(point, [point], height);
+
+ expect(occluder.isScaledSpacePointVisible(scaledSpacePoint)).toEqual(false);
+ expect(occluder.isScaledSpacePointVisiblePossiblyUnderEllipsoid(scaledSpacePointShrunk, height)).toEqual(true);
+
+ direction = new Cartesian3(0.0, 1.0, 0.0);
+ point = Cartesian3.multiplyByScalar(direction, 0.5, new Cartesian3());
+ scaledSpacePoint = occluder.computeHorizonCullingPoint(point, [point]);
+ scaledSpacePointShrunk = occluder.computeHorizonCullingPointPossiblyUnderEllipsoid(point, [point], height);
+
+ expect(occluder.isScaledSpacePointVisible(scaledSpacePoint)).toEqual(false);
+ expect(occluder.isScaledSpacePointVisiblePossiblyUnderEllipsoid(scaledSpacePointShrunk, height)).toEqual(false);
+ });
+
it('reports not visible when point is directly behind ellipsoid', function() {
var ellipsoid = Ellipsoid.WGS84;
var occluder = new EllipsoidalOccluder(ellipsoid);
@@ -178,6 +206,19 @@ describe('Core/EllipsoidalOccluder', function() {
expect(foundOneNearZero).toBe(true);
});
+
+ it('computes a point under the ellipsoid with computeHorizonCullingPointPossiblyUnderEllipsoid', function() {
+ var ellipsoid = new Ellipsoid(12345.0, 4567.0, 8910.0);
+ var ellipsoidalOccluder = new EllipsoidalOccluder(ellipsoid);
+ var positions = [new Cartesian3(12344.0, 0.0, 0.0)];
+ var directionToPoint = new Cartesian3(1.0, 0.0, 0.0);
+
+ var result = ellipsoidalOccluder.computeHorizonCullingPointPossiblyUnderEllipsoid(directionToPoint, positions, -1.0);
+
+ expect(result.x).toEqualEpsilon(1.0, CesiumMath.EPSILON14);
+ expect(result.y).toEqualEpsilon(0.0, CesiumMath.EPSILON14);
+ expect(result.z).toEqualEpsilon(0.0, CesiumMath.EPSILON14);
+ });
});
describe('computeHorizonCullingPointFromVertices', function() {
@@ -243,6 +284,20 @@ describe('Core/EllipsoidalOccluder', function() {
expect(result1.y).toEqualEpsilon(result2.y, CesiumMath.EPSILON14);
expect(result1.z).toEqualEpsilon(result2.z, CesiumMath.EPSILON14);
});
+
+ it('computes a point under the ellipsoid with computeHorizonCullingPointFromVerticesPossiblyUnderEllipsoid', function() {
+ var ellipsoid = new Ellipsoid(12345.0, 4567.0, 8910.0);
+ var ellipsoidalOccluder = new EllipsoidalOccluder(ellipsoid);
+ var vertices = [12344.0, 0.0, 0.0];
+ var directionToPoint = new Cartesian3(1.0, 0.0, 0.0);
+ var center = Cartesian3.ZERO;
+
+ var result = ellipsoidalOccluder.computeHorizonCullingPointFromVerticesPossiblyUnderEllipsoid(directionToPoint, vertices, 3, center, -1.0);
+
+ expect(result.x).toEqualEpsilon(1.0, CesiumMath.EPSILON14);
+ expect(result.y).toEqualEpsilon(0.0, CesiumMath.EPSILON14);
+ expect(result.z).toEqualEpsilon(0.0, CesiumMath.EPSILON14);
+ });
});
describe('computeHorizonCullingPointFromRectangle', function() {