ソースを参照

Merge pull request #5300 from barroij/localTmpVectorInBounding

use dedicated TmpVector3 For BBox and BSphere + Prevent some Matrix inversion
David Catuhe 6 年 前
コミット
205f695aa7

+ 1 - 0
dist/preview release/what's new.md

@@ -16,6 +16,7 @@
 - Added utility function `Tools.BuildArray` for array initialisation ([barroij](https://github.com/barroij))
 - Introduced a new `IOfflineSupport` interface to hide IndexedDB ([Deltakosh](https://github.com/deltakosh))
 - `PBRMaterial` and `StandardMaterial` now use hot swapping feature for shaders. This means they can keep using a previous shader while a new one is being compiled ([Deltakosh](https://github.com/deltakosh))
+- Performance oriented change (prevent avoidable matrix inversion or square root computation) ([barroij](https://github.com/barroij))
 
 ### glTF Loader
 

+ 4 - 3
src/Culling/babylon.boundingBox.ts

@@ -49,6 +49,7 @@
         public maximum: Vector3 = Vector3.Zero();
 
         private _worldMatrix: Matrix;
+        private static TmpVector3 = Tools.BuildArray(3, Vector3.Zero);
 
         /**
          * @hidden
@@ -89,8 +90,8 @@
             vectors[7].copyFromFloats(maxX, minY, maxZ);
 
             // OBB
-            this.maximum.addToRef(min, this.center).scaleInPlace(0.5);
-            this.maximum.subtractToRef(max, this.extendSize).scaleInPlace(0.5);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
+            max.subtractToRef(max, this.extendSize).scaleInPlace(0.5);
 
             this._update(worldMatrix || this._worldMatrix || Matrix.Identity());
         }
@@ -101,7 +102,7 @@
          * @returns the current bounding box
          */
         public scale(factor: number): BoundingBox {
-            const tmpVectors = Tmp.Vector3;
+            const tmpVectors = BoundingBox.TmpVector3;
             const diff = this.maximum.subtractToRef(this.minimum, tmpVectors[0]);
             const len = diff.length();
             diff.normalizeFromLength(len);

+ 14 - 20
src/Culling/babylon.boundingSphere.ts

@@ -31,6 +31,8 @@ module BABYLON {
          */
         public maximum = Vector3.Zero();
 
+        private static TmpVector3 = Tools.BuildArray(3, Vector3.Zero);
+
         /**
          * Creates a new bounding sphere
          * @param min defines the minimum vector (in local space)
@@ -53,7 +55,7 @@ module BABYLON {
 
             var distance = Vector3.Distance(min, max);
 
-            Vector3.LerpToRef(min, max, 0.5, this.center);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
             this.radius = distance * 0.5;
 
             this._update(worldMatrix || _identityMatrix);
@@ -65,11 +67,11 @@ module BABYLON {
          * @returns the current bounding box
          */
         public scale(factor: number): BoundingSphere {
-            let newRadius = this.radius * factor;
-            const tmpVectors = Tmp.Vector3;
-            const tempRadiusVector = tmpVectors[0].copyFromFloats(newRadius, newRadius, newRadius);
-            let min = this.center.subtractToRef(tempRadiusVector, tmpVectors[1]);
-            let max = this.center.addToRef(tempRadiusVector, tmpVectors[2]);
+            const newRadius = this.radius * factor;
+            const tmpVectors = BoundingSphere.TmpVector3;
+            const tempRadiusVector = tmpVectors[0].setAll(newRadius);
+            const min = this.center.subtractToRef(tempRadiusVector, tmpVectors[1]);
+            const max = this.center.addToRef(tempRadiusVector, tmpVectors[2]);
 
             this.reConstruct(min, max);
 
@@ -80,7 +82,7 @@ module BABYLON {
         /** @hidden */
         public _update(world: Matrix): void {
             Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
-            const tempVector = Tmp.Vector3[0];
+            const tempVector = BoundingSphere.TmpVector3[0];
             Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, tempVector);
             this.radiusWorld = Math.max(Math.abs(tempVector.x), Math.abs(tempVector.y), Math.abs(tempVector.z)) * this.radius;
         }
@@ -106,13 +108,8 @@ module BABYLON {
          * @returns true if the point is inside the bounding sphere
          */
         public intersectsPoint(point: Vector3): boolean {
-            var x = this.centerWorld.x - point.x;
-            var y = this.centerWorld.y - point.y;
-            var z = this.centerWorld.z - point.z;
-
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-
-            if (this.radiusWorld < distance) {
+            const squareDistance = Vector3.DistanceSquared(this.centerWorld, point);
+            if (this.radiusWorld * this.radiusWorld < squareDistance) {
                 return false;
             }
 
@@ -127,13 +124,10 @@ module BABYLON {
          * @returns true if the speres intersect
          */
         public static Intersects(sphere0: BoundingSphere, sphere1: BoundingSphere): boolean {
-            var x = sphere0.centerWorld.x - sphere1.centerWorld.x;
-            var y = sphere0.centerWorld.y - sphere1.centerWorld.y;
-            var z = sphere0.centerWorld.z - sphere1.centerWorld.z;
-
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
+            const squareDistance = Vector3.DistanceSquared(sphere0.centerWorld, sphere1.centerWorld);
+            const radiusSum = sphere0.radiusWorld + sphere1.radiusWorld;
 
-            if (sphere0.radiusWorld + sphere1.radiusWorld < distance) {
+            if (radiusSum * radiusSum < squareDistance) {
                 return false;
             }
 

+ 55 - 65
src/Mesh/babylon.transformNode.ts

@@ -162,8 +162,8 @@ module BABYLON {
         public set rotationQuaternion(quaternion: Nullable<Quaternion>) {
             this._rotationQuaternion = quaternion;
             //reset the rotation vector.
-            if (quaternion && this.rotation.length()) {
-                this.rotation.copyFromFloats(0.0, 0.0, 0.0);
+            if (quaternion) {
+                this.rotation.setAll(0.0);
             }
         }
 
@@ -222,7 +222,7 @@ module BABYLON {
             }
 
             if (this.billboardMode !== this._cache.billboardMode || this.billboardMode !== TransformNode.BILLBOARDMODE_NONE) {
-                return false;
+                return false;
             }
 
             if (this._cache.pivotMatrixUpdated) {
@@ -234,21 +234,21 @@ module BABYLON {
             }
 
             if (!this._cache.position.equals(this._position)) {
-                return false;
+                return false;
             }
 
             if (this._rotationQuaternion) {
                 if (!this._cache.rotationQuaternion.equals(this._rotationQuaternion)) {
-                    return false;
+                    return false;
                 }
             }
 
             if (!this._cache.rotation.equals(this._rotation)) {
-                return false;
+                return false;
             }
 
             if (!this._cache.scaling.equals(this._scaling)) {
-                return false;
+                return false;
             }
 
             return true;
@@ -304,7 +304,7 @@ module BABYLON {
          * @returns the current TransformNode
         */
         public setPivotMatrix(matrix: Matrix, postMultiplyPivotMatrix = true): TransformNode {
-            this._pivotMatrix = matrix.clone();
+            this._pivotMatrix.copyFrom(matrix);
             this._cache.pivotMatrixUpdated = true;
             this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
 
@@ -391,10 +391,9 @@ module BABYLON {
                 absolutePositionZ = absolutePosition.z;
             }
             if (this.parent) {
-                var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                invertParentWorldMatrix.invert();
-                var worldPosition = new Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
-                this.position = Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
+                const invertParentWorldMatrix = Tmp.Matrix[0];
+                this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
+                Vector3.TransformCoordinatesFromFloatsToRef(absolutePositionX, absolutePositionY, absolutePositionZ, invertParentWorldMatrix, this.position);
             } else {
                 this.position.x = absolutePositionX;
                 this.position.y = absolutePositionY;
@@ -420,9 +419,8 @@ module BABYLON {
          */
         public getPositionExpressedInLocalSpace(): Vector3 {
             this.computeWorldMatrix();
-            var invLocalWorldMatrix = this._localWorld.clone();
-            invLocalWorldMatrix.invert();
-
+            const invLocalWorldMatrix = Tmp.Matrix[0];
+            this._localWorld.invertToRef(invLocalWorldMatrix);
             return Vector3.TransformNormal(this.position, invLocalWorldMatrix);
         }
 
@@ -571,34 +569,18 @@ module BABYLON {
             if (!node && !this.parent) {
                 return this;
             }
-            if (!node) {
-                var rotation = Tmp.Quaternion[0];
-                var position = Tmp.Vector3[0];
-                var scale = Tmp.Vector3[1];
 
+            var quatRotation = Tmp.Quaternion[0];
+            var position = Tmp.Vector3[0];
+            var scale = Tmp.Vector3[1];
+
+            if (!node) {
                 if (this.parent && this.parent.computeWorldMatrix) {
                     this.parent.computeWorldMatrix(true);
                 }
                 this.computeWorldMatrix(true);
-                this.getWorldMatrix().decompose(scale, rotation, position);
-
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                } else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
-
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
+                this.getWorldMatrix().decompose(scale, quatRotation, position);
             } else {
-                var rotation = Tmp.Quaternion[0];
-                var position = Tmp.Vector3[0];
-                var scale = Tmp.Vector3[1];
                 var diffMatrix = Tmp.Matrix[0];
                 var invParentMatrix = Tmp.Matrix[1];
 
@@ -607,23 +589,18 @@ module BABYLON {
 
                 node.getWorldMatrix().invertToRef(invParentMatrix);
                 this.getWorldMatrix().multiplyToRef(invParentMatrix, diffMatrix);
-                diffMatrix.decompose(scale, rotation, position);
-
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                } else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
+                diffMatrix.decompose(scale, quatRotation, position);
+            }
 
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
+            if (this.rotationQuaternion) {
+                this.rotationQuaternion.copyFrom(quatRotation);
+            } else {
+                quatRotation.toEulerAnglesToRef(this.rotation);
             }
 
+            this.scaling.copyFrom(scale);
+            this.position.copyFrom(position);
+
             this.parent = node;
             return this;
         }
@@ -693,8 +670,8 @@ module BABYLON {
         public rotate(axis: Vector3, amount: number, space?: Space): TransformNode {
             axis.normalize();
             if (!this.rotationQuaternion) {
-                this.rotationQuaternion = Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation = Vector3.Zero();
+                this.rotationQuaternion = this.rotation.toQuaternion();
+                this.rotation.setAll(0);
             }
             var rotationQuaternion: Quaternion;
             if (!space || (space as any) === Space.LOCAL) {
@@ -703,8 +680,8 @@ module BABYLON {
             }
             else {
                 if (this.parent) {
-                    var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                    invertParentWorldMatrix.invert();
+                    const invertParentWorldMatrix = Tmp.Matrix[0];
+                    this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
                     axis = Vector3.TransformNormal(axis, invertParentWorldMatrix);
                 }
                 rotationQuaternion = Quaternion.RotationAxisToRef(axis, amount, TransformNode._rotationAxisCache);
@@ -727,19 +704,32 @@ module BABYLON {
             axis.normalize();
             if (!this.rotationQuaternion) {
                 this.rotationQuaternion = Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation.copyFromFloats(0, 0, 0);
+                this.rotation.setAll(0);
             }
-            point.subtractToRef(this.position, Tmp.Vector3[0]);
-            Matrix.TranslationToRef(Tmp.Vector3[0].x, Tmp.Vector3[0].y, Tmp.Vector3[0].z, Tmp.Matrix[0]);
-            Tmp.Matrix[0].invertToRef(Tmp.Matrix[2]);
-            Matrix.RotationAxisToRef(axis, amount, Tmp.Matrix[1]);
-            Tmp.Matrix[2].multiplyToRef(Tmp.Matrix[1], Tmp.Matrix[2]);
-            Tmp.Matrix[2].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[2]);
 
-            Tmp.Matrix[2].decompose(Tmp.Vector3[0], Tmp.Quaternion[0], Tmp.Vector3[1]);
+            const tmpVector = Tmp.Vector3[0];
+            const finalScale = Tmp.Vector3[1];
+            const finalTranslation = Tmp.Vector3[2];
+
+            const finalRotation = Tmp.Quaternion[0];
+
+            const translationMatrix = Tmp.Matrix[0]; // T
+            const translationMatrixInv = Tmp.Matrix[1]; // T'
+            const rotationMatrix = Tmp.Matrix[2]; // R
+            const finalMatrix = Tmp.Matrix[3]; // T' x R x T
+
+            point.subtractToRef(this.position, tmpVector);
+            Matrix.TranslationToRef(tmpVector.x, tmpVector.y, tmpVector.z, translationMatrix); // T
+            Matrix.TranslationToRef(-tmpVector.x, -tmpVector.y, -tmpVector.z, translationMatrixInv); // T'
+            Matrix.RotationAxisToRef(axis, amount, rotationMatrix); // R
+
+            translationMatrixInv.multiplyToRef(rotationMatrix, finalMatrix); // T' x R
+            finalMatrix.multiplyToRef(translationMatrix, finalMatrix);  // T' x R x T
+
+            finalMatrix.decompose(finalScale, finalRotation, finalTranslation);
 
-            this.position.addInPlace(Tmp.Vector3[1]);
-            Tmp.Quaternion[0].multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
+            this.position.addInPlace(finalTranslation);
+            finalRotation.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
 
             return this;
         }

+ 14 - 4
src/Particles/babylon.solidParticleSystem.ts

@@ -301,13 +301,23 @@ module BABYLON {
             var index = 0;
             var idx = 0;
             const tmpNormal = Tmp.Vector3[0];
-            const rotMatrix = Tmp.Matrix[0];
-            const invertedRotMatrix = Tmp.Matrix[1];
+            const quaternion = Tmp.Quaternion[0];
+            const invertedRotMatrix = Tmp.Matrix[0];
             for (var p = 0; p < this.particles.length; p++) {
                 const particle = this.particles[p];
                 const shape = particle._model._shape;
-                particle.getRotationMatrix(rotMatrix);
-                rotMatrix.invertToRef(invertedRotMatrix);
+
+                // computing the inverse of the rotation matrix from the quaternion
+                // is equivalent to computing the matrix of the inverse quaternion, i.e of the conjugate quaternion
+                if (particle.rotationQuaternion) {
+                    particle.rotationQuaternion.conjugateToRef(quaternion);
+                }
+                else {
+                    const rotation = particle.rotation;
+                    Quaternion.RotationYawPitchRollToRef(rotation.y, rotation.x, rotation.z, quaternion);
+                    quaternion.conjugateInPlace();
+                }
+                quaternion.toRotationMatrix(invertedRotMatrix);
 
                 for (var pt = 0; pt < shape.length; pt++) {
                     idx = index + pt * 3;