I want to ask about how to calculate the shadow of a Cesium3DTileset on the ground. Currently, I am following this logic:
- Obtain the boundingSphere of the Cesium3DTileset.
- Calculate the position of the sun using Simon1994PlanetaryPositions.
- Calculate the light vector from the sun to the center of the Cesium3DTileset.
- Calculate the intersection points between the light direction vector and the object, and project them onto the ground.
- 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;
};