Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 17 commits into from
Oct 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions examples/jsm/shaders/VelocityShader.js
Original file line number Diff line number Diff line change
@@ -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 };
42 changes: 39 additions & 3 deletions examples/webgl_materials_channels.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand All @@ -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;

Expand All @@ -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
Expand All @@ -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' ] );

Expand Down Expand Up @@ -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();
Expand All @@ -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 );

} );
Expand Down Expand Up @@ -261,6 +275,7 @@
case 'depthBasic': material = materialDepthBasic; break;
case 'depthRGBA': material = materialDepthRGBA; break;
case 'normal': material = materialNormal; break;
case 'velocity': material = materialVelocity; break;

}

Expand Down Expand Up @@ -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>
Expand Down
8 changes: 8 additions & 0 deletions src/renderers/shaders/ShaderChunk/packing.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down