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

Fix the transformation of plane's normal #9135

Merged
merged 13 commits into from
Sep 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@

### 1.74 - 2020-10-01

##### Additions :tada:

- Added `Matrix3.inverseTranspose` and `Matrix4.inverseTranspose`. [#9135](https://github.com/CesiumGS/cesium/pull/9135)

##### Fixes :wrench:

- Fixed an issue where the camera zooming is stuck when looking up. [#9126](https://github.com/CesiumGS/cesium/pull/9126)
- Fixed an issue where Plane doesn't rotate correctly around the main local axis. [#8268](https://github.com/CesiumGS/cesium/issues/8268)
- Fixed clipping planes with non-uniform scale. [#9135](https://github.com/CesiumGS/cesium/pull/9135)
- Fixed an issue where ground primitives would get clipped at certain camera angles. [#9114](https://github.com/CesiumGS/cesium/issues/9114)

### 1.73 - 2020-09-01
Expand Down
21 changes: 21 additions & 0 deletions Source/Core/Matrix3.js
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,27 @@ Matrix3.inverse = function (matrix, result) {
return Matrix3.multiplyByScalar(result, scale, result);
};

var scratchTransposeMatrix = new Matrix3();

/**
* Computes the inverse transpose of a matrix.
*
* @param {Matrix3} matrix The matrix to transpose and invert.
* @param {Matrix3} result The object onto which to store the result.
* @returns {Matrix3} The modified result parameter.
*/
Matrix3.inverseTranspose = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');

return Matrix3.inverse(
Matrix3.transpose(matrix, scratchTransposeMatrix),
result
);
};

/**
* Compares the provided matrices componentwise and returns
* <code>true</code> if they are equal, <code>false</code> otherwise.
Expand Down
21 changes: 21 additions & 0 deletions Source/Core/Matrix4.js
Original file line number Diff line number Diff line change
Expand Up @@ -2647,6 +2647,27 @@ Matrix4.inverseTransformation = function (matrix, result) {
return result;
};

var scratchTransposeMatrix = new Matrix4();

/**
* Computes the inverse transpose of a matrix.
*
* @param {Matrix4} matrix The matrix to transpose and invert.
* @param {Matrix4} result The object onto which to store the result.
* @returns {Matrix4} The modified result parameter.
*/
Matrix4.inverseTranspose = function (matrix, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("matrix", matrix);
Check.typeOf.object("result", result);
//>>includeEnd('debug');

return Matrix4.inverse(
Matrix4.transpose(matrix, scratchTransposeMatrix),
result
);
};

/**
* An immutable Matrix4 instance initialized to the identity matrix.
*
Expand Down
40 changes: 34 additions & 6 deletions Source/Core/Plane.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Cartesian3 from "./Cartesian3.js";
import Cartesian4 from "./Cartesian4.js";
import Check from "./Check.js";
import defined from "./defined.js";
import DeveloperError from "./DeveloperError.js";
Expand Down Expand Up @@ -192,7 +193,9 @@ Plane.projectPointOntoPlane = function (plane, point, result) {
return Cartesian3.subtract(point, scaledNormal, result);
};

var scratchPosition = new Cartesian3();
var scratchInverseTranspose = new Matrix4();
var scratchPlaneCartesian4 = new Cartesian4();
var scratchTransformNormal = new Cartesian3();
/**
* Transforms the plane by the given transformation matrix.
*
Expand All @@ -207,13 +210,38 @@ Plane.transform = function (plane, transform, result) {
Check.typeOf.object("transform", transform);
//>>includeEnd('debug');

Matrix4.multiplyByPointAsVector(transform, plane.normal, scratchNormal);
Cartesian3.normalize(scratchNormal, scratchNormal);
var normal = plane.normal;
var distance = plane.distance;
var inverseTranspose = Matrix4.inverseTranspose(
transform,
scratchInverseTranspose
);
var planeAsCartesian4 = Cartesian4.fromElements(
normal.x,
normal.y,
normal.z,
distance,
scratchPlaneCartesian4
);
planeAsCartesian4 = Matrix4.multiplyByVector(
inverseTranspose,
planeAsCartesian4,
planeAsCartesian4
);

Cartesian3.multiplyByScalar(plane.normal, -plane.distance, scratchPosition);
Matrix4.multiplyByPoint(transform, scratchPosition, scratchPosition);
// Convert the transformed plane to Hessian Normal Form
var transformedNormal = Cartesian3.fromCartesian4(
planeAsCartesian4,
scratchTransformNormal
);

planeAsCartesian4 = Cartesian4.divideByScalar(
planeAsCartesian4,
Cartesian3.magnitude(transformedNormal),
planeAsCartesian4
);

return Plane.fromPointNormal(scratchPosition, scratchNormal, result);
return Plane.fromCartesian4(planeAsCartesian4, result);
};

/**
Expand Down
2 changes: 1 addition & 1 deletion Source/Scene/Batched3DModel3DTileContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ Batched3DModel3DTileContent.prototype.update = function (tileset, frameState) {

// Update clipping planes
var tilesetClippingPlanes = this._tileset.clippingPlanes;
this._model.clippingPlanesOriginMatrix = this._tileset.clippingPlanesOriginMatrix;
this._model.referenceMatrix = this._tileset.clippingPlanesOriginMatrix;
if (defined(tilesetClippingPlanes) && this._tile.clippingPlanesDirty) {
// Dereference the clipping planes from the model if they are irrelevant.
// Link/Dereference directly to avoid ownership checks.
Expand Down
12 changes: 9 additions & 3 deletions Source/Scene/GlobeSurfaceTileProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -1501,7 +1501,8 @@ GlobeSurfaceTileProvider.prototype._onLayerShownOrHidden = function (
}
};

var scratchClippingPlaneMatrix = new Matrix4();
var scratchClippingPlanesMatrix = new Matrix4();
var scratchInverseTransposeClippingPlanesMatrix = new Matrix4();
function createTileUniformMap(frameState, globeSurfaceTileProvider) {
var uniformMap = {
u_initialColor: function () {
Expand Down Expand Up @@ -1634,13 +1635,18 @@ function createTileUniformMap(frameState, globeSurfaceTileProvider) {
},
u_clippingPlanesMatrix: function () {
var clippingPlanes = globeSurfaceTileProvider._clippingPlanes;
return defined(clippingPlanes)
var transform = defined(clippingPlanes)
? Matrix4.multiply(
frameState.context.uniformState.view,
clippingPlanes.modelMatrix,
scratchClippingPlaneMatrix
scratchClippingPlanesMatrix
)
: Matrix4.IDENTITY;

return Matrix4.inverseTranspose(
transform,
scratchInverseTransposeClippingPlanesMatrix
);
},
u_clippingPlanesEdgeStyle: function () {
var style = this.properties.clippingPlanesEdgeColor;
Expand Down
2 changes: 1 addition & 1 deletion Source/Scene/Instanced3DModel3DTileContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ Instanced3DModel3DTileContent.prototype.update = function (
if (defined(model)) {
// Update for clipping planes
var tilesetClippingPlanes = this._tileset.clippingPlanes;
model.clippingPlanesOriginMatrix = this._tileset.clippingPlanesOriginMatrix;
model.referenceMatrix = this._tileset.clippingPlanesOriginMatrix;
if (defined(tilesetClippingPlanes) && this._tile.clippingPlanesDirty) {
// Dereference the clipping planes from the model if they are irrelevant - saves on shading
// Link/Dereference directly to avoid ownership checks.
Expand Down
108 changes: 71 additions & 37 deletions Source/Scene/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -489,10 +489,12 @@ function Model(options) {
this.clippingPlanes = options.clippingPlanes;
// Used for checking if shaders need to be regenerated due to clipping plane changes.
this._clippingPlanesState = 0;
// If defined, use this matrix to position the clipping planes instead of the modelMatrix.
// This is so that when models are part of a tileset they all get clipped relative
// to the root tile.
this.clippingPlanesOriginMatrix = undefined;

// If defined, use this matrix to transform miscellaneous properties like
// clipping planes and IBL instead of the modelMatrix. This is so that when
// models are part of a tileset these properties get transformed relative to
// a common reference (such as the root).
this.referenceMatrix = undefined;

/**
* Whether to cull back-facing geometry. When true, back face culling is
Expand Down Expand Up @@ -564,7 +566,8 @@ function Model(options) {
this.opaquePass = defaultValue(options.opaquePass, Pass.OPAQUE);

this._computedModelMatrix = new Matrix4(); // Derived from modelMatrix and scale
this._clippingPlaneModelViewMatrix = Matrix4.clone(Matrix4.IDENTITY); // Derived from modelMatrix, scale, and the current view matrix
this._clippingPlanesMatrix = Matrix4.clone(Matrix4.IDENTITY); // Derived from reference matrix and the current view matrix
this._iblReferenceFrameMatrix = Matrix3.clone(Matrix3.IDENTITY); // Derived from reference matrix and the current view matrix
this._initialRadius = undefined; // Radius without model's scale property, model-matrix scale, animations, or skins
this._boundingSphere = undefined;
this._scaledBoundingSphere = new BoundingSphere();
Expand Down Expand Up @@ -2489,7 +2492,7 @@ function createProgram(programToCreate, model, context) {
model._useDefaultSpecularMaps;
var addMatrix = usesSH || usesSM || useIBL;
if (addMatrix) {
drawFS = "uniform mat4 gltf_clippingPlanesMatrix; \n" + drawFS;
drawFS = "uniform mat3 gltf_iblReferenceFrameMatrix; \n" + drawFS;
}

if (defined(model._sphericalHarmonicCoefficients)) {
Expand Down Expand Up @@ -2605,9 +2608,9 @@ function recreateProgram(programToCreate, model, context) {
(defined(model._specularEnvironmentMapAtlas) &&
model._specularEnvironmentMapAtlas.ready) ||
model._useDefaultSpecularMaps;
var addMatrix = !addClippingPlaneCode && (usesSH || usesSM || useIBL);
var addMatrix = usesSH || usesSM || useIBL;
if (addMatrix) {
drawFS = "uniform mat4 gltf_clippingPlanesMatrix; \n" + drawFS;
drawFS = "uniform mat3 gltf_iblReferenceFrameMatrix; \n" + drawFS;
}

if (defined(model._sphericalHarmonicCoefficients)) {
Expand Down Expand Up @@ -3659,25 +3662,15 @@ function createColorFunction(model) {
};
}

var scratchClippingPlaneMatrix = new Matrix4();
function createClippingPlanesMatrixFunction(model) {
return function () {
var clippingPlanes = model.clippingPlanes;
if (
!defined(clippingPlanes) &&
!defined(model._sphericalHarmonicCoefficients) &&
!defined(model._specularEnvironmentMaps)
) {
return Matrix4.IDENTITY;
}
var modelMatrix = defined(clippingPlanes)
? clippingPlanes.modelMatrix
: Matrix4.IDENTITY;
return Matrix4.multiply(
model._clippingPlaneModelViewMatrix,
modelMatrix,
scratchClippingPlaneMatrix
);
return model._clippingPlanesMatrix;
};
}

function createIBLReferenceFrameMatrixFunction(model) {
return function () {
return model._iblReferenceFrameMatrix;
};
}

Expand Down Expand Up @@ -3859,6 +3852,9 @@ function createCommand(model, gltfNode, runtimeNode, context, scene3DOnly) {
model
),
gltf_clippingPlanesMatrix: createClippingPlanesMatrixFunction(model),
gltf_iblReferenceFrameMatrix: createIBLReferenceFrameMatrixFunction(
model
),
gltf_iblFactor: createIBLFactorFunction(model),
gltf_lightColor: createLightColorFunction(model),
gltf_sphericalHarmonicCoefficients: createSphericalHarmonicCoefficientsFunction(
Expand Down Expand Up @@ -5101,6 +5097,10 @@ function distanceDisplayConditionVisible(model, frameState) {
return distance2 >= nearSquared && distance2 <= farSquared;
}

var scratchClippingPlanesMatrix = new Matrix4();
var scratchIBLReferenceFrameMatrix4 = new Matrix4();
var scratchIBLReferenceFrameMatrix3 = new Matrix3();

/**
* Called when {@link Viewer} or {@link CesiumWidget} render the scene to
* get the draw commands needed to render this primitive.
Expand Down Expand Up @@ -5507,27 +5507,61 @@ Model.prototype.update = function (frameState) {
defined(clippingPlanes) &&
clippingPlanes.enabled &&
clippingPlanes.length > 0;

// If defined, use the reference matrix to transform miscellaneous properties like
// clipping planes and IBL instead of the modelMatrix. This is so that when
// models are part of a tileset these properties get transformed relative to
// a common reference (such as the root).
var referenceMatrix = defaultValue(this.referenceMatrix, modelMatrix);

if (useClippingPlanes) {
var clippingPlanesMatrix = scratchClippingPlanesMatrix;
clippingPlanesMatrix = Matrix4.multiply(
context.uniformState.view3D,
referenceMatrix,
clippingPlanesMatrix
);
clippingPlanesMatrix = Matrix4.multiply(
clippingPlanesMatrix,
clippingPlanes.modelMatrix,
clippingPlanesMatrix
);
this._clippingPlanesMatrix = Matrix4.inverseTranspose(
clippingPlanesMatrix,
this._clippingPlanesMatrix
);
currentClippingPlanesState = clippingPlanes.clippingPlanesState;
}

var usesSH =
defined(this._sphericalHarmonicCoefficients) ||
this._useDefaultSphericalHarmonics;
var usesSM =
(defined(this._specularEnvironmentMapAtlas) &&
this._specularEnvironmentMapAtlas.ready) ||
this._useDefaultSpecularMaps;
if (useClippingPlanes || usesSH || usesSM) {
var clippingPlanesOriginMatrix = defaultValue(
this.clippingPlanesOriginMatrix,
modelMatrix
);
Matrix4.multiply(

if (usesSH || usesSM) {
var iblReferenceFrameMatrix3 = scratchIBLReferenceFrameMatrix3;
var iblReferenceFrameMatrix4 = scratchIBLReferenceFrameMatrix4;

iblReferenceFrameMatrix4 = Matrix4.multiply(
context.uniformState.view3D,
clippingPlanesOriginMatrix,
this._clippingPlaneModelViewMatrix
referenceMatrix,
iblReferenceFrameMatrix4
);
iblReferenceFrameMatrix3 = Matrix4.getMatrix3(
iblReferenceFrameMatrix4,
iblReferenceFrameMatrix3
);
iblReferenceFrameMatrix3 = Matrix3.getRotation(
iblReferenceFrameMatrix3,
iblReferenceFrameMatrix3
);
this._iblReferenceFrameMatrix = Matrix3.transpose(
iblReferenceFrameMatrix3,
this._iblReferenceFrameMatrix
);
}

if (useClippingPlanes) {
currentClippingPlanesState = clippingPlanes.clippingPlanesState;
}

var shouldRegenerateShaders = this._shouldRegenerateShaders;
Expand Down
16 changes: 11 additions & 5 deletions Source/Scene/PointCloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,8 @@ var normalLocation = 2;
var batchIdLocation = 3;
var numberOfAttributes = 4;

var scratchClippingPlaneMatrix = new Matrix4();
var scratchClippingPlanesMatrix = new Matrix4();
var scratchInverseTransposeClippingPlanesMatrix = new Matrix4();

function createResources(pointCloud, frameState) {
var context = frameState.context;
Expand Down Expand Up @@ -939,12 +940,17 @@ function createUniformMap(pointCloud, frameState) {
Matrix4.multiply(
context.uniformState.view3D,
clippingPlanesOriginMatrix,
scratchClippingPlaneMatrix
scratchClippingPlanesMatrix
);
return Matrix4.multiply(
scratchClippingPlaneMatrix,
var transform = Matrix4.multiply(
scratchClippingPlanesMatrix,
clippingPlanes.modelMatrix,
scratchClippingPlaneMatrix
scratchClippingPlanesMatrix
);

return Matrix4.inverseTranspose(
transform,
scratchInverseTransposeClippingPlanesMatrix
);
},
};
Expand Down
Loading