diff --git a/Source/Core/EllipsoidalOccluder.js b/Source/Core/EllipsoidalOccluder.js
index 8a2c1edc6a66..575bd727a2a6 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,16 +117,40 @@ 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 scratchEllipsoidShrunkRadii = new Cartesian3();
+ var scratchEllipsoidShrunk = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
+ var scratchCameraPositionInScaledSpaceShrunk = new Cartesian3();
+
+ /**
+ * 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},
+ * {@link EllipsoidalOccluder#computeHorizonCullingPointFromVerticesPossiblyUnderEllipsoid}, or
+ * {@link EllipsoidalOccluder#computeHorizonCullingPointFromRectanglePossiblyUnderEllipsoid}.
+ *
+ * @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.isScaledSpacePointVisiblePossiblyUnderEllipsoid = function(occludeeScaledSpacePosition, minimumHeight) {
+ var ellipsoid = this._ellipsoid;
+ 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
+ );
+ var ellipsoidShrunk = Ellipsoid.fromCartesian3(ellipsoidShrunkRadii, scratchEllipsoidShrunk);
+ var cameraPositionInScaledSpaceShrunk = ellipsoidShrunk.transformPositionToScaledSpace(this._cameraPosition, scratchCameraPositionInScaledSpaceShrunk);
+ var distanceToLimbinScaledSpaceSquaredShrunk = Cartesian3.magnitudeSquared(cameraPositionInScaledSpaceShrunk) - 1.0;
+ return isScaledSpacePointVisible(occludeeScaledSpacePosition, cameraPositionInScaledSpaceShrunk, distanceToLimbinScaledSpaceSquaredShrunk);
+ }
+
+ return isScaledSpacePointVisible(occludeeScaledSpacePosition, this._cameraPositionInScaledSpace, this._distanceToLimbInScaledSpaceSquared);
};
/**
@@ -167,6 +192,30 @@ import Rectangle from './Rectangle.js';
return magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, 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 that = this;
+ return computeHorizonCullingPointPossiblyUnderEllipsoid(that, minimumHeight, function() {
+ return that.computeHorizonCullingPoint(directionToPoint, positions, result);
+ });
+ };
+
var positionScratch = new Cartesian3();
/**
@@ -215,6 +264,32 @@ import Rectangle from './Rectangle.js';
return magnitudeToPoint(scaledSpaceDirectionToPoint, resultMagnitude, 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 that = this;
+ return computeHorizonCullingPointPossiblyUnderEllipsoid(that, minimumHeight, function() {
+ return that.computeHorizonCullingPointFromVertices(directionToPoint, vertices, stride, center, result);
+ });
+ };
+
var subsampleScratch = [];
/**
@@ -246,6 +321,65 @@ import Rectangle from './Rectangle.js';
return this.computeHorizonCullingPoint(bs.center, positions, result);
};
+ /**
+ * Similar to {@link EllipsoidalOccluder#computeHorizonCullingPointFromRectangle} except computes the culling
+ * point relative to an ellipsoid that has been shrunk by the height when the 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 {Rectangle} rectangle The rectangle for which to compute the horizon culling point.
+ * @param {Ellipsoid} ellipsoid The ellipsoid on which the rectangle is defined. This may be different from
+ * the ellipsoid used by this instance for occlusion testing.
+ * @param {Number} [height] The height of the rectangle. If this value is undefined, the rectangle is assumed to be on the occluder's 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.computeHorizonCullingPointFromRectanglePossiblyUnderEllipsoid = function(rectangle, ellipsoid, height, result) {
+ var that = this;
+ return computeHorizonCullingPointPossiblyUnderEllipsoid(that, height, function() {
+ return that.computeHorizonCullingPointFromRectangle(rectangle, ellipsoid, result);
+ });
+ };
+
+ var scratchEllipsoidShrunkRadii2 = new Cartesian3();
+ var scratchEllipsoidShrunk2 = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
+
+ function computeHorizonCullingPointPossiblyUnderEllipsoid(ellipsoidalOccluder, minimumHeight, func) {
+ var ellipsoid = ellipsoidalOccluder._ellipsoid;
+
+ 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,
+ scratchEllipsoidShrunkRadii2
+ );
+ var ellipsoidShrunk = Ellipsoid.fromCartesian3(ellipsoidShrunkRadii, scratchEllipsoidShrunk2);
+
+ // The horizon culling point is calculated with respect to the shrunk ellipsoid, so
+ // temporarily change change the occluder's ellipsoid to the shrunk ellipsoid.
+ ellipsoidalOccluder._ellipsoid = ellipsoidShrunk;
+ var result = func();
+ ellipsoidalOccluder._ellipsoid = ellipsoid;
+ return result;
+ }
+
+ return func();
+ }
+
+ 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;