Selaa lähdekoodia

Merge pull request #6277 from julien-moreau/master

 Added support of bones velocities while computing velocity map in geometry render buffer
David Catuhe 6 vuotta sitten
vanhempi
commit
96753fcdd2

+ 28 - 0
src/PostProcesses/motionBlurPostProcess.ts

@@ -7,6 +7,7 @@ import { PostProcess, PostProcessOptions } from "./postProcess";
 import { Constants } from "../Engines/constants";
 import { GeometryBufferRenderer } from "../Rendering/geometryBufferRenderer";
 import { Scene } from "../scene";
+import { AbstractMesh } from "../Meshes/abstractMesh";
 
 import "../Animations/animatable";
 import '../Rendering/geometryBufferRendererSceneComponent';
@@ -93,6 +94,31 @@ export class MotionBlurPostProcess extends PostProcess {
     }
 
     /**
+     * Excludes the given skinned mesh from computing bones velocities.
+     * Computing bones velocities can have a cost and that cost. The cost can be saved by calling this function and by passing the skinned mesh reference to ignore.
+     * @param skinnedMesh The mesh containing the skeleton to ignore when computing the velocity map.
+     */
+    public excludeSkinnedMesh(skinnedMesh: AbstractMesh): void {
+        if (this._geometryBufferRenderer && skinnedMesh.skeleton) {
+            this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity.push(skinnedMesh);
+        }
+    }
+
+    /**
+     * Removes the given skinned mesh from the excluded meshes to integrate bones velocities while rendering the velocity map.
+     * @param skinnedMesh The mesh containing the skeleton that has been ignored previously.
+     * @see excludeSkinnedMesh to exclude a skinned mesh from bones velocity computation.
+     */
+    public removeExcludedSkinnedMesh(skinnedMesh: AbstractMesh): void {
+        if (this._geometryBufferRenderer && skinnedMesh.skeleton) {
+            const index = this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity.indexOf(skinnedMesh);
+            if (index !== -1) {
+                this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity.splice(index, 1);
+            }
+        }
+    }
+
+    /**
      * Disposes the post process.
      * @param camera The camera to dispose the post process on.
      */
@@ -100,6 +126,8 @@ export class MotionBlurPostProcess extends PostProcess {
         if (this._geometryBufferRenderer) {
             // Clear previous transformation matrices dictionary used to compute objects velocities
             this._geometryBufferRenderer._previousTransformationMatrices = {};
+            this._geometryBufferRenderer._previousBonesTransformationMatrices = {};
+            this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity = [];
         }
 
         super.dispose(camera);

+ 50 - 6
src/Rendering/geometryBufferRenderer.ts

@@ -9,11 +9,17 @@ import { MultiRenderTarget } from "../Materials/Textures/multiRenderTarget";
 import { Effect } from "../Materials/effect";
 import { Material } from "../Materials/material";
 import { Scene } from "../scene";
+import { AbstractMesh } from "../Meshes/abstractMesh";
 
 import "../Shaders/geometry.fragment";
 import "../Shaders/geometry.vertex";
 import { _DevTools } from '../Misc/devTools';
 
+interface ISavedTransformationMatrix {
+    world: Matrix;
+    viewProjection: Matrix;
+}
+
 /**
  * This renderer is helpfull to fill one of the render target with a geometry buffer.
  */
@@ -34,7 +40,18 @@ export class GeometryBufferRenderer {
      * in order to compute objects velocities when enableVelocity is set to "true"
      * @hidden
      */
-    public _previousTransformationMatrices: { [index: number]: Matrix } = {};
+    public _previousTransformationMatrices: { [index: number]: ISavedTransformationMatrix } = {};
+    /**
+     * Dictionary used to store the previous bones transformation matrices of each rendered mesh
+     * in order to compute objects velocities when enableVelocity is set to "true"
+     * @hidden
+     */
+    public _previousBonesTransformationMatrices: { [index: number]: Float32Array } = {};
+    /**
+     * Array used to store the ignored skinned meshes while computing velocity map (typically used by the motion blur post-process).
+     * Avoids computing bones velocities and computes only mesh's velocity itself (position, rotation, scaling).
+     */
+    public excludedSkinnedMeshesFromVelocity: AbstractMesh[] = [];
 
     private _scene: Scene;
     private _multiRenderTarget: MultiRenderTarget;
@@ -189,6 +206,9 @@ export class GeometryBufferRenderer {
         if (this._enableVelocity) {
             defines.push("#define VELOCITY");
             defines.push("#define VELOCITY_INDEX " + this._velocityIndex);
+            if (this.excludedSkinnedMeshesFromVelocity.indexOf(mesh) === -1) {
+                defines.push("#define BONES_VELOCITY_ENABLED");
+            }
         }
 
         // Bones
@@ -223,7 +243,7 @@ export class GeometryBufferRenderer {
             this._cachedDefines = join;
             this._effect = this._scene.getEngine().createEffect("geometry",
                 attribs,
-                ["world", "mBones", "viewProjection", "diffuseMatrix", "view", "previousWorldViewProjection", "currentWorldViewProjection"],
+                ["world", "mBones", "viewProjection", "diffuseMatrix", "view", "previousWorld", "previousViewProjection", "mPreviousBones"],
                 ["diffuseSampler"], join,
                 undefined, undefined, undefined,
                 { buffersCount: this._enablePosition ? 3 : 2 });
@@ -305,7 +325,15 @@ export class GeometryBufferRenderer {
 
             // Velocity
             if (this._enableVelocity && !this._previousTransformationMatrices[mesh.uniqueId]) {
-                this._previousTransformationMatrices[mesh.uniqueId] = Matrix.Identity();
+                this._previousTransformationMatrices[mesh.uniqueId] = {
+                    world: Matrix.Identity(),
+                    viewProjection: scene.getTransformMatrix()
+                };
+
+                if (mesh.skeleton) {
+                    const bonesTransformations = mesh.skeleton.getTransformMatrices(mesh);
+                    this._previousBonesTransformationMatrices[mesh.uniqueId] = this._copyBonesTransformationMatrices(bonesTransformations, new Float32Array(bonesTransformations.length));
+                }
             }
 
             // Culling
@@ -340,12 +368,15 @@ export class GeometryBufferRenderer {
                 // Bones
                 if (mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
                     this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
+                    if (this._enableVelocity) {
+                        this._effect.setMatrices("mPreviousBones", this._previousBonesTransformationMatrices[mesh.uniqueId]);
+                    }
                 }
 
                 // Velocity
                 if (this._enableVelocity) {
-                    this._effect.setMatrix("currentWorldViewProjection", mesh.getWorldMatrix().multiply(this._scene.getTransformMatrix()));
-                    this._effect.setMatrix("previousWorldViewProjection", this._previousTransformationMatrices[mesh.uniqueId]);
+                    this._effect.setMatrix("previousWorld", this._previousTransformationMatrices[mesh.uniqueId].world);
+                    this._effect.setMatrix("previousViewProjection", this._previousTransformationMatrices[mesh.uniqueId].viewProjection);
                 }
 
                 // Draw
@@ -355,7 +386,11 @@ export class GeometryBufferRenderer {
 
             // Velocity
             if (this._enableVelocity) {
-                this._previousTransformationMatrices[mesh.uniqueId] = mesh.getWorldMatrix().multiply(this._scene.getTransformMatrix());
+                this._previousTransformationMatrices[mesh.uniqueId].world = mesh.getWorldMatrix().clone();
+                this._previousTransformationMatrices[mesh.uniqueId].viewProjection = this._scene.getTransformMatrix().clone();
+                if (mesh.skeleton) {
+                    this._copyBonesTransformationMatrices(mesh.skeleton.getTransformMatrices(mesh), this._previousBonesTransformationMatrices[mesh.uniqueId]);
+                }
             }
         };
 
@@ -379,4 +414,13 @@ export class GeometryBufferRenderer {
             }
         };
     }
+
+    // Copies the bones transformation matrices into the target array and returns the target's reference
+    private _copyBonesTransformationMatrices(source: Float32Array, target: Float32Array): Float32Array {
+        for (let i = 0; i < source.length; i++) {
+            target[i] = source[i];
+        }
+
+        return target;
+    }
 }

+ 2 - 3
src/Shaders/geometry.fragment.fx

@@ -41,9 +41,8 @@ void main() {
     vec2 a = (vCurrentPosition.xy / vCurrentPosition.w) * 0.5 + 0.5;
 	vec2 b = (vPreviousPosition.xy / vPreviousPosition.w) * 0.5 + 0.5;
 
-    vec2 velocity = (a - b) * 0.5 + 0.5;
-	velocity *= 0.5 + 0.5;
-	velocity = vec2(pow(velocity.x, 3.0), pow(velocity.y, 3.0));
+    vec2 velocity = abs(a - b);
+    velocity = vec2(pow(velocity.x, 1.0 / 3.0), pow(velocity.y, 1.0 / 3.0)) * sign(a - b) * 0.5 + 0.5;
 
     gl_FragData[VELOCITY_INDEX] = vec4(velocity, 0.0, 1.0);
     #endif

+ 46 - 5
src/Shaders/geometry.vertex.fx

@@ -30,8 +30,14 @@ varying vec3 vPosition;
 #endif
 
 #ifdef VELOCITY
-uniform mat4 previousWorldViewProjection;
-uniform mat4 currentWorldViewProjection;
+uniform mat4 previousWorld;
+uniform mat4 previousViewProjection;
+#ifdef BONES_VELOCITY_ENABLED
+#if NUM_BONE_INFLUENCERS > 0
+uniform mat4 mPreviousBones[BonesPerMesh];
+#endif
+#endif
+
 varying vec4 vCurrentPosition;
 varying vec4 vPreviousPosition;
 #endif
@@ -40,10 +46,10 @@ void main(void)
 {
 #include<instancesVertex>
 
-	#ifdef VELOCITY
+	#if defined(VELOCITY) && !defined(BONES_VELOCITY_ENABLED)
 	// Compute velocity before bones computation
-	vCurrentPosition = currentWorldViewProjection * vec4(position, 1.0);
-	vPreviousPosition = previousWorldViewProjection * vec4(position, 1.0);
+	vCurrentPosition = viewProjection * finalWorld * vec4(position, 1.0);	
+	vPreviousPosition = previousViewProjection * previousWorld * vec4(position, 1.0);
 	#endif
 
 #include<bonesVertex>
@@ -52,6 +58,41 @@ void main(void)
 	vNormalV = normalize(vec3((view * finalWorld) * vec4(normal, 0.0)));
 	vViewPos = view * pos;
 
+	#if defined(VELOCITY) && defined(BONES_VELOCITY_ENABLED)
+		vCurrentPosition = viewProjection * finalWorld * vec4(position, 1.0);
+
+		#if NUM_BONE_INFLUENCERS > 0
+			mat4 previousInfluence;
+			previousInfluence = mPreviousBones[int(matricesIndices[0])] * matricesWeights[0];
+			#if NUM_BONE_INFLUENCERS > 1
+				previousInfluence += mPreviousBones[int(matricesIndices[1])] * matricesWeights[1];
+			#endif	
+			#if NUM_BONE_INFLUENCERS > 2
+				previousInfluence += mPreviousBones[int(matricesIndices[2])] * matricesWeights[2];
+			#endif	
+			#if NUM_BONE_INFLUENCERS > 3
+				previousInfluence += mPreviousBones[int(matricesIndices[3])] * matricesWeights[3];
+			#endif	
+
+			#if NUM_BONE_INFLUENCERS > 4
+				previousInfluence += mPreviousBones[int(matricesIndicesExtra[0])] * matricesWeightsExtra[0];
+			#endif	
+			#if NUM_BONE_INFLUENCERS > 5
+				previousInfluence += mPreviousBones[int(matricesIndicesExtra[1])] * matricesWeightsExtra[1];
+			#endif	
+			#if NUM_BONE_INFLUENCERS > 6
+				previousInfluence += mPreviousBones[int(matricesIndicesExtra[2])] * matricesWeightsExtra[2];
+			#endif	
+			#if NUM_BONE_INFLUENCERS > 7
+				previousInfluence += mPreviousBones[int(matricesIndicesExtra[3])] * matricesWeightsExtra[3];
+			#endif
+
+			vPreviousPosition = previousViewProjection * previousWorld * previousInfluence * vec4(position, 1.0);
+		#else
+			vPreviousPosition = previousViewProjection * previousWorld * vec4(position, 1.0);
+		#endif
+	#endif
+
 	#ifdef POSITION
 	vPosition = pos.xyz / pos.w;
 	#endif

+ 3 - 2
src/Shaders/motionBlur.fragment.fx

@@ -12,9 +12,9 @@ void main(void)
 {
     #ifdef GEOMETRY_SUPPORTED
     vec2 texelSize = 1.0 / screenSize;
-    vec2 velocityColor = texture2D(velocitySampler, vUV).rg;
+    vec2 velocityColor = texture2D(velocitySampler, vUV).rg * 2.0 - 1.0;
 	
-    vec2 velocity = vec2(pow(velocityColor.r, 1.0 / 3.0), pow(velocityColor.g, 1.0 / 3.0)) * 2.0 - 1.0;
+    vec2 velocity = vec2(pow(velocityColor.r, 3.0), pow(velocityColor.g, 3.0));
 	velocity *= motionScale * motionStrength;
 
     float speed = length(velocity / texelSize);
@@ -35,6 +35,7 @@ void main(void)
     }
 
 	gl_FragColor = result / float(samplesCount);
+    gl_FragColor.a = 1.0;
     #else
     gl_FragColor = texture2D(textureSampler, vUV);
     #endif