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

Add SSRPass (screen space reflection) #20156

Merged
merged 108 commits into from
Feb 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
65679de
SSRPass init
gonnavis Aug 10, 2020
4b41a96
a
gonnavis Aug 10, 2020
204ea1f
a
gonnavis Aug 10, 2020
614ae8b
a
gonnavis Aug 11, 2020
1bcff91
a
gonnavis Aug 11, 2020
4078f7a
a
gonnavis Aug 11, 2020
78fa272
a
gonnavis Aug 11, 2020
9703d2c
a
gonnavis Aug 11, 2020
88c78e8
a
gonnavis Aug 11, 2020
d103220
a
gonnavis Aug 11, 2020
7468084
use resolution & delete depthRenderMaterial
gonnavis Aug 11, 2020
67aa950
SSRPassPerspective
gonnavis Aug 11, 2020
ebc4ab8
a
gonnavis Aug 11, 2020
d483010
a
gonnavis Aug 11, 2020
16a6725
a
gonnavis Aug 12, 2020
9ed5d1f
a
gonnavis Aug 12, 2020
5786c74
a
gonnavis Aug 12, 2020
cc14b55
a
gonnavis Aug 20, 2020
cadb7f9
a
gonnavis Aug 21, 2020
672f8bd
use pointToLineDistance, maybe ok
gonnavis Aug 21, 2020
65bc8c2
a
gonnavis Aug 21, 2020
5262a8c
almost OK
gonnavis Aug 21, 2020
673b2ff
increase FOV
gonnavis Aug 21, 2020
304b3ad
a
gonnavis Aug 21, 2020
b65ed77
a
gonnavis Aug 22, 2020
963e6b1
a
gonnavis Aug 22, 2020
0d24e9d
A
gonnavis Aug 22, 2020
4e9f48b
A
gonnavis Aug 22, 2020
83f19f8
a
gonnavis Aug 22, 2020
5c77745
clean
gonnavis Aug 22, 2020
f776e9a
clean
gonnavis Aug 22, 2020
acf4d06
screenshot
gonnavis Aug 22, 2020
898c688
a
gonnavis Aug 22, 2020
fbf6f8e
gui
gonnavis Aug 23, 2020
e86f5c9
a
gonnavis Aug 23, 2020
f005e08
new pointToLineDistance function
gonnavis Aug 23, 2020
0bb587e
#define MAX_STEP & onresize replace MAX_STEP
gonnavis Aug 23, 2020
27b2d88
bug fix
gonnavis Aug 23, 2020
7b6a6d0
a
gonnavis Aug 23, 2020
a5b89ee
mobile bug fix
gonnavis Aug 24, 2020
0b3054b
surfDist affected by clipW
gonnavis Aug 25, 2020
600fc0f
performance improvement
gonnavis Aug 26, 2020
91da469
a
gonnavis Aug 26, 2020
58bd9ce
SSRPassSelective
gonnavis Aug 30, 2020
1c5854c
a
gonnavis Aug 30, 2020
135b3f3
selective ok
gonnavis Aug 30, 2020
3ce1c0d
selective ok
gonnavis Aug 30, 2020
6df5b11
a
gonnavis Aug 30, 2020
7de93ca
a
gonnavis Aug 30, 2020
bed4359
use traverse for selective reflect first, try other methods after
gonnavis Aug 30, 2020
518da6a
Configurable encoding
gonnavis Aug 31, 2020
252e87b
support OrthographicCamera
gonnavis Aug 31, 2020
14df55a
traverseVisible
gonnavis Aug 31, 2020
a3261bf
SSRPass_bouncing
gonnavis Sep 2, 2020
80b48b5
a
gonnavis Sep 2, 2020
e026754
a
gonnavis Sep 2, 2020
9fa2a96
performance improvement
gonnavis Sep 7, 2020
3abcc06
a
gonnavis Sep 20, 2020
776917b
No need to calculate clipW separately
gonnavis Sep 24, 2020
e12c022
performance: Use the same skip strategy as viewZ for vZ
gonnavis Sep 27, 2020
e3f0aed
Merge branch 'SSRPass' of https://github.com/gonnavis/three.js into S…
gonnavis Sep 27, 2020
4420625
clean
gonnavis Sep 28, 2020
ff425c9
use lineLineIntersection instead of pointToLineDistance, can get accu…
gonnavis Sep 28, 2020
13e3078
lineLineIntersection & DistanceAttenuation.
gonnavis Sep 28, 2020
8db64cb
Merge branch 'SSRPass' of https://github.com/gonnavis/three.js into S…
gonnavis Sep 28, 2020
753fe6b
default DistanceAttenuation on
gonnavis Sep 28, 2020
d0b0b93
bugfix: OrthographicCamera support
gonnavis Sep 28, 2020
62e4079
infiniteThick
gonnavis Sep 28, 2020
6607e29
normal noise
gonnavis Sep 28, 2020
28aef30
a
gonnavis Sep 28, 2020
c51855d
a
gonnavis Sep 28, 2020
f6a1f3e
fit morphTargets
gonnavis Sep 29, 2020
d5d25a2
Separate blur setting
gonnavis Sep 29, 2020
36473a2
performance: use #ifdef instead of if
gonnavis Sep 30, 2020
7511ce7
a
gonnavis Sep 30, 2020
8c59420
New d1viewPosition calc method, seems same performance, but more conc…
gonnavis Oct 2, 2020
9fe3281
Use Perspective-Correct Interpolation instead of lineLineIntersection
gonnavis Oct 7, 2020
311bf63
performance & priliminary angleCompensation
gonnavis Oct 7, 2020
454c82d
NormalBlending
gonnavis Oct 13, 2020
34e2044
screenshot
gonnavis Oct 13, 2020
b8b7b82
a
gonnavis Oct 13, 2020
6029774
Resolve conflict of examples/files.js
gonnavis Oct 25, 2020
8181946
bugfix: maxDistance and attenuation should compared by distance perpe…
gonnavis Oct 26, 2020
da39b17
fresnel
gonnavis Oct 26, 2020
7ae5672
Merge branch 'dev' into SSRPass
gonnavis Oct 27, 2020
b0fc8ef
Merge https://github.com/mrdoob/three.js into SSRPass
gonnavis Oct 29, 2020
5aebdd8
calculated maxReflectRayLen
gonnavis Oct 31, 2020
6666d3b
bugfix: Character morphTarget normalMaterial.
gonnavis Oct 31, 2020
92ead6b
bugfix: Character morphTarget normalMaterial.
gonnavis Nov 1, 2020
640daa0
change default scene to bunny
gonnavis Jan 20, 2021
d042fdf
surfDist compensation by angle
gonnavis Jan 21, 2021
701f6a5
With Refelector.js, default off. Now just add a reflector to hide the…
gonnavis Jan 22, 2021
cd8eb7a
Let Reflector.js can handle opacity by depthTexture.
gonnavis Jan 23, 2021
2e79d4a
fix the "jumpiness" of the reflection
gonnavis Jan 24, 2021
4dcbe8c
1. Exclude Reflector from SSRPass if Reflector is on. 2. Increase ref…
gonnavis Jan 25, 2021
7e08822
Decrease the vertical offset between SSR and Reflector.
gonnavis Jan 25, 2021
01588a5
Revert plane.depthWrite = false & Revert to reflector.position.y = pl…
gonnavis Jan 25, 2021
2c56b95
Remove the noise setting.
gonnavis Jan 25, 2021
58c2812
Use pointToLineDistance instead of viewReflectRayZ to calculate away,…
gonnavis Jan 25, 2021
15a1bd1
Performance: perform pointToLineDistance only if viewReflectRayZ-sD<=vZ.
gonnavis Jan 26, 2021
ba1630c
1. Reduce the size of the reflector to prevent glitch caused by low p…
gonnavis Jan 26, 2021
424b074
Merge remote-tracking branch 'upstream/dev' into SSRPass
gonnavis Feb 3, 2021
a1e8e98
Fix: .getClearColor() now requires a Color as an argument.
gonnavis Feb 6, 2021
98f9aaa
postprocessing with reflector performance problem quick hack.
gonnavis Feb 18, 2021
1142c1b
Turn on GroundReflector by default & some clean up.
gonnavis Feb 19, 2021
414da57
Let groundReflector also follow settings.
gonnavis Feb 21, 2021
de0c8f7
Fix zigzag problem between ground and objects.
gonnavis Feb 21, 2021
c37e040
gui folder
gonnavis Feb 21, 2021
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
1 change: 1 addition & 0 deletions examples/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@
"webgl_postprocessing_smaa",
"webgl_postprocessing_sobel",
"webgl_postprocessing_ssao",
"webgl_postprocessing_ssr",
"webgl_postprocessing_taa",
"webgl_postprocessing_unreal_bloom",
"webgl_postprocessing_unreal_bloom_selective"
Expand Down
333 changes: 333 additions & 0 deletions examples/jsm/objects/ReflectorForSSRPass.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
import {
Color,
LinearFilter,
MathUtils,
Matrix4,
Mesh,
PerspectiveCamera,
Plane,
RGBFormat,
ShaderMaterial,
UniformsUtils,
Vector3,
Vector4,
WebGLRenderTarget,
DepthTexture,
UnsignedShortType,
NearestFilter
} from '../../../build/three.module.js';

var Reflector = function ( geometry, options ) {

Mesh.call( this, geometry );

this.type = 'Reflector';

var scope = this;

options = options || {};

var color = ( options.color !== undefined ) ? new Color( options.color ) : new Color( 0x7F7F7F );
var textureWidth = options.textureWidth || 512;
var textureHeight = options.textureHeight || 512;
var clipBias = options.clipBias || 0;
var shader = options.shader || Reflector.ReflectorShader;
var useDepthTexture = options.useDepthTexture
var yAxis = new Vector3(0, 1, 0);
var vecTemp0 = new Vector3();
var vecTemp1 = new Vector3();

//

scope.needsUpdate = false;
scope.maxDistance = Reflector.ReflectorShader.uniforms.maxDistance.value
scope.opacity = Reflector.ReflectorShader.uniforms.opacity.value

scope._isDistanceAttenuation = Reflector.ReflectorShader.defines.isDistanceAttenuation
Object.defineProperty(scope, 'isDistanceAttenuation', {
get() {
return scope._isDistanceAttenuation
},
set(val) {
if (scope._isDistanceAttenuation === val) return
scope._isDistanceAttenuation = val
scope.material.defines.isDistanceAttenuation = val
scope.material.needsUpdate = true
}
})

scope._isFresnel = Reflector.ReflectorShader.defines.isFresnel
Object.defineProperty(scope, 'isFresnel', {
get() {
return scope._isFresnel
},
set(val) {
if (scope._isFresnel === val) return
scope._isFresnel = val
scope.material.defines.isFresnel = val
scope.material.needsUpdate = true
}
})

var reflectorPlane = new Plane();
var normal = new Vector3();
var reflectorWorldPosition = new Vector3();
var cameraWorldPosition = new Vector3();
var rotationMatrix = new Matrix4();
var lookAtPosition = new Vector3( 0, 0, - 1 );
var clipPlane = new Vector4();

var view = new Vector3();
var target = new Vector3();
var q = new Vector4();

var textureMatrix = new Matrix4();
var virtualCamera = new PerspectiveCamera();

if( useDepthTexture ){
var depthTexture = new DepthTexture();
depthTexture.type = UnsignedShortType;
depthTexture.minFilter = NearestFilter;
depthTexture.maxFilter = NearestFilter;
}

var parameters = {
minFilter: LinearFilter,
magFilter: LinearFilter,
format: RGBFormat,
depthTexture: useDepthTexture ? depthTexture : null,
};

var renderTarget = new WebGLRenderTarget( textureWidth, textureHeight, parameters );

if ( ! MathUtils.isPowerOfTwo( textureWidth ) || ! MathUtils.isPowerOfTwo( textureHeight ) ) {

renderTarget.texture.generateMipmaps = false;

}

var material = new ShaderMaterial( {
transparent: useDepthTexture,
defines: Object.assign({
useDepthTexture: useDepthTexture
}, Reflector.ReflectorShader.defines),
uniforms: UniformsUtils.clone( shader.uniforms ),
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader
} );

material.uniforms[ 'tDiffuse' ].value = renderTarget.texture;
material.uniforms[ 'color' ].value = color;
material.uniforms[ 'textureMatrix' ].value = textureMatrix;
if (useDepthTexture) {
material.uniforms[ 'tDepth' ].value = renderTarget.depthTexture;
}

this.material = material;

this.doRender = function ( renderer, scene, camera ) {

material.uniforms['maxDistance'].value = scope.maxDistance * (camera.position.length() / camera.position.y);
///todo: Temporary hack,
// need precise calculation like this https://github.com/mrdoob/three.js/pull/20156/commits/8181946068e386d14a283cbd4f8877bc7ae066d3 ,
// after fully understand http://www.terathon.com/lengyel/Lengyel-Oblique.pdf .

material.uniforms['opacity'].value = scope.opacity;

vecTemp0.copy(camera.position).normalize();
vecTemp1.copy(vecTemp0).reflect(yAxis);
material.uniforms['fresnel'].value = (vecTemp0.dot( vecTemp1 ) + 1.) / 2.; ///todo: Also need to use glsl viewPosition and viewNormal per pixel.
// console.log(material.uniforms['fresnel'].value)

reflectorWorldPosition.setFromMatrixPosition( scope.matrixWorld );
cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld );

rotationMatrix.extractRotation( scope.matrixWorld );

normal.set( 0, 0, 1 );
normal.applyMatrix4( rotationMatrix );

view.subVectors( reflectorWorldPosition, cameraWorldPosition );

// Avoid rendering when reflector is facing away

if ( view.dot( normal ) > 0 ) return;

view.reflect( normal ).negate();
view.add( reflectorWorldPosition );

rotationMatrix.extractRotation( camera.matrixWorld );

lookAtPosition.set( 0, 0, - 1 );
lookAtPosition.applyMatrix4( rotationMatrix );
lookAtPosition.add( cameraWorldPosition );

target.subVectors( reflectorWorldPosition, lookAtPosition );
target.reflect( normal ).negate();
target.add( reflectorWorldPosition );

virtualCamera.position.copy( view );
virtualCamera.up.set( 0, 1, 0 );
virtualCamera.up.applyMatrix4( rotationMatrix );
virtualCamera.up.reflect( normal );
virtualCamera.lookAt( target );

virtualCamera.far = camera.far; // Used in WebGLBackground

virtualCamera.updateMatrixWorld();
virtualCamera.projectionMatrix.copy( camera.projectionMatrix );

// Update the texture matrix
textureMatrix.set(
0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0
);
textureMatrix.multiply( virtualCamera.projectionMatrix );
textureMatrix.multiply( virtualCamera.matrixWorldInverse );
textureMatrix.multiply( scope.matrixWorld );

// Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
// Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
reflectorPlane.setFromNormalAndCoplanarPoint( normal, reflectorWorldPosition );
reflectorPlane.applyMatrix4( virtualCamera.matrixWorldInverse );

clipPlane.set( reflectorPlane.normal.x, reflectorPlane.normal.y, reflectorPlane.normal.z, reflectorPlane.constant );

var projectionMatrix = virtualCamera.projectionMatrix;

q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ];
q.z = - 1.0;
q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];

// Calculate the scaled plane vector
clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) );

// Replacing the third row of the projection matrix
projectionMatrix.elements[ 2 ] = clipPlane.x;
projectionMatrix.elements[ 6 ] = clipPlane.y;
projectionMatrix.elements[ 10 ] = clipPlane.z + 1.0 - clipBias;
projectionMatrix.elements[ 14 ] = clipPlane.w;

// Render

renderTarget.texture.encoding = renderer.outputEncoding;

// scope.visible = false;

var currentRenderTarget = renderer.getRenderTarget();

var currentXrEnabled = renderer.xr.enabled;
var currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;

renderer.xr.enabled = false; // Avoid camera modification
renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows

renderer.setRenderTarget( renderTarget );

renderer.state.buffers.depth.setMask( true ); // make sure the depth buffer is writable so it can be properly cleared, see #18897

if ( renderer.autoClear === false ) renderer.clear();
renderer.render( scene, virtualCamera );

renderer.xr.enabled = currentXrEnabled;
renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;

renderer.setRenderTarget( currentRenderTarget );

// Restore viewport

var viewport = camera.viewport;

if ( viewport !== undefined ) {

renderer.state.viewport( viewport );

}

// scope.visible = true;

};

this.getRenderTarget = function () {

return renderTarget;

};

};

Reflector.prototype = Object.create( Mesh.prototype );
Reflector.prototype.constructor = Reflector;

Reflector.ReflectorShader = { ///todo: Will conflict with Reflector.js?

defines: {
isDistanceAttenuation: true,
isFresnel: true,
},

uniforms: {

color: { value: null },
tDiffuse: { value: null },
tDepth: { value: null },
textureMatrix: { value: null },
maxDistance: { value: 180 },
opacity: { value: .5 },
fresnel: { value: null },

},

vertexShader: [
'uniform mat4 textureMatrix;',
'varying vec4 vUv;',

'void main() {',

' vUv = textureMatrix * vec4( position, 1.0 );',

' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',

'}'
].join( '\n' ),

fragmentShader: `
uniform vec3 color;
uniform sampler2D tDiffuse;
uniform sampler2D tDepth;
uniform float maxDistance;
uniform float opacity;
uniform float fresnel;
varying vec4 vUv;
float blendOverlay( float base, float blend ) {
return( base < 0.5 ? ( 2.0 * base * blend ) : ( 1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );
}
vec3 blendOverlay( vec3 base, vec3 blend ) {
return vec3( blendOverlay( base.r, blend.r ), blendOverlay( base.g, blend.g ), blendOverlay( base.b, blend.b ) );
}
void main() {
vec4 base = texture2DProj( tDiffuse, vUv );
#ifdef useDepthTexture
float op=opacity;
float depth = texture2DProj( tDepth, vUv ).r;
if(depth>maxDistance) discard;
#ifdef isDistanceAttenuation
float ratio=1.-(depth/maxDistance);
float attenuation=ratio*ratio;
op=opacity*attenuation;
#endif
#ifdef isFresnel
op*=fresnel;
#endif
gl_FragColor = vec4( blendOverlay( base.rgb, color ), op );
#else
gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );
#endif
}
`,
};

export { Reflector };
Loading