瀏覽代碼

Merge pull request #8536 from Popov72/matrix-64-bits

Add option to use 64 bits for matrix computations
mergify[bot] 5 年之前
父節點
當前提交
e2eba7e437

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

@@ -30,6 +30,7 @@
 - Added a Simple and advanced timer, based on observables ([RaananW](https://github.com/RaananW))
 - Don't log a message in `CustomProceduralTexture` if the `texturePath` is not a JSON path ([Popov72](https://github.com/Popov72))
 - Added an alternate option to the mesh edge renderer to generate edges faster / more accurately for unusual geometries (like the ones generated by CSG) ([Popov72](https://github.com/Popov72))
+- Added an option when creating the engine to switch matrix computation to 64 bits ([Popov72](https://github.com/Popov72))
 
 ### Engine
 

+ 1 - 1
serializers/src/glTF/2.0/glTFExporter.ts

@@ -1695,7 +1695,7 @@ export class _Exporter {
             skinMap[skeleton.uniqueId] = this._skins.length - 1;
 
             inverseBindMatrices.forEach((mat) => {
-                mat.m.forEach((cell) => {
+                mat.m.forEach((cell: number) => {
                     binaryWriter.setFloat32(cell);
                 });
             });

+ 1 - 0
src/Engines/index.ts

@@ -11,3 +11,4 @@ export * from "./WebGL/webGLPipelineContext";
 export * from "./WebGL/webGL2ShaderProcessors";
 export * from "./nativeEngine";
 export * from "./Processors/shaderCodeInliner";
+export * from "./performanceConfigurator";

+ 8 - 0
src/Engines/nullEngine.ts

@@ -10,6 +10,7 @@ import { IPipelineContext } from './IPipelineContext';
 import { DataBuffer } from '../Meshes/dataBuffer';
 import { IColor4Like, IViewportLike } from '../Maths/math.like';
 import { ISceneLike } from './thinEngine';
+import { PerformanceConfigurator } from './performanceConfigurator';
 
 declare const global: any;
 
@@ -42,6 +43,11 @@ export class NullEngineOptions {
      * @see https://doc.babylonjs.com/babylon101/animations#deterministic-lockstep
      */
     public lockstepMaxSteps = 4;
+
+    /**
+     * Make the matrix computations to be performed in 64 bits instead of 32 bits. False by default
+     */
+    useHighPrecisionMatrix?: boolean;
 }
 
 /**
@@ -94,6 +100,8 @@ export class NullEngine extends Engine {
 
         this._options = options;
 
+        PerformanceConfigurator.SetMatrixPrecision(!!options.useHighPrecisionMatrix);
+
         // Init caps
         // We consider we are on a webgl1 capable device
 

+ 35 - 0
src/Engines/performanceConfigurator.ts

@@ -0,0 +1,35 @@
+/** @hidden */
+export class PerformanceConfigurator {
+    /** @hidden */
+    public static MatrixUse64Bits = false;
+    /** @hidden */
+    public static MatrixTrackPrecisionChange = true;
+    /** @hidden */
+    public static MatrixCurrentType: any = Float32Array;
+    /** @hidden */
+    public static MatrixTrackedMatrices: Array<any> | null = [];
+
+    /** @hidden */
+    public static SetMatrixPrecision(use64bits: boolean) {
+        PerformanceConfigurator.MatrixTrackPrecisionChange = false;
+
+        if (use64bits && !PerformanceConfigurator.MatrixUse64Bits) {
+            if (PerformanceConfigurator.MatrixTrackedMatrices) {
+                for (let m = 0; m < PerformanceConfigurator.MatrixTrackedMatrices.length; ++m) {
+                    const matrix = PerformanceConfigurator.MatrixTrackedMatrices[m];
+                    const values = matrix._m;
+
+                    matrix._m = new Array(16);
+
+                    for (let i = 0; i < 16; ++i) {
+                        matrix._m[i] = values[i];
+                    }
+                }
+            }
+        }
+
+        PerformanceConfigurator.MatrixUse64Bits = use64bits;
+        PerformanceConfigurator.MatrixCurrentType = PerformanceConfigurator.MatrixUse64Bits ? Array : Float32Array;
+        PerformanceConfigurator.MatrixTrackedMatrices = null; // reclaim some memory, as we don't need _TrackedMatrices anymore
+    }
+}

+ 8 - 0
src/Engines/thinEngine.ts

@@ -28,6 +28,7 @@ import { IOfflineProvider } from '../Offline/IOfflineProvider';
 import { IEffectFallbacks } from '../Materials/iEffectFallbacks';
 import { IWebRequest } from '../Misc/interfaces/iWebRequest';
 import { CanvasGenerator } from '../Misc/canvasGenerator';
+import { PerformanceConfigurator } from './performanceConfigurator';
 
 declare type WebRequest = import("../Misc/webRequest").WebRequest;
 declare type LoadFileError = import("../Misc/fileTools").LoadFileError;
@@ -110,6 +111,11 @@ export interface EngineOptions extends WebGLContextAttributes {
      * Make the canvas XR Compatible for XR sessions
      */
     xrCompatible?: boolean;
+
+    /**
+     * Make the matrix computations to be performed in 64 bits instead of 32 bits. False by default
+     */
+    useHighPrecisionMatrix?: boolean;
 }
 
 /**
@@ -484,6 +490,8 @@ export class ThinEngine {
 
         options = options || {};
 
+        PerformanceConfigurator.SetMatrixPrecision(!!options.useHighPrecisionMatrix);
+
         if ((canvasOrContext as any).getContext) {
             canvas = <HTMLCanvasElement>canvasOrContext;
             this._renderingCanvas = canvas;

+ 6 - 6
src/Materials/effect.ts

@@ -1143,13 +1143,13 @@ export class Effect implements IDisposable {
      * @param matrices matrices to be set.
      * @returns this effect.
      */
-    public setMatrices(uniformName: string, matrices: Float32Array): Effect {
+    public setMatrices(uniformName: string, matrices: Float32Array | Array<number>): Effect {
         if (!matrices) {
             return this;
         }
 
         this._valueCache[uniformName] = null;
-        this._engine.setMatrices(this._uniforms[uniformName], matrices);
+        this._engine.setMatrices(this._uniforms[uniformName], matrices as Float32Array); // the cast is ok because it is gl.uniformMatrix4fv() which is called at the end, and this function accepts Float32Array and Array<number>
 
         return this;
     }
@@ -1173,9 +1173,9 @@ export class Effect implements IDisposable {
      * @param matrix matrix to be set.
      * @returns this effect.
      */
-    public setMatrix3x3(uniformName: string, matrix: Float32Array): Effect {
+    public setMatrix3x3(uniformName: string, matrix: Float32Array | Array<number>): Effect {
         this._valueCache[uniformName] = null;
-        this._engine.setMatrix3x3(this._uniforms[uniformName], matrix);
+        this._engine.setMatrix3x3(this._uniforms[uniformName], matrix as Float32Array); // the cast is ok because it is gl.uniformMatrix3fv() which is called at the end, and this function accepts Float32Array and Array<number>
 
         return this;
     }
@@ -1186,9 +1186,9 @@ export class Effect implements IDisposable {
      * @param matrix matrix to be set.
      * @returns this effect.
      */
-    public setMatrix2x2(uniformName: string, matrix: Float32Array): Effect {
+    public setMatrix2x2(uniformName: string, matrix: Float32Array | Array<number>): Effect {
         this._valueCache[uniformName] = null;
-        this._engine.setMatrix2x2(this._uniforms[uniformName], matrix);
+        this._engine.setMatrix2x2(this._uniforms[uniformName], matrix as Float32Array); // the cast is ok because it is gl.uniformMatrix2fv() which is called at the end, and this function accepts Float32Array and Array<number>
 
         return this;
     }

+ 5 - 5
src/Materials/shaderMaterial.ts

@@ -82,9 +82,9 @@ export class ShaderMaterial extends Material {
     private _vectors3: { [name: string]: Vector3 } = {};
     private _vectors4: { [name: string]: Vector4 } = {};
     private _matrices: { [name: string]: Matrix } = {};
-    private _matrixArrays: { [name: string]: Float32Array } = {};
-    private _matrices3x3: { [name: string]: Float32Array } = {};
-    private _matrices2x2: { [name: string]: Float32Array } = {};
+    private _matrixArrays: { [name: string]: Float32Array | Array<number> } = {};
+    private _matrices3x3: { [name: string]: Float32Array | Array<number> } = {};
+    private _matrices2x2: { [name: string]: Float32Array | Array<number> } = {};
     private _vectors2Arrays: { [name: string]: number[] } = {};
     private _vectors3Arrays: { [name: string]: number[] } = {};
     private _vectors4Arrays: { [name: string]: number[] } = {};
@@ -393,7 +393,7 @@ export class ShaderMaterial extends Material {
      * @param value Define the value to give to the uniform
      * @return the material itself allowing "fluent" like uniform updates
      */
-    public setMatrix3x3(name: string, value: Float32Array): ShaderMaterial {
+    public setMatrix3x3(name: string, value: Float32Array | Array<number>): ShaderMaterial {
         this._checkUniform(name);
         this._matrices3x3[name] = value;
 
@@ -406,7 +406,7 @@ export class ShaderMaterial extends Material {
      * @param value Define the value to give to the uniform
      * @return the material itself allowing "fluent" like uniform updates
      */
-    public setMatrix2x2(name: string, value: Float32Array): ShaderMaterial {
+    public setMatrix2x2(name: string, value: Float32Array | Array<number>): ShaderMaterial {
         this._checkUniform(name);
         this._matrices2x2[name] = value;
 

+ 1 - 1
src/Maths/math.like.ts

@@ -50,7 +50,7 @@ export interface IVector2Like {
  * @hidden
  */
 export interface IMatrixLike {
-    toArray(): DeepImmutable<Float32Array>;
+    toArray(): DeepImmutable<Float32Array | Array<number>>;
     updateFlag: int;
 }
 

+ 30 - 14
src/Maths/math.vector.ts

@@ -6,6 +6,7 @@ import { ArrayTools } from '../Misc/arrayTools';
 import { IPlaneLike } from './math.like';
 import { _TypeStore } from '../Misc/typeStore';
 import { Plane } from './math.plane';
+import { PerformanceConfigurator } from '../Engines/performanceConfigurator';
 
 /**
  * Class representing a vector containing 2 coordinates
@@ -3552,6 +3553,14 @@ export class Quaternion {
  * Class used to store matrix data (4x4)
  */
 export class Matrix {
+
+    /**
+     * Gets the precision of matrix computations
+     */
+    public static get Use64Bits(): boolean {
+        return PerformanceConfigurator.MatrixUse64Bits;
+    }
+
     private static _updateFlagSeed = 0;
     private static _identityReadOnly = Matrix.Identity() as DeepImmutable<Matrix>;
 
@@ -3566,12 +3575,12 @@ export class Matrix {
      */
     public updateFlag: number = -1;
 
-    private readonly _m: Float32Array = new Float32Array(16);
+    private readonly _m: Float32Array | Array<number>;
 
     /**
      * Gets the internal data of the matrix
      */
-    public get m(): DeepImmutable<Float32Array> { return this._m; }
+    public get m(): DeepImmutable<Float32Array | Array<number>> { return this._m; }
 
     /** @hidden */
     public _markAsUpdated() {
@@ -3595,6 +3604,11 @@ export class Matrix {
      * Creates an empty matrix (filled with zeros)
      */
     public constructor() {
+        if (PerformanceConfigurator.MatrixTrackPrecisionChange) {
+            PerformanceConfigurator.MatrixTrackedMatrices!.push(this);
+        }
+
+        this._m = new PerformanceConfigurator.MatrixCurrentType(16);
         this._updateIdentityStatus(false);
     }
 
@@ -3681,17 +3695,17 @@ export class Matrix {
     // Methods
 
     /**
-     * Returns the matrix as a Float32Array
+     * Returns the matrix as a Float32Array or Array<number>
      * @returns the matrix underlying array
      */
-    public toArray(): DeepImmutable<Float32Array> {
+    public toArray(): DeepImmutable<Float32Array | Array<number>> {
         return this._m;
     }
     /**
-     * Returns the matrix as a Float32Array
+     * Returns the matrix as a Float32Array or Array<number>
     * @returns the matrix underlying array.
     */
-    public asArray(): DeepImmutable<Float32Array> {
+    public asArray(): DeepImmutable<Float32Array | Array<number>> {
         return this._m;
     }
 
@@ -3969,7 +3983,7 @@ export class Matrix {
      * @param offset defines the offset in the target array where to start storing values
      * @returns the current matrix
      */
-    public copyToArray(array: Float32Array, offset: number = 0): Matrix {
+    public copyToArray(array: Float32Array | Array<number>, offset: number = 0): Matrix {
         let source = this._m;
         array[offset] = source[0];
         array[offset + 1] = source[1];
@@ -4019,7 +4033,7 @@ export class Matrix {
      * @param offset defines the offset in the target array where to start storing values
      * @returns the current matrix
      */
-    public multiplyToArray(other: DeepImmutable<Matrix>, result: Float32Array, offset: number): Matrix {
+    public multiplyToArray(other: DeepImmutable<Matrix>, result: Float32Array | Array<number>, offset: number): Matrix {
         const m = this._m;
         const otherM = other.m;
         var tm0 = m[0], tm1 = m[1], tm2 = m[2], tm3 = m[3];
@@ -4382,7 +4396,7 @@ export class Matrix {
      * @param scale defines the scaling factor
      * @param result defines the target matrix
      */
-    public static FromFloat32ArrayToRefScaled(array: DeepImmutable<Float32Array>, offset: number, scale: number, result: Matrix) {
+    public static FromFloat32ArrayToRefScaled(array: DeepImmutable<Float32Array | Array<number>>, offset: number, scale: number, result: Matrix) {
         for (var index = 0; index < 16; index++) {
             result._m[index] = array[index + offset] * scale;
         }
@@ -5378,22 +5392,24 @@ export class Matrix {
      * @param matrix defines the matrix to use
      * @returns a new Float32Array array with 4 elements : the 2x2 matrix extracted from the given matrix
      */
-    public static GetAsMatrix2x2(matrix: DeepImmutable<Matrix>): Float32Array {
+    public static GetAsMatrix2x2(matrix: DeepImmutable<Matrix>): Float32Array | Array<number> {
         const m = matrix.m;
-        return new Float32Array([m[0], m[1], m[4], m[5]]);
+        const arr = [m[0], m[1], m[4], m[5]];
+        return PerformanceConfigurator.MatrixUse64Bits ? arr : new Float32Array(arr);
     }
     /**
      * Extracts a 3x3 matrix from a given matrix and store the result in a Float32Array
      * @param matrix defines the matrix to use
      * @returns a new Float32Array array with 9 elements : the 3x3 matrix extracted from the given matrix
      */
-    public static GetAsMatrix3x3(matrix: DeepImmutable<Matrix>): Float32Array {
+    public static GetAsMatrix3x3(matrix: DeepImmutable<Matrix>): Float32Array | Array<number> {
         const m = matrix.m;
-        return new Float32Array([
+        const arr = [
             m[0], m[1], m[2],
             m[4], m[5], m[6],
             m[8], m[9], m[10]
-        ]);
+        ];
+        return PerformanceConfigurator.MatrixUse64Bits ? arr : new Float32Array(arr);
     }
 
     /**