import Cartesian3 from "../Core/Cartesian3.js"; import Check from "../Core/Check.js"; import Cesium3DTileOptimizationHint from "./Cesium3DTileOptimizationHint.js"; import TileBoundingRegion from "./TileBoundingRegion.js"; import TileOrientedBoundingBox from "./TileOrientedBoundingBox.js"; /** * Utility functions for computing optimization hints for a {@link Cesium3DTileset}. * * @namespace Cesium3DTileOptimizations * * @private */ const Cesium3DTileOptimizations = {}; const scratchAxis = new Cartesian3(); /** * Evaluates support for the childrenWithinParent optimization. This is used to more tightly cull tilesets if * children bounds are fully contained within the parent. Currently, support for the optimization only works for * oriented bounding boxes, so both the child and parent tile must be either a {@link TileOrientedBoundingBox} or * {@link TileBoundingRegion}. The purpose of this check is to prevent use of a culling optimization when the child * bounds exceed those of the parent. If the child bounds are greater, it is more likely that the optimization will * waste CPU cycles. Bounding spheres are not supported for the reason that the child bounds can very often be * partially outside of the parent bounds. * * @param {Cesium3DTile} tile The tile to check. * @returns {boolean} Whether the childrenWithinParent optimization is supported. */ Cesium3DTileOptimizations.checkChildrenWithinParent = function (tile) { //>>includeStart('debug', pragmas.debug); Check.typeOf.object("tile", tile); //>>includeEnd('debug'); const children = tile.children; const length = children.length; // Check if the parent has an oriented bounding box. const boundingVolume = tile.boundingVolume; if ( boundingVolume instanceof TileOrientedBoundingBox || boundingVolume instanceof TileBoundingRegion ) { const orientedBoundingBox = boundingVolume._orientedBoundingBox; tile._optimChildrenWithinParent = Cesium3DTileOptimizationHint.USE_OPTIMIZATION; for (let i = 0; i < length; ++i) { const child = children[i]; // Check if the child has an oriented bounding box. const childBoundingVolume = child.boundingVolume; if ( !( childBoundingVolume instanceof TileOrientedBoundingBox || childBoundingVolume instanceof TileBoundingRegion ) ) { // Do not support if the parent and child both do not have oriented bounding boxes. tile._optimChildrenWithinParent = Cesium3DTileOptimizationHint.SKIP_OPTIMIZATION; break; } const childOrientedBoundingBox = childBoundingVolume._orientedBoundingBox; // Compute the axis from the parent to the child. const axis = Cartesian3.subtract( childOrientedBoundingBox.center, orientedBoundingBox.center, scratchAxis ); const axisLength = Cartesian3.magnitude(axis); Cartesian3.divideByScalar(axis, axisLength, axis); // Project the bounding box of the parent onto the axis. Because the axis is a ray from the parent // to the child, the projection parameterized along the ray will be (+/- proj1). const proj1 = Math.abs(orientedBoundingBox.halfAxes[0] * axis.x) + Math.abs(orientedBoundingBox.halfAxes[1] * axis.y) + Math.abs(orientedBoundingBox.halfAxes[2] * axis.z) + Math.abs(orientedBoundingBox.halfAxes[3] * axis.x) + Math.abs(orientedBoundingBox.halfAxes[4] * axis.y) + Math.abs(orientedBoundingBox.halfAxes[5] * axis.z) + Math.abs(orientedBoundingBox.halfAxes[6] * axis.x) + Math.abs(orientedBoundingBox.halfAxes[7] * axis.y) + Math.abs(orientedBoundingBox.halfAxes[8] * axis.z); // Project the bounding box of the child onto the axis. Because the axis is a ray from the parent // to the child, the projection parameterized along the ray will be (+/- proj2) + axis.length. const proj2 = Math.abs(childOrientedBoundingBox.halfAxes[0] * axis.x) + Math.abs(childOrientedBoundingBox.halfAxes[1] * axis.y) + Math.abs(childOrientedBoundingBox.halfAxes[2] * axis.z) + Math.abs(childOrientedBoundingBox.halfAxes[3] * axis.x) + Math.abs(childOrientedBoundingBox.halfAxes[4] * axis.y) + Math.abs(childOrientedBoundingBox.halfAxes[5] * axis.z) + Math.abs(childOrientedBoundingBox.halfAxes[6] * axis.x) + Math.abs(childOrientedBoundingBox.halfAxes[7] * axis.y) + Math.abs(childOrientedBoundingBox.halfAxes[8] * axis.z); // If the child extends the parent's bounds, the optimization is not valid and we skip it. if (proj1 <= proj2 + axisLength) { tile._optimChildrenWithinParent = Cesium3DTileOptimizationHint.SKIP_OPTIMIZATION; break; } } } return ( tile._optimChildrenWithinParent === Cesium3DTileOptimizationHint.USE_OPTIMIZATION ); }; export default Cesium3DTileOptimizations;