The shadow area of the Cesium3DTileset on the ground

I want to ask about how to calculate the shadow of a Cesium3DTileset on the ground. Currently, I am following this logic:

  1. Obtain the boundingSphere of the Cesium3DTileset.
  2. Calculate the position of the sun using Simon1994PlanetaryPositions.
  3. Calculate the light vector from the sun to the center of the Cesium3DTileset.
  4. Calculate the intersection points between the light direction vector and the object, and project them onto the ground.
  5. Calculate the area of the polygon formed by these points.

Here is my code:

const calculate3DTilesShadowArea = (
  tileset: Cesium.Cesium3DTileset, julianDate: Cesium.JulianDate, viewer: Cesium.Viewer,
) => {
  // Get BoundingSphere
  const boundingSphere = tileset.boundingSphere;

  // Get Sun Position
  const sunPosition = Cesium.Simon1994PlanetaryPositions.computeSunPositionInEarthInertialFrame(julianDate);

  // Vector light direction to bounding sphere center
  const lightDirection = Cesium.Cartesian3.normalize(
    Cesium.Cartesian3.subtract(
      sunPosition,
      boundingSphere.center,
      new Cesium.Cartesian3(),
    ),
    new Cesium.Cartesian3(),
  );

  // Create a matrix to transform points from the local space of the bounding sphere to world space
  const transformMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(boundingSphere.center);

  // Generate points on the surface of the bounding sphere to simulate the shadow outline
  const numPoints = 64; // Adjust for accuracy
  let boundingVolumePoints = [];
  for (let i = 0; i < numPoints; i++) {
    const angle = (i / numPoints) * Cesium.Math.TWO_PI;
    const x = boundingSphere.radius * Math.cos(angle);
    const y = boundingSphere.radius * Math.sin(angle);
    const z = 0;

    // Transform the point to world coordinates
    const point = Cesium.Matrix4.multiplyByPoint(transformMatrix, new Cesium.Cartesian3(x, y, z), new Cesium.Cartesian3());

    // Project the point in the direction of the light onto the ground plane (z = 0)
    const t = -point.z / lightDirection.z;
    const shadowPoint = new Cesium.Cartesian3(
      point.x + t * lightDirection.x,
      point.y + t * lightDirection.y,
      0, // z = 0 for ground plane
    );

    boundingVolumePoints.push(new Cesium.Cartesian2(shadowPoint.x, shadowPoint.y));
  }
  if (boundingVolumePoints.length < 3) {
    console.error('Not enough points for shadow calculation');
    return 0;
  }

  const area = computePolygonArea(boundingVolumePoints);

  return area;
};

Hi @DoHung1997,

Interesting use case! Are you looking for help on any particular part of this process?

Thanks!
Gabby