Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compute normals for voxel shape intersections #11847

Merged
merged 10 commits into from
Mar 7, 2024
Merged
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Change Log

### 1.116 - 2024-04-01

#### @cesium/engine

##### Additions :tada:

- Surface normals are now computed for clipping and shape bounds in VoxelEllipsoidShape and VoxelCylinderShape. [#11847](https://github.com/CesiumGS/cesium/pull/11847)

### 1.115 - 2024-03-01

#### @cesium/engine
Expand Down
84 changes: 14 additions & 70 deletions packages/engine/Source/Scene/VoxelCylinderShape.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,8 @@ function VoxelCylinderShape() {
* @readonly
*/
this.shaderUniforms = {
cylinderUvToRenderBoundsScale: new Cartesian3(),
cylinderUvToRenderBoundsTranslate: new Cartesian3(),
cylinderUvToRenderRadiusMin: 0.0,
cylinderRenderHeightMinMax: new Cartesian2(),
cylinderRenderRadiusMinMax: new Cartesian2(),
cylinderRenderAngleMinMax: new Cartesian2(),
cylinderUvToShapeUvRadius: new Cartesian2(),
cylinderUvToShapeUvHeight: new Cartesian2(),
Expand All @@ -113,10 +112,7 @@ function VoxelCylinderShape() {
*/
this.shaderDefines = {
CYLINDER_HAS_RENDER_BOUNDS_RADIUS_MIN: undefined,
CYLINDER_HAS_RENDER_BOUNDS_RADIUS_MAX: undefined,
CYLINDER_HAS_RENDER_BOUNDS_RADIUS_FLAT: undefined,
CYLINDER_HAS_RENDER_BOUNDS_HEIGHT: undefined,
CYLINDER_HAS_RENDER_BOUNDS_HEIGHT_FLAT: undefined,
CYLINDER_HAS_RENDER_BOUNDS_ANGLE: undefined,
CYLINDER_HAS_RENDER_BOUNDS_ANGLE_RANGE_EQUAL_ZERO: undefined,
CYLINDER_HAS_RENDER_BOUNDS_ANGLE_RANGE_UNDER_HALF: undefined,
Expand All @@ -143,17 +139,6 @@ function VoxelCylinderShape() {
}

const scratchScale = new Cartesian3();
const scratchBoundsTranslation = new Cartesian3();
const scratchBoundsScale = new Cartesian3();
const scratchBoundsScaleMatrix = new Matrix3();
const scratchTransformLocalToBounds = new Matrix4();
const scratchTransformUvToBounds = new Matrix4();

const transformUvToLocal = Matrix4.fromRotationTranslation(
Matrix3.fromUniformScale(2.0, new Matrix3()),
new Cartesian3(-1.0, -1.0, -1.0),
new Matrix4()
);

/**
* Update the shape's state.
Expand Down Expand Up @@ -339,11 +324,7 @@ VoxelCylinderShape.prototype.update = function (
epsilonAngleDiscontinuity
);

const renderIsDefaultMaxRadius = renderMaxRadius === defaultMaxRadius;
const renderIsDefaultMinRadius = renderMinRadius === defaultMinRadius;
const renderIsDefaultHeight =
renderMinHeight === defaultMinHeight &&
renderMaxHeight === defaultMaxHeight;
const renderIsAngleReversed = renderMaxAngle < renderMinAngle;
const renderAngleRange =
renderMaxAngle - renderMinAngle + renderIsAngleReversed * defaultAngleRange;
Expand Down Expand Up @@ -376,22 +357,16 @@ VoxelCylinderShape.prototype.update = function (
shaderDefines["CYLINDER_HAS_RENDER_BOUNDS_RADIUS_MIN"] = true;
shaderDefines["CYLINDER_INTERSECTION_INDEX_RADIUS_MIN"] = intersectionCount;
intersectionCount += 1;

shaderUniforms.cylinderUvToRenderRadiusMin =
renderMaxRadius / renderMinRadius;
}
if (!renderIsDefaultMaxRadius) {
shaderDefines["CYLINDER_HAS_RENDER_BOUNDS_RADIUS_MAX"] = true;
}
shaderUniforms.cylinderRenderRadiusMinMax = Cartesian2.fromElements(
renderMinRadius,
renderMaxRadius,
shaderUniforms.cylinderRenderRadiusMinMax
);

if (renderMinRadius === renderMaxRadius) {
shaderDefines["CYLINDER_HAS_RENDER_BOUNDS_RADIUS_FLAT"] = true;
}
if (!renderIsDefaultHeight) {
shaderDefines["CYLINDER_HAS_RENDER_BOUNDS_HEIGHT"] = true;
}
if (renderMinHeight === renderMaxHeight) {
shaderDefines["CYLINDER_HAS_RENDER_BOUNDS_HEIGHT_FLAT"] = true;
}
if (!shapeIsDefaultRadius) {
shaderDefines["CYLINDER_HAS_SHAPE_BOUNDS_RADIUS"] = true;

Expand Down Expand Up @@ -442,42 +417,11 @@ VoxelCylinderShape.prototype.update = function (
shaderUniforms.cylinderUvToShapeUvHeight
);
}

if (!renderIsDefaultMaxRadius || !renderIsDefaultHeight) {
const heightScale = 0.5 * (renderMaxHeight - renderMinHeight);
const scaleLocalToBounds = Cartesian3.fromElements(
1.0 / renderMaxRadius,
1.0 / renderMaxRadius,
1.0 / (heightScale === 0.0 ? 1.0 : heightScale),
scratchBoundsScale
);
// -inverse(scale) * translation // affine inverse
// -inverse(scale) * 0.5 * (minHeight + maxHeight)
const translateLocalToBounds = Cartesian3.fromElements(
0.0,
0.0,
-scaleLocalToBounds.z * 0.5 * (renderMinHeight + renderMaxHeight),
scratchBoundsTranslation
);
const transformLocalToBounds = Matrix4.fromRotationTranslation(
Matrix3.fromScale(scaleLocalToBounds, scratchBoundsScaleMatrix),
translateLocalToBounds,
scratchTransformLocalToBounds
);
const transformUvToBounds = Matrix4.multiplyTransformation(
transformLocalToBounds,
transformUvToLocal,
scratchTransformUvToBounds
);
shaderUniforms.cylinderUvToRenderBoundsScale = Matrix4.getScale(
transformUvToBounds,
shaderUniforms.cylinderUvToRenderBoundsScale
);
shaderUniforms.cylinderUvToRenderBoundsTranslate = Matrix4.getTranslation(
transformUvToBounds,
shaderUniforms.cylinderUvToRenderBoundsTranslate
);
}
shaderUniforms.cylinderRenderHeightMinMax = Cartesian2.fromElements(
renderMinHeight,
renderMaxHeight,
shaderUniforms.cylinderRenderHeightMinMax
);

if (shapeIsAngleReversed) {
shaderDefines["CYLINDER_HAS_SHAPE_BOUNDS_ANGLE_MIN_MAX_REVERSED"] = true;
Expand All @@ -501,7 +445,7 @@ VoxelCylinderShape.prototype.update = function (
shaderUniforms.cylinderRenderAngleMinMax = Cartesian2.fromElements(
renderMinAngle,
renderMaxAngle,
shaderUniforms.cylinderAngleMinMax
shaderUniforms.cylinderRenderAngleMinMax
);
}

Expand Down
73 changes: 15 additions & 58 deletions packages/engine/Source/Scene/VoxelEllipsoidShape.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,10 @@ function VoxelEllipsoidShape() {
ellipsoidShapeUvLongitudeMinMaxMid: new Cartesian3(),
ellipsoidUvToShapeUvLongitude: new Cartesian2(),
ellipsoidUvToShapeUvLatitude: new Cartesian2(),
ellipsoidRenderLatitudeCosSqrHalfMinMax: new Cartesian2(),
ellipsoidRenderLatitudeSinMinMax: new Cartesian2(),
ellipsoidInverseHeightDifferenceUv: 0.0,
ellipseInnerRadiiUv: new Cartesian2(),
ellipsoidInverseInnerScaleUv: 0.0,
ellipsoidInverseOuterScaleUv: 0.0,
clipMinMaxHeight: new Cartesian2(),
};

/**
Expand All @@ -127,8 +126,6 @@ function VoxelEllipsoidShape() {
ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MIN_EQUAL_HALF: undefined,
ELLIPSOID_HAS_RENDER_BOUNDS_LATITUDE_MIN_OVER_HALF: undefined,
ELLIPSOID_HAS_SHAPE_BOUNDS_LATITUDE: undefined,
ELLIPSOID_HAS_RENDER_BOUNDS_HEIGHT_MAX: undefined,
ELLIPSOID_HAS_RENDER_BOUNDS_HEIGHT_MIN: undefined,
ELLIPSOID_HAS_SHAPE_BOUNDS_HEIGHT_FLAT: undefined,
ELLIPSOID_IS_SPHERE: undefined,
ELLIPSOID_INTERSECTION_INDEX_LONGITUDE: undefined,
Expand All @@ -150,7 +147,6 @@ const scratchScale = new Cartesian3();
const scratchRotationScale = new Matrix3();
const scratchShapeOuterExtent = new Cartesian3();
const scratchRenderOuterExtent = new Cartesian3();
const scratchRenderInnerExtent = new Cartesian3();
const scratchRenderRectangle = new Rectangle();

/**
Expand Down Expand Up @@ -270,16 +266,6 @@ VoxelEllipsoidShape.prototype.update = function (
);
const shapeMaxExtent = Cartesian3.maximumComponent(shapeOuterExtent);

const renderInnerExtent = Cartesian3.add(
radii,
Cartesian3.fromElements(
renderMinHeight,
renderMinHeight,
renderMinHeight,
scratchRenderInnerExtent
),
scratchRenderInnerExtent
);
const renderOuterExtent = Cartesian3.add(
radii,
Cartesian3.fromElements(
Expand Down Expand Up @@ -441,16 +427,6 @@ VoxelEllipsoidShape.prototype.update = function (
shapeIsLatitudeMinOverHalf;
const shapeHasLatitude = shapeHasLatitudeMax || shapeHasLatitudeMin;

// Height
const renderHasMinHeight = !Cartesian3.equals(
renderInnerExtent,
Cartesian3.ZERO
);
const renderHasMaxHeight = !Cartesian3.equals(
renderOuterExtent,
Cartesian3.ZERO
);

const { shaderUniforms, shaderDefines } = this;

// To keep things simple, clear the defines every time
Expand Down Expand Up @@ -484,27 +460,14 @@ VoxelEllipsoidShape.prototype.update = function (
// Intersects an outer ellipsoid for the max height.
shaderDefines["ELLIPSOID_INTERSECTION_INDEX_HEIGHT_MAX"] = intersectionCount;
intersectionCount += 1;
shaderDefines["ELLIPSOID_INTERSECTION_INDEX_HEIGHT_MIN"] = intersectionCount;
intersectionCount += 1;

if (renderHasMinHeight) {
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_HEIGHT_MIN"] = true;
shaderDefines[
"ELLIPSOID_INTERSECTION_INDEX_HEIGHT_MIN"
] = intersectionCount;
intersectionCount += 1;

// The inverse of the percent of space that is taken up by the inner ellipsoid, relative to the shape bounds
// 1.0 / (1.0 - thickness) // thickness = percent of space that is between the min and max height.
// 1.0 / (1.0 - (shapeMaxHeight - renderMinHeight) / shapeMaxExtent)
// shapeMaxExtent / (shapeMaxExtent - (shapeMaxHeight - renderMinHeight))
shaderUniforms.ellipsoidInverseInnerScaleUv =
shapeMaxExtent / (shapeMaxExtent - (shapeMaxHeight - renderMinHeight));
}

if (renderHasMaxHeight) {
shaderDefines["ELLIPSOID_HAS_RENDER_BOUNDS_HEIGHT_MAX"] = true;
shaderUniforms.ellipsoidInverseOuterScaleUv =
shapeMaxExtent / (shapeMaxExtent - (shapeMaxHeight - renderMaxHeight));
}
shaderUniforms.clipMinMaxHeight = Cartesian2.fromElements(
(renderMinHeight - shapeMaxHeight) / shapeMaxExtent,
(renderMaxHeight - shapeMaxHeight) / shapeMaxExtent,
shaderUniforms.clipMinMaxHeight
);

// The percent of space that is between the inner and outer ellipsoid.
const thickness = (shapeMaxHeight - shapeMinHeight) / shapeMaxExtent;
Expand Down Expand Up @@ -680,18 +643,12 @@ VoxelEllipsoidShape.prototype.update = function (
}
}

const minCosHalfAngleSqr = Math.pow(
Math.cos(CesiumMath.PI_OVER_TWO - Math.abs(renderMinLatitude)),
2.0
);
const maxCosHalfAngleSqr = Math.pow(
Math.cos(CesiumMath.PI_OVER_TWO - Math.abs(renderMaxLatitude)),
2.0
);
shaderUniforms.ellipsoidRenderLatitudeCosSqrHalfMinMax = Cartesian2.fromElements(
minCosHalfAngleSqr,
maxCosHalfAngleSqr,
shaderUniforms.ellipsoidRenderLatitudeCosSqrHalfMinMax
const sinMinLatitude = Math.sin(renderMinLatitude);
const sinMaxLatitude = Math.sin(renderMaxLatitude);
shaderUniforms.ellipsoidRenderLatitudeSinMinMax = Cartesian2.fromElements(
sinMinLatitude,
sinMaxLatitude,
shaderUniforms.ellipsoidRenderLatitudeSinMinMax
);
}

Expand Down
4 changes: 2 additions & 2 deletions packages/engine/Source/Scene/VoxelRenderResources.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,17 +132,17 @@ function VoxelRenderResources(primitive) {
]);
} else if (shapeType === "CYLINDER") {
shaderBuilder.addFragmentLines([
convertUvToCylinder,
IntersectLongitude,
IntersectCylinder,
Intersection,
convertUvToCylinder,
]);
} else if (shapeType === "ELLIPSOID") {
shaderBuilder.addFragmentLines([
convertUvToEllipsoid,
IntersectLongitude,
IntersectEllipsoid,
Intersection,
convertUvToEllipsoid,
]);
}

Expand Down
Loading
Loading