diff --git a/Source/Core/GeometryPipeline.js b/Source/Core/GeometryPipeline.js index 25ab70f16775..816416fa96dc 100644 --- a/Source/Core/GeometryPipeline.js +++ b/Source/Core/GeometryPipeline.js @@ -808,7 +808,7 @@ define([ Matrix4.inverse(modelMatrix, inverseTranspose); Matrix4.transpose(inverseTranspose, inverseTranspose); - Matrix4.getRotation(inverseTranspose, normalMatrix); + Matrix4.getMatrix3(inverseTranspose, normalMatrix); transformVector(normalMatrix, attributes.normal); transformVector(normalMatrix, attributes.tangent); diff --git a/Source/Core/Matrix3.js b/Source/Core/Matrix3.js index 23e9b6c21376..0937d9e2425b 100644 --- a/Source/Core/Matrix3.js +++ b/Source/Core/Matrix3.js @@ -1023,6 +1023,27 @@ define([ return result; }; + var UNIT = new Cartesian3(1, 1, 1); + + /** + * Extracts the rotation assuming the matrix is an affine transformation. + * + * @param {Matrix3} matrix The matrix. + * @param {Matrix3} result The object onto which to store the result. + * @returns {Cartesian3} The modified result parameter + */ + Matrix3.getRotation = function(matrix, result) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.object('matrix', matrix); + Check.typeOf.object('result', result); + //>>includeEnd('debug'); + + var inverseScale = Cartesian3.divideComponents(UNIT, Matrix3.getScale(matrix, scratchScale), scratchScale); + result = Matrix3.multiplyByScale(matrix, inverseScale, result); + + return result; + }; + function computeFrobeniusNorm(matrix) { var norm = 0.0; for (var i = 0; i < 9; ++i) { diff --git a/Source/Core/Matrix4.js b/Source/Core/Matrix4.js index 19ed5ed1d520..e750680465c7 100644 --- a/Source/Core/Matrix4.js +++ b/Source/Core/Matrix4.js @@ -2149,6 +2149,13 @@ define([ return result; }; + /** + * @deprecated moved to Matrix4.getMatrix3 + */ + Matrix4.getRotation = function(matrix, result) { + return Matrix4.getMatrix3(matrix, result); + }; + /** * Gets the upper left 3x3 rotation matrix of the provided matrix, assuming the matrix is a affine transformation matrix. * @@ -2165,13 +2172,13 @@ define([ * // [13.0, 17.0, 21.0, 25.0] * * var b = new Cesium.Matrix3(); - * Cesium.Matrix4.getRotation(m,b); + * Cesium.Matrix4.getMatrix3(m,b); * * // b = [10.0, 14.0, 18.0] * // [11.0, 15.0, 19.0] * // [12.0, 16.0, 20.0] */ - Matrix4.getRotation = function(matrix, result) { + Matrix4.getMatrix3 = function(matrix, result) { //>>includeStart('debug', pragmas.debug); Check.typeOf.object('matrix', matrix); Check.typeOf.object('result', result); @@ -2286,7 +2293,7 @@ define([ if (Math.abs(det) < CesiumMath.EPSILON21) { // Special case for a zero scale matrix that can occur, for example, // when a model's node has a [0, 0, 0] scale. - if (Matrix3.equalsEpsilon(Matrix4.getRotation(matrix, scratchInverseRotation), scratchMatrix3Zero, CesiumMath.EPSILON7) && + if (Matrix3.equalsEpsilon(Matrix4.getMatrix3(matrix, scratchInverseRotation), scratchMatrix3Zero, CesiumMath.EPSILON7) && Cartesian4.equals(Matrix4.getRow(matrix, 3, scratchBottomRow), scratchExpectedBottomRow)) { result[0] = 0.0; @@ -2353,7 +2360,7 @@ define([ //>>includeEnd('debug'); //This function is an optimized version of the below 4 lines. - //var rT = Matrix3.transpose(Matrix4.getRotation(matrix)); + //var rT = Matrix3.transpose(Matrix4.getMatrix3(matrix)); //var rTN = Matrix3.negate(rT); //var rTT = Matrix3.multiplyByVector(rTN, Matrix4.getTranslation(matrix)); //return Matrix4.fromRotationTranslation(rT, rTT, result); diff --git a/Source/Core/Transforms.js b/Source/Core/Transforms.js index 7732bb39f097..72928ec492e8 100644 --- a/Source/Core/Transforms.js +++ b/Source/Core/Transforms.js @@ -376,7 +376,7 @@ define([ //>>includeEnd('debug'); var transform = Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, scratchENUMatrix4); - var rotation = Matrix4.getRotation(transform, scratchHPRMatrix3); + var rotation = Matrix4.getMatrix3(transform, scratchHPRMatrix3); return Quaternion.fromRotationMatrix(rotation, result); }; @@ -421,7 +421,7 @@ define([ transformCopy = Matrix4.setTranslation(transformCopy, Cartesian3.ZERO, transformCopy); toFixedFrame = Matrix4.multiply(toFixedFrame, transformCopy, toFixedFrame); - var quaternionRotation = Quaternion.fromRotationMatrix(Matrix4.getRotation(toFixedFrame, hprRotationScratch), hprQuaternionScratch); + var quaternionRotation = Quaternion.fromRotationMatrix(Matrix4.getMatrix3(toFixedFrame, hprRotationScratch), hprQuaternionScratch); quaternionRotation = Quaternion.normalize(quaternionRotation, quaternionRotation); return HeadingPitchRoll.fromQuaternion(quaternionRotation, result); @@ -878,7 +878,7 @@ define([ // Assuming the instance are positioned in WGS84, invert the WGS84 transform to get the local transform and then convert to 2D var fromENU = Transforms.eastNorthUpToFixedFrame(rtcCenter, ellipsoid, scratchFromENU); var toENU = Matrix4.inverseTransformation(fromENU, scratchToENU); - var rotation = Matrix4.getRotation(matrix, scratchRotation); + var rotation = Matrix4.getMatrix3(matrix, scratchRotation); var local = Matrix4.multiplyByMatrix3(toENU, rotation, result); Matrix4.multiply(swizzleMatrix, local, result); // Swap x, y, z for 2D Matrix4.setTranslation(result, projectedPosition, result); // Use the projected center diff --git a/Source/Renderer/UniformState.js b/Source/Renderer/UniformState.js index aff11a5b9196..f431f1ae2ebb 100644 --- a/Source/Renderer/UniformState.js +++ b/Source/Renderer/UniformState.js @@ -296,7 +296,7 @@ define([ if (this._inverseTransposeModelDirty) { this._inverseTransposeModelDirty = false; - Matrix4.getRotation(this.inverseModel, m); + Matrix4.getMatrix3(this.inverseModel, m); Matrix3.transpose(m, m); } @@ -967,7 +967,7 @@ define([ function setView(uniformState, matrix) { Matrix4.clone(matrix, uniformState._view); - Matrix4.getRotation(matrix, uniformState._viewRotation); + Matrix4.getMatrix3(matrix, uniformState._viewRotation); uniformState._view3DDirty = true; uniformState._inverseView3DDirty = true; @@ -989,7 +989,7 @@ define([ function setInverseView(uniformState, matrix) { Matrix4.clone(matrix, uniformState._inverseView); - Matrix4.getRotation(matrix, uniformState._inverseViewRotation); + Matrix4.getMatrix3(matrix, uniformState._inverseViewRotation); } function setProjection(uniformState, matrix) { @@ -1294,7 +1294,8 @@ define([ uniformState._normalDirty = false; var m = uniformState._normal; - Matrix4.getRotation(uniformState.inverseModelView, m); + Matrix4.getMatrix3(uniformState.inverseModelView, m); + Matrix3.getRotation(m, m); Matrix3.transpose(m, m); } } @@ -1304,7 +1305,8 @@ define([ uniformState._normal3DDirty = false; var m = uniformState._normal3D; - Matrix4.getRotation(uniformState.inverseModelView3D, m); + Matrix4.getMatrix3(uniformState.inverseModelView3D, m); + Matrix3.getRotation(m, m); Matrix3.transpose(m, m); } } @@ -1312,16 +1314,16 @@ define([ function cleanInverseNormal(uniformState) { if (uniformState._inverseNormalDirty) { uniformState._inverseNormalDirty = false; - - Matrix4.getRotation(uniformState.inverseModelView, uniformState._inverseNormal); + Matrix4.getMatrix3(uniformState.inverseModelView, uniformState._inverseNormal); + Matrix3.getRotation(uniformState._inverseNormal, uniformState._inverseNormal); } } function cleanInverseNormal3D(uniformState) { if (uniformState._inverseNormal3DDirty) { uniformState._inverseNormal3DDirty = false; - - Matrix4.getRotation(uniformState.inverseModelView3D, uniformState._inverseNormal3D); + Matrix4.getMatrix3(uniformState.inverseModelView3D, uniformState._inverseNormal3D); + Matrix3.getRotation(uniformState._inverseNormal3D, uniformState._inverseNormal3D); } } @@ -1424,7 +1426,7 @@ define([ } else { view2Dto3D(that._cameraPosition, that._cameraDirection, that._cameraRight, that._cameraUp, that._frustum2DWidth, that._mode, that._mapProjection, that._view3D); } - Matrix4.getRotation(that._view3D, that._viewRotation3D); + Matrix4.getMatrix3(that._view3D, that._viewRotation3D); that._view3DDirty = false; } } @@ -1432,7 +1434,7 @@ define([ function updateInverseView3D(that){ if (that._inverseView3DDirty) { Matrix4.inverseTransformation(that.view3D, that._inverseView3D); - Matrix4.getRotation(that._inverseView3D, that._inverseViewRotation3D); + Matrix4.getMatrix3(that._inverseView3D, that._inverseViewRotation3D); that._inverseView3DDirty = false; } } diff --git a/Source/Scene/Cesium3DTile.js b/Source/Scene/Cesium3DTile.js index ce8c95085c11..0df77e743b41 100644 --- a/Source/Scene/Cesium3DTile.js +++ b/Source/Scene/Cesium3DTile.js @@ -140,12 +140,15 @@ define([ * @readonly */ this.geometricError = header.geometricError; + this._geometricError = header.geometricError; - if (!defined(this.geometricError)) { - this.geometricError = defined(parent) ? parent.geometricError : tileset._geometricError; + if (!defined(this._geometricError)) { + this._geometricError = defined(parent) ? parent.geometricError : tileset._geometricError; Cesium3DTile._deprecationWarning('geometricErrorUndefined', 'Required property geometricError is undefined for this tile. Using parent\'s geometric error instead.'); } + this.updateGeometricErrorScale(); + var refine; if (defined(header.refine)) { if (header.refine === 'replace' || header.refine === 'add') { @@ -990,7 +993,7 @@ define([ // Find the transformed center and halfAxes center = Matrix4.multiplyByPoint(transform, center, center); - var rotationScale = Matrix4.getRotation(transform, scratchMatrix); + var rotationScale = Matrix4.getMatrix3(transform, scratchMatrix); halfAxes = Matrix3.multiply(rotationScale, halfAxes, halfAxes); if (defined(result)) { @@ -1014,7 +1017,7 @@ define([ // This is why the transform is calculated as the difference between the initial transform and the current transform. transform = Matrix4.multiplyTransformation(transform, Matrix4.inverseTransformation(initialTransform, scratchTransform), scratchTransform); center = Matrix4.multiplyByPoint(transform, center, center); - var rotationScale = Matrix4.getRotation(transform, scratchMatrix); + var rotationScale = Matrix4.getMatrix3(transform, scratchMatrix); halfAxes = Matrix3.multiply(rotationScale, halfAxes, halfAxes); if (defined(result) && (result instanceof TileOrientedBoundingBox)) { @@ -1114,12 +1117,20 @@ define([ this._viewerRequestVolume = this.createBoundingVolume(header.viewerRequestVolume, this.computedTransform, this._viewerRequestVolume); } + this.updateGeometricErrorScale(); + // Destroy the debug bounding volumes. They will be generated fresh. this._debugBoundingVolume = this._debugBoundingVolume && this._debugBoundingVolume.destroy(); this._debugContentBoundingVolume = this._debugContentBoundingVolume && this._debugContentBoundingVolume.destroy(); this._debugViewerRequestVolume = this._debugViewerRequestVolume && this._debugViewerRequestVolume.destroy(); }; + Cesium3DTile.prototype.updateGeometricErrorScale = function() { + var scale = Matrix4.getScale(this.computedTransform, scratchScale); + var uniformScale = Cartesian3.maximumComponent(scale); + this.geometricError = this._geometricError * uniformScale; + }; + function applyDebugSettings(tile, tileset, frameState) { if (!frameState.passes.render) { return; diff --git a/Source/Scene/Instanced3DModel3DTileContent.js b/Source/Scene/Instanced3DModel3DTileContent.js index aa150f33f08b..d00d17e8b288 100644 --- a/Source/Scene/Instanced3DModel3DTileContent.js +++ b/Source/Scene/Instanced3DModel3DTileContent.js @@ -378,7 +378,7 @@ define([ hasCustomOrientation = true; } else if (eastNorthUp) { Transforms.eastNorthUpToFixedFrame(instancePosition, Ellipsoid.WGS84, instanceTransform); - Matrix4.getRotation(instanceTransform, instanceRotation); + Matrix4.getMatrix3(instanceTransform, instanceRotation); } else { Matrix3.clone(Matrix3.IDENTITY, instanceRotation); } diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index d8dee18a2e78..a4b0d1180f71 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -2892,7 +2892,7 @@ define([ var mInverseTranspose = new Matrix3(); return function() { Matrix4.inverse(runtimeNode.computedMatrix, mInverse); - Matrix4.getRotation(mInverse, mInverseTranspose); + Matrix4.getMatrix3(mInverse, mInverseTranspose); return Matrix3.transpose(mInverseTranspose, mInverseTranspose); }; }, @@ -2903,7 +2903,7 @@ define([ return function() { Matrix4.multiplyTransformation(uniformState.view, runtimeNode.computedMatrix, mv); Matrix4.inverse(mv, mvInverse); - Matrix4.getRotation(mvInverse, mvInverseTranspose); + Matrix4.getMatrix3(mvInverse, mvInverseTranspose); return Matrix3.transpose(mvInverseTranspose, mvInverseTranspose); }; }, diff --git a/Specs/Core/Matrix3Spec.js b/Specs/Core/Matrix3Spec.js index 5ff147cbc677..300a21d70ad9 100644 --- a/Specs/Core/Matrix3Spec.js +++ b/Specs/Core/Matrix3Spec.js @@ -639,6 +639,41 @@ defineSuite([ expect(result).toEqual(expected); }); + it('getRotation returns matrix without scale', function() { + var matrix = new Matrix3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0); + var result = new Matrix3(); + var expected = Matrix3.fromArray([ + 0.12309149097933272, 0.4923659639173309, 0.8616404368553291, + 0.20739033894608505, 0.5184758473652127, 0.8295613557843402, + 0.26726124191242440, 0.5345224838248488, 0.8017837257372732 + ]); + var scale = new Cartesian3(); + var expectedScale = new Cartesian3(1.0, 1.0, 1.0); + result = Matrix3.getRotation(matrix, result); + console.log(result); + var resultScale = Matrix3.getScale(result, scale); + expect(resultScale).toEqualEpsilon(expectedScale, CesiumMath.EPSILON14); + expect(result).toEqualEpsilon(expected, CesiumMath.EPSILON14); + }); + + it('getRotation does not modify rotation matrix', function() { + var tmp = new Matrix3(); + var result = new Matrix3(); + var rotation = Matrix3.clone(Matrix3.IDENTITY, new Matrix3()); + Matrix3.multiply(rotation, Matrix3.fromRotationX(1.0, tmp), rotation); + Matrix3.multiply(rotation, Matrix3.fromRotationY(2.0, tmp), rotation); + Matrix3.multiply(rotation, Matrix3.fromRotationZ(3.0, tmp), rotation); + result = Matrix3.getRotation(rotation, result); + expect(rotation).toEqualEpsilon(result, CesiumMath.EPSILON14); + expect(rotation).not.toBe(result); + }); + + it('getRotation throws without a matrix', function() { + expect(function() { + return Matrix3.getRotation(); + }).toThrowDeveloperError(); + }); + it('transpose works with a result parameter that is an input result parameter', function() { var matrix = new Matrix3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0); var expected = new Matrix3(1.0, 4.0, 7.0, 2.0, 5.0, 8.0, 3.0, 6.0, 9.0);