All files / engine/Source/Scene Cesium3DTileOptimizations.js

100% Statements 27/27
100% Branches 10/10
100% Functions 1/1
100% Lines 26/26

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116                          1x   1x                           1x   1579x     1579x 1579x     1579x 1579x       1530x 1530x   1530x 834x     834x 834x             4x   4x     830x     830x         830x 830x         830x                         830x                     830x 55x   55x         1579x            
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;