Ver código fonte

Texture preparation

David Catuhe 4 anos atrás
pai
commit
f043187cf9
2 arquivos alterados com 111 adições e 0 exclusões
  1. 4 0
      src/Meshes/mesh.ts
  2. 107 0
      src/Morph/morphTargetManager.ts

+ 4 - 0
src/Meshes/mesh.ts

@@ -3298,6 +3298,10 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
                 return;
             }
 
+            if (morphTargetManager.isUsingTextureForTargets) {
+                return;
+            }
+
             for (var index = 0; index < morphTargetManager.numInfluencers; index++) {
                 var morphTarget = morphTargetManager.getActiveTarget(index);
 

+ 107 - 0
src/Morph/morphTargetManager.ts

@@ -6,6 +6,8 @@ import { Scene } from "../scene";
 import { EngineStore } from "../Engines/engineStore";
 import { Mesh } from "../Meshes/mesh";
 import { MorphTarget } from "./morphTarget";
+import { RawTexture } from "../Materials/Textures/rawTexture";
+import { Constants } from "../Engines/constants";
 /**
  * This class is used to deform meshes using morphing between different targets
  * @see https://doc.babylonjs.com/how_to/how_to_use_morphtargets
@@ -23,6 +25,10 @@ export class MorphTargetManager {
     private _vertexCount = 0;
     private _uniqueId = 0;
     private _tempInfluences = new Array<number>();
+    private _canUseTextureForTargets = false;
+
+    /** @hidden */
+    public _targetStoreTextures: Array<RawTexture> = [];
 
     /**
      * Gets or sets a boolean indicating if normals must be morphed
@@ -54,6 +60,9 @@ export class MorphTargetManager {
             this._scene.morphTargetManagers.push(this);
 
             this._uniqueId = this._scene.getUniqueId();
+            
+            const engineCaps = this._scene.getEngine().getCaps();
+            this._canUseTextureForTargets = engineCaps.textureFloat && engineCaps.maxVertexTextureImageUnits > 0;
         }
     }
 
@@ -113,6 +122,26 @@ export class MorphTargetManager {
         return this._influences;
     }
 
+    private _useTextureToStoreTargets = true;
+    /**
+     * Gets or sets a boolean indicating that targets should be stored as a texture instead of using vertex attributes (default is true).
+     * Please note that this option is not available if the hardware does not support it
+     */
+    public get useTextureToStoreTargets(): boolean {
+        return this._useTextureToStoreTargets;
+    }
+
+    public set useTextureToStoreTargets(value: boolean) {
+        this._useTextureToStoreTargets = value;
+    }
+
+    /**
+     * Gets a boolean indicating that the targets are stored into a texture (instead of as attributes)
+     */
+    public get isUsingTextureForTargets() {
+        return this.useTextureToStoreTargets && this._canUseTextureForTargets;
+    }
+
     /**
      * Gets the active target at specified index. An active target is a target with an influence > 0
      * @param index defines the index to check
@@ -248,6 +277,84 @@ export class MorphTargetManager {
         if (!this._scene) {
             return;
         }
+
+        if (this.isUsingTextureForTargets) {
+            if (!this._vertexCount) {
+                return;
+            }
+
+            let textureWidth = this._vertexCount * 3;
+
+            if (this._supportsNormals) {
+                textureWidth *= 2;
+            }
+
+            if (this._supportsTangents) {
+                textureWidth += this._vertexCount * 4;
+            }
+
+            if (this._supportsUVs) {
+                textureWidth += this._vertexCount * 2;
+            }
+
+            for (var index = 0; index < this._targets.length; index++) {
+                let target = this._targets[index];
+
+                if (!this._targetStoreTextures[index] || this._targetStoreTextures[index].getSize().width !== textureWidth) {
+                    if (this._targetStoreTextures[index]) {
+                        this._targetStoreTextures[index].dispose();
+                    }
+
+                    let data = new Float32Array(textureWidth);
+
+                    let offset = 0;
+                    const positions = target.getPositions();
+                    const normals = target.getNormals();
+                    const uvs = target.getUVs();
+                    const tangents = target.getTangents();
+
+                    if (!positions) {
+                        Logger.Error("Invalid morph target. Target must have positions.");
+                        return;
+                    }
+
+                    for (var vertex = 0; vertex < this._vertexCount; vertex++) {
+                        data[offset] = positions[vertex * 3];
+                        data[offset + 1] = positions[vertex * 3 + 1];
+                        data[offset + 2] = positions[vertex * 3 + 2];
+
+                        offset += 3;
+
+                        if (normals) {
+                            data[offset] = normals[vertex * 3];
+                            data[offset + 1] = normals[vertex * 3 + 1];
+                            data[offset + 2] = normals[vertex * 3 + 2];
+                            offset += 3;
+                        }
+
+                        if (uvs) {
+                            data[offset] = uvs[vertex * 2];
+                            data[offset + 1] = uvs[vertex * 2 + 1];
+                            offset += 2;
+                        }
+
+                        if (tangents) {
+                            data[offset] = tangents[vertex * 4];
+                            data[offset + 1] = tangents[vertex * 4 + 1];
+                            data[offset + 2] = tangents[vertex * 4 + 2];
+                            data[offset + 3] = tangents[vertex * 4 + 3];
+                            offset += 4;
+                        }
+                    }
+
+                    this._targetStoreTextures[index]= RawTexture.CreateRGBATexture(data, textureWidth, 1, 
+                        this._scene, false, false, Constants.TEXTURE_NEAREST_SAMPLINGMODE, Constants.TEXTURETYPE_FLOAT);
+                }
+            }
+
+            return;
+        }
+
         // Flag meshes as dirty to resync with the active targets
         for (var mesh of this._scene.meshes) {
             if ((<any>mesh).morphTargetManager === this) {