Переглянути джерело

MeshVelocityMaterial: render a scene's velocity field to a buffer (useful for motion blur, TRAA post effects) (#23784)

* beginning work on TRAA pass.

* more work on TRAA.

* remove TRAA for now.

* velocity material is working.

* update default channel in example.

* Update MeshVelocityMaterial.js

* Update ShaderLib.js

* add mention of velocity in channel example description

* clean up MeshVelocityMaterial class.

* Update MeshVelocityMaterial.js

* move velocity shader out of core and into examples.

* channel example working again.

* make Object3D.matrixWorldPrevious optional.

* cleanup of PR.

* Update webgl_materials_channels.html

Co-authored-by: Michael Herzog <[email protected]>
Ben Houston 2 роки тому
батько
коміт
20c13f1e24

+ 128 - 0
examples/jsm/shaders/VelocityShader.js

@@ -0,0 +1,128 @@
+import {
+	UniformsLib,
+	UniformsUtils,
+	Matrix4
+} from 'three';
+
+/**
+ * Mesh Velocity Shader @bhouston
+ */
+
+const VelocityShader = {
+
+	uniforms: UniformsUtils.merge( [
+		UniformsLib.common,
+		UniformsLib.displacementmap,
+		{
+			modelMatrixPrev: { value: new Matrix4() },
+			currentProjectionViewMatrix: { value: new Matrix4() },
+			previousProjectionViewMatrix: { value: new Matrix4() }
+		}
+	] ),
+
+	vertexShader: /* glsl */`
+#define NORMAL
+
+#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )
+
+	varying vec3 vViewPosition;
+
+#endif
+
+#include <common>
+#include <packing>
+#include <uv_pars_vertex>
+#include <displacementmap_pars_vertex>
+#include <normal_pars_vertex>
+#include <morphtarget_pars_vertex>
+#include <skinning_pars_vertex>
+#include <logdepthbuf_pars_vertex>
+#include <clipping_planes_pars_vertex>
+
+uniform mat4 previousProjectionViewMatrix;
+uniform mat4 currentProjectionViewMatrix;
+
+uniform mat4 modelMatrixPrev;
+
+varying vec4 clipPositionCurrent;
+varying vec4 clipPositionPrevious;
+
+void main() {
+
+
+	#include <uv_vertex>
+
+	#include <beginnormal_vertex>
+	#include <morphnormal_vertex>
+	#include <skinbase_vertex>
+	#include <skinnormal_vertex>
+	#include <defaultnormal_vertex>
+	#include <normal_vertex>
+
+	#include <begin_vertex>
+	#include <morphtarget_vertex>
+	#include <displacementmap_vertex>
+	#include <morphtarget_vertex>
+	#include <skinning_vertex>
+
+#ifdef USE_SKINNING
+
+	vec4 mvPosition = modelViewMatrix * skinned;
+	clipPositionCurrent  = currentProjectionViewMatrix * modelMatrix * skinned;
+	clipPositionPrevious = previousProjectionViewMatrix * modelMatrixPrev * skinned;
+
+#else
+
+	vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );
+	clipPositionCurrent  = currentProjectionViewMatrix * modelMatrix * vec4( transformed, 1.0 );
+	clipPositionPrevious = previousProjectionViewMatrix * modelMatrixPrev * vec4( transformed, 1.0 );
+
+#endif
+
+	gl_Position = projectionMatrix * mvPosition;
+
+	#include <logdepthbuf_vertex>
+	#include <clipping_planes_vertex>
+}
+`,
+	fragmentShader: /* glsl */`
+#define NORMAL
+
+uniform float opacity;
+
+#include <packing>
+#include <uv_pars_fragment>
+#include <map_pars_fragment>
+#include <alphamap_pars_fragment>
+#include <alphatest_pars_fragment>
+#include <logdepthbuf_pars_fragment>
+#include <clipping_planes_pars_fragment>
+
+varying vec4 clipPositionCurrent;
+varying vec4 clipPositionPrevious;
+
+void main() {
+
+	vec4 diffuseColor = vec4( 1.0 );
+	diffuseColor.a = opacity;
+
+	#include <map_fragment>
+	#include <alphamap_fragment>
+	#include <alphatest_fragment>
+
+	vec2 ndcPositionCurrent  = clipPositionCurrent.xy/clipPositionCurrent.w;
+	vec2 ndcPositionPrevious = clipPositionPrevious.xy/clipPositionPrevious.w;
+	vec2 vel = ( ndcPositionCurrent - ndcPositionPrevious ) * 0.5;
+	vel = vel * 0.5 + 0.5;
+	vec2 v1 = packDepthToRG(vel.x);
+	vec2 v2 = packDepthToRG(vel.y);
+	gl_FragColor = vec4(v1.x, v1.y, v2.x, v2.y);
+
+	#include <logdepthbuf_fragment>
+
+}
+
+`
+};
+
+export { VelocityShader };

+ 39 - 3
examples/webgl_materials_channels.html

@@ -9,7 +9,7 @@
 	<body>
 
 		<div id="info">
-			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - <span id="description">Normal, Depth, DepthRGBA, DepthRGBAUnpacked, Materials</span><br/>
+			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - <span id="description">Normal, Velocity, Depth, DepthRGBA, DepthRGBAUnpacked, Materials</span><br/>
 			by <a href="https://Clara.io">Ben Houston</a>. ninja head from <a href="https://gpuopen.com/archive/gamescgi/amd-gpu-meshmapper/" target="_blank" rel="noopener">AMD GPU MeshMapper</a>
 		</div>
 
@@ -35,6 +35,8 @@
 			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 			import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
 			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+			import { VelocityShader } from 'three/addons/shaders/VelocityShader.js';
+
 
 			let stats;
 
@@ -55,7 +57,7 @@
 			let cameraOrtho, cameraPerspective;
 			let controlsOrtho, controlsPerspective;
 
-			let mesh, materialStandard, materialDepthBasic, materialDepthRGBA, materialNormal;
+			let mesh, materialStandard, materialDepthBasic, materialDepthRGBA, materialNormal, materialVelocity;
 
 			const SCALE = 2.436143; // from original model
 			const BIAS = - 0.428408; // from original model
@@ -68,7 +70,7 @@
 			function initGui() {
 
 				const gui = new GUI();
-				gui.add( params, 'material', [ 'standard', 'normal', 'depthBasic', 'depthRGBA' ] );
+				gui.add( params, 'material', [ 'standard', 'normal', 'velocity', 'depthBasic', 'depthRGBA' ] );
 				gui.add( params, 'camera', [ 'perspective', 'ortho' ] );
 				gui.add( params, 'side', [ 'front', 'back', 'double' ] );
 
@@ -191,6 +193,17 @@
 					side: THREE.DoubleSide
 				} );
 
+				materialVelocity = new THREE.ShaderMaterial( {
+					uniforms: THREE.UniformsUtils.clone( VelocityShader.uniforms ),
+					vertexShader: VelocityShader.vertexShader,
+					fragmentShader: VelocityShader.fragmentShader,
+					side: THREE.DoubleSide
+				} );
+				materialVelocity.uniforms.displacementMap.value = displacementMap;
+				materialVelocity.uniforms.displacementScale.value = SCALE;
+				materialVelocity.uniforms.displacementBias.value = BIAS;
+				materialVelocity.extensions.derivatives = true;
+
 				//
 
 				const loader = new OBJLoader();
@@ -202,6 +215,7 @@
 
 					mesh = new THREE.Mesh( geometry, materialNormal );
 					mesh.scale.multiplyScalar( 25 );
+					mesh.userData.matrixWorldPrevious = new THREE.Matrix4(); // for velocity
 					scene.add( mesh );
 
 				} );
@@ -261,6 +275,7 @@
 						case 'depthBasic': material = materialDepthBasic; break;
 						case 'depthRGBA': material = materialDepthRGBA; break;
 						case 'normal': material = materialNormal; break;
+						case 'velocity': material = materialVelocity; break;
 
 					}
 
@@ -296,8 +311,29 @@
 				controlsPerspective.update();
 				controlsOrtho.update(); // must update both controls for damping to complete
 
+				// remember camera projection changes
+			
+				materialVelocity.uniforms.previousProjectionViewMatrix.value.copy( materialVelocity.uniforms.currentProjectionViewMatrix.value );
+				materialVelocity.uniforms.currentProjectionViewMatrix.value.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
+
+				if ( mesh && mesh.userData.matrixWorldPrevious ) {
+
+					materialVelocity.uniforms.modelMatrixPrev.value.copy( mesh.userData.matrixWorldPrevious );
+			
+				}
+
 				renderer.render( scene, camera );
 
+				scene.traverse( function ( object ) {
+
+					if ( object.isMesh ) {
+
+						object.userData.matrixWorldPrevious.copy( object.matrixWorld );
+			
+					}
+			
+				} );
+
 			}
 
 		</script>

+ 8 - 0
src/renderers/shaders/ShaderChunk/packing.glsl.js

@@ -25,6 +25,14 @@ float unpackRGBAToDepth( const in vec4 v ) {
 	return dot( v, UnpackFactors );
 }
 
+vec2 packDepthToRG( in highp float v ) {
+	return packDepthToRGBA( v ).yx;
+}
+
+float unpackRGToDepth( const in highp vec2 v ) {
+	return unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) );
+}
+
 vec4 pack2HalfToRGBA( vec2 v ) {
 	vec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );
 	return vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );