Skip to content

Commit 0deec79

Browse files
committed
Let groundReflector also follow settings.
1 parent 1142c1b commit 0deec79

File tree

3 files changed

+117
-58
lines changed

3 files changed

+117
-58
lines changed

examples/jsm/objects/ReflectorForSSRPass.js

+93-47
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,41 @@ var Reflector = function ( geometry, options ) {
3333
var clipBias = options.clipBias || 0;
3434
var shader = options.shader || Reflector.ReflectorShader;
3535
var useDepthTexture = options.useDepthTexture
36+
var yAxis = new Vector3(0, 1, 0);
37+
var vecTemp0 = new Vector3();
38+
var vecTemp1 = new Vector3();
3639

3740
//
3841

3942
scope.needsUpdate = false;
43+
scope.maxDistance = Reflector.ReflectorShader.uniforms.maxDistance.value
44+
scope.opacity = Reflector.ReflectorShader.uniforms.opacity.value
45+
46+
scope._isDistanceAttenuation = Reflector.ReflectorShader.defines.isDistanceAttenuation
47+
Object.defineProperty(scope, 'isDistanceAttenuation', {
48+
get() {
49+
return scope._isDistanceAttenuation
50+
},
51+
set(val) {
52+
if (scope._isDistanceAttenuation === val) return
53+
scope._isDistanceAttenuation = val
54+
scope.material.defines.isDistanceAttenuation = val
55+
scope.material.needsUpdate = true
56+
}
57+
})
58+
59+
scope._isFresnel = Reflector.ReflectorShader.defines.isFresnel
60+
Object.defineProperty(scope, 'isFresnel', {
61+
get() {
62+
return scope._isFresnel
63+
},
64+
set(val) {
65+
if (scope._isFresnel === val) return
66+
scope._isFresnel = val
67+
scope.material.defines.isFresnel = val
68+
scope.material.needsUpdate = true
69+
}
70+
})
4071

4172
var reflectorPlane = new Plane();
4273
var normal = new Vector3();
@@ -77,7 +108,9 @@ var Reflector = function ( geometry, options ) {
77108

78109
var material = new ShaderMaterial( {
79110
transparent: useDepthTexture,
80-
defines: { useDepthTexture: useDepthTexture },
111+
defines: Object.assign({
112+
useDepthTexture: useDepthTexture
113+
}, Reflector.ReflectorShader.defines),
81114
uniforms: UniformsUtils.clone( shader.uniforms ),
82115
fragmentShader: shader.fragmentShader,
83116
vertexShader: shader.vertexShader
@@ -97,6 +130,18 @@ var Reflector = function ( geometry, options ) {
97130
scope.needsUpdate = false;
98131
// console.log('onBeforeRender')
99132

133+
material.uniforms['maxDistance'].value = scope.maxDistance * (camera.position.length() / camera.position.y);
134+
// Temporary hack,
135+
// need precise calculation like this https://github.com/mrdoob/three.js/pull/20156/commits/8181946068e386d14a283cbd4f8877bc7ae066d3 ,
136+
// after fully understand http://www.terathon.com/lengyel/Lengyel-Oblique.pdf .
137+
138+
material.uniforms['opacity'].value = scope.opacity;
139+
140+
vecTemp0.copy(camera.position).normalize();
141+
vecTemp1.copy(vecTemp0).reflect(yAxis);
142+
material.uniforms['fresnel'].value = (vecTemp0.dot( vecTemp1 ) + 1.) / 2.;
143+
// console.log(material.uniforms['fresnel'].value)
144+
100145
reflectorWorldPosition.setFromMatrixPosition( scope.matrixWorld );
101146
cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld );
102147

@@ -220,25 +265,22 @@ var Reflector = function ( geometry, options ) {
220265
Reflector.prototype = Object.create( Mesh.prototype );
221266
Reflector.prototype.constructor = Reflector;
222267

223-
Reflector.ReflectorShader = {
224-
225-
uniforms: {
226-
227-
'color': {
228-
value: null
229-
},
268+
Reflector.ReflectorShader = { ///todo: Will conflict with Reflector.js?
230269

231-
'tDiffuse': {
232-
value: null
233-
},
270+
defines: {
271+
isDistanceAttenuation: true,
272+
isFresnel: true,
273+
},
234274

235-
'tDepth': {
236-
value: null
237-
},
275+
uniforms: {
238276

239-
'textureMatrix': {
240-
value: null
241-
}
277+
color: { value: null },
278+
tDiffuse: { value: null },
279+
tDepth: { value: null },
280+
textureMatrix: { value: null },
281+
maxDistance: { value: 180 },
282+
opacity: { value: .5 },
283+
fresnel: { value: null },
242284

243285
},
244286

@@ -255,36 +297,40 @@ Reflector.ReflectorShader = {
255297
'}'
256298
].join( '\n' ),
257299

258-
fragmentShader: [
259-
'uniform vec3 color;',
260-
'uniform sampler2D tDiffuse;',
261-
'uniform sampler2D tDepth;',
262-
'varying vec4 vUv;',
263-
264-
'float blendOverlay( float base, float blend ) {',
265-
266-
' return( base < 0.5 ? ( 2.0 * base * blend ) : ( 1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );',
267-
268-
'}',
269-
270-
'vec3 blendOverlay( vec3 base, vec3 blend ) {',
271-
272-
' return vec3( blendOverlay( base.r, blend.r ), blendOverlay( base.g, blend.g ), blendOverlay( base.b, blend.b ) );',
273-
274-
'}',
275-
276-
'void main() {',
277-
278-
' vec4 base = texture2DProj( tDiffuse, vUv );',
279-
' #ifdef useDepthTexture',
280-
' vec4 depth = texture2DProj( tDepth, vUv );',
281-
' gl_FragColor = vec4( blendOverlay( base.rgb, color ), pow(1.-depth.r,10./*temp*/) );',
282-
' #else',
283-
' gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );',
284-
' #endif',
285-
286-
'}'
287-
].join( '\n' )
300+
fragmentShader: `
301+
uniform vec3 color;
302+
uniform sampler2D tDiffuse;
303+
uniform sampler2D tDepth;
304+
uniform float maxDistance;
305+
uniform float opacity;
306+
uniform float fresnel;
307+
varying vec4 vUv;
308+
float blendOverlay( float base, float blend ) {
309+
return( base < 0.5 ? ( 2.0 * base * blend ) : ( 1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );
310+
}
311+
vec3 blendOverlay( vec3 base, vec3 blend ) {
312+
return vec3( blendOverlay( base.r, blend.r ), blendOverlay( base.g, blend.g ), blendOverlay( base.b, blend.b ) );
313+
}
314+
void main() {
315+
vec4 base = texture2DProj( tDiffuse, vUv );
316+
#ifdef useDepthTexture
317+
float op=opacity;
318+
float depth = texture2DProj( tDepth, vUv ).r;
319+
if(depth>maxDistance) discard;
320+
#ifdef isDistanceAttenuation
321+
float ratio=1.-(depth/maxDistance);
322+
float attenuation=ratio*ratio;
323+
op=opacity*attenuation;
324+
#endif
325+
#ifdef isFresnel
326+
op*=fresnel;
327+
#endif
328+
gl_FragColor = vec4( blendOverlay( base.rgb, color ), op );
329+
#else
330+
gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );
331+
#endif
332+
}
333+
`,
288334
};
289335

290336
export { Reflector };

examples/jsm/postprocessing/SSRPass.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ var SSRPass = function({ scene, camera, width, height, selects, encoding, isPers
6666
}
6767
})
6868

69-
this._isBouncing = isBouncing
69+
this._isBouncing = isBouncing ///todo: don't need defineProperty
7070
Object.defineProperty(this, 'isBouncing', {
7171
get() {
7272
return this._isBouncing

examples/webgl_postprocessing_ssr.html

+23-10
Original file line numberDiff line numberDiff line change
@@ -188,14 +188,8 @@
188188

189189
// GUI
190190

191-
gui = new GUI({ width: 400 });
191+
gui = new GUI();
192192
gui.add(params, 'enableSSR').name('Enable SSR');
193-
gui.add(params, 'autoRotate').onChange(() => {
194-
controls.enabled = !params.autoRotate
195-
})
196-
gui.add(ssrPass, 'isDistanceAttenuation');
197-
ssrPass.maxDistance = .1
198-
gui.add(ssrPass, 'maxDistance').min(0).max(1).step(.01);
199193
gui.add(params, 'isGroundReflector').onChange(() => {
200194
if (params.isGroundReflector) {
201195
groundReflector.visible = true
@@ -205,14 +199,27 @@
205199
ssrPass.selects = null
206200
}
207201
})
202+
gui.add(params, 'autoRotate').onChange(() => {
203+
controls.enabled = !params.autoRotate
204+
})
205+
gui.add(ssrPass, 'isFresnel').onChange(()=>{
206+
groundReflector.isFresnel=ssrPass.isFresnel
207+
});
208+
gui.add(ssrPass, 'isDistanceAttenuation').onChange(()=>{
209+
groundReflector.isDistanceAttenuation=ssrPass.isDistanceAttenuation
210+
});
211+
ssrPass.maxDistance = .1
212+
groundReflector.maxDistance = ssrPass.maxDistance
213+
gui.add(ssrPass, 'maxDistance').min(0).max(.5).step(.001).onChange(()=>{
214+
groundReflector.maxDistance=ssrPass.maxDistance
215+
});
208216
gui.add(params, 'isOtherMeshes').onChange(() => {
209217
if (params.isOtherMeshes) {
210218
otherMeshes.forEach(mesh => mesh.visible = true)
211219
} else {
212220
otherMeshes.forEach(mesh => mesh.visible = false)
213221
}
214222
})
215-
gui.add(ssrPass, 'isFresnel');
216223
gui.add(ssrPass, 'isBouncing')
217224
gui.add(ssrPass, 'output', {
218225
'Default': SSRPass.OUTPUT.Default,
@@ -226,8 +233,11 @@
226233
ssrPass.output = parseInt(value);
227234

228235
});
229-
ssrPass.opacity = .8
230-
gui.add(ssrPass, 'opacity').min(0).max(1);
236+
ssrPass.opacity = 1
237+
groundReflector.opacity=ssrPass.opacity
238+
gui.add(ssrPass, 'opacity').min(0).max(1).onChange(()=>{
239+
groundReflector.opacity=ssrPass.opacity
240+
});
231241
if (isPerspectiveCamera) {
232242
ssrPass.surfDist = 0.0015
233243
gui.add(ssrPass, 'surfDist').min(0).max(.005).step(.0001);
@@ -238,6 +248,7 @@
238248
gui.add(ssrPass, 'isInfiniteThick');
239249
gui.add(ssrPass, 'thickTolerance').min(0).max(.05).step(.0001);
240250
gui.add(ssrPass, 'isBlur');
251+
gui.close()
241252

242253
}
243254

@@ -278,6 +289,8 @@
278289

279290
if (params.enableSSR) {
280291
groundReflector.needsUpdate = true; // Just SSRPass's beautyRenderTarget (which rendered fisrt internally) need Reflector.
292+
///todo: groundReflector has full ground info, need use it to solve reflection gaps problem on objects when camera near ground.
293+
///todo: the normal info where groundReflector reflected need to be changed.
281294
composer.render();
282295
} else {
283296
groundReflector.needsUpdate = true;

0 commit comments

Comments
 (0)