Skip to content

Commit da169d5

Browse files
authored
TSL: Add roughness as an independent parameter for ssr() and move camera to optional. (#31663)
* use `roughnessNode` as input * ignore sample * simplification * Update SSRNode.js * `this._isPerspectiveCamera` as boolean * convert roughness and metalness to float * auto-detect camera and move param to optional value * Update SSRNode.js * cleanup
1 parent 16082fa commit da169d5

File tree

2 files changed

+58
-34
lines changed

2 files changed

+58
-34
lines changed

examples/jsm/tsl/display/SSRNode.js

Lines changed: 56 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ class SSRNode extends TempNode {
2828
* @param {Node<vec4>} colorNode - The node that represents the beauty pass.
2929
* @param {Node<float>} depthNode - A node that represents the beauty pass's depth.
3030
* @param {Node<vec3>} normalNode - A node that represents the beauty pass's normals.
31-
* @param {Node<float>} metalnessRoughnessNode - A node that represents the beauty pass's metalness and roughness.
32-
* @param {Camera} camera - The camera the scene is rendered with.
33-
* @param {boolean} [blurred=false] - Whether the SSR reflections should be blurred or not.
31+
* @param {Node<float>} metalnessNode - A node that represents the beauty pass's metalness.
32+
* @param {?Node<float>} [roughnessNode=null] - A node that represents the beauty pass's roughness.
33+
* @param {?Camera} [camera=null] - The camera the scene is rendered with.
3434
*/
35-
constructor( colorNode, depthNode, normalNode, metalnessRoughnessNode, camera, blurred = false ) {
35+
constructor( colorNode, depthNode, normalNode, metalnessNode, roughnessNode = null, camera = null ) {
3636

3737
super( 'vec4' );
3838

@@ -62,14 +62,18 @@ class SSRNode extends TempNode {
6262
*
6363
* @type {Node<float>}
6464
*/
65-
this.metalnessRoughnessNode = metalnessRoughnessNode;
65+
this.metalnessNode = metalnessNode;
6666

6767
/**
68-
* The camera the scene is rendered with.
68+
* Whether the SSR reflections should be blurred or not. Blurring is a costly
69+
* operation so turn it off if you encounter performance issues on certain
70+
* devices.
6971
*
70-
* @type {Camera}
72+
* @private
73+
* @type {Node<float>}
74+
* @default false
7175
*/
72-
this.camera = camera;
76+
this.roughnessNode = roughnessNode;
7377

7478
/**
7579
* The resolution scale. Valid values are in the range
@@ -133,24 +137,36 @@ class SSRNode extends TempNode {
133137
*/
134138
this.blurQuality = uniform( 2 );
135139

140+
//
141+
142+
if ( camera === null ) {
143+
144+
if ( this.colorNode.passNode && this.colorNode.passNode.isPassNode === true ) {
145+
146+
camera = this.colorNode.passNode.camera;
147+
148+
} else {
149+
150+
throw new Error( 'THREE.TSL: No camera found. ssr() requires a camera.' );
151+
152+
}
153+
154+
}
155+
136156
/**
137-
* The spread of the blur. Automatically set when generating mips.
157+
* The camera the scene is rendered with.
138158
*
139-
* @private
140-
* @type {UniformNode<int>}
159+
* @type {Camera}
141160
*/
142-
this._blurSpread = uniform( 1 );
161+
this.camera = camera;
143162

144163
/**
145-
* Whether the SSR reflections should be blurred or not. Blurring is a costly
146-
* operation so turn it off if you encounter performance issues on certain
147-
* devices.
164+
* The spread of the blur. Automatically set when generating mips.
148165
*
149166
* @private
150-
* @type {boolean}
151-
* @default false
167+
* @type {UniformNode<int>}
152168
*/
153-
this._blurred = blurred;
169+
this._blurSpread = uniform( 1 );
154170

155171
/**
156172
* Represents the projection matrix of the scene's camera.
@@ -190,7 +206,7 @@ class SSRNode extends TempNode {
190206
* @private
191207
* @type {UniformNode<bool>}
192208
*/
193-
this._isPerspectiveCamera = uniform( camera.isPerspectiveCamera ? 1 : 0 );
209+
this._isPerspectiveCamera = uniform( camera.isPerspectiveCamera );
194210

195211
/**
196212
* The resolution of the pass.
@@ -254,16 +270,24 @@ class SSRNode extends TempNode {
254270
*/
255271
this._textureNode = passTexture( this, this._ssrRenderTarget.texture );
256272

257-
const mips = this._blurRenderTarget.texture.mipmaps.length - 1;
258-
const lod = this.metalnessRoughnessNode.g.mul( mips ).clamp( 0, mips );
273+
let blurredTextureNode = null;
274+
275+
if ( this.roughnessNode !== null ) {
276+
277+
const mips = this._blurRenderTarget.texture.mipmaps.length - 1;
278+
const lod = float( this.roughnessNode ).mul( mips ).clamp( 0, mips );
279+
280+
blurredTextureNode = passTexture( this, this._blurRenderTarget.texture ).level( lod );
281+
282+
}
259283

260284
/**
261285
* Holds the blurred SSR reflections.
262286
*
263287
* @private
264-
* @type {PassTextureNode}
288+
* @type {?PassTextureNode}
265289
*/
266-
this._blurredTextureNode = passTexture( this, this._blurRenderTarget.texture ).level( lod );
290+
this._blurredTextureNode = blurredTextureNode;
267291

268292
}
269293

@@ -274,7 +298,7 @@ class SSRNode extends TempNode {
274298
*/
275299
getTextureNode() {
276300

277-
return this._blurred ? this._blurredTextureNode : this._textureNode;
301+
return this.roughnessNode !== null ? this._blurredTextureNode : this._textureNode;
278302

279303
}
280304

@@ -327,7 +351,7 @@ class SSRNode extends TempNode {
327351

328352
// blur (optional)
329353

330-
if ( this._blurred === true ) {
354+
if ( this.roughnessNode !== null ) {
331355

332356
// blur mips but leave the base mip unblurred
333357

@@ -417,7 +441,7 @@ class SSRNode extends TempNode {
417441

418442
const ssr = Fn( () => {
419443

420-
const metalness = this.metalnessRoughnessNode.sample( uvNode ).r;
444+
const metalness = float( this.metalnessNode );
421445

422446
// fragments with no metalness do not reflect their environment
423447
metalness.equal( 0.0 ).discard();
@@ -440,7 +464,7 @@ class SSRNode extends TempNode {
440464
const d1viewPosition = viewPosition.add( viewReflectDir.mul( maxReflectRayLen ) ).toVar();
441465

442466
// check if d1viewPosition lies behind the camera near plane
443-
If( this._isPerspectiveCamera.equal( float( 1 ) ).and( d1viewPosition.z.greaterThan( this._cameraNear.negate() ) ), () => {
467+
If( this._isPerspectiveCamera.and( d1viewPosition.z.greaterThan( this._cameraNear.negate() ) ), () => {
444468

445469
// if so, ensure d1viewPosition is clamped on the near plane.
446470
// this prevents artifacts during the ray marching process
@@ -499,7 +523,7 @@ class SSRNode extends TempNode {
499523
const s = xy.sub( d0 ).length().div( totalLen );
500524

501525
// depending on the camera type, we now compute the z-coordinate of the reflected ray at the current step in view space
502-
If( this._isPerspectiveCamera.equal( float( 1 ) ), () => {
526+
If( this._isPerspectiveCamera, () => {
503527

504528
const recipVPZ = float( 1 ).div( viewPosition.z ).toVar();
505529
viewReflectRayZ.assign( float( 1 ).div( recipVPZ.add( s.mul( float( 1 ).div( d1viewPosition.z ).sub( recipVPZ ) ) ) ) );
@@ -622,9 +646,9 @@ export default SSRNode;
622646
* @param {Node<vec4>} colorNode - The node that represents the beauty pass.
623647
* @param {Node<float>} depthNode - A node that represents the beauty pass's depth.
624648
* @param {Node<vec3>} normalNode - A node that represents the beauty pass's normals.
625-
* @param {Node<float>} metalnessRoughnessNode - A node that represents the beauty pass's metalness and roughness.
626-
* @param {Camera} camera - The camera the scene is rendered with.
627-
* @param {boolean} [blurred=false] - Whether the SSR reflections should be blurred or not.
649+
* @param {Node<float>} metalnessNode - A node that represents the beauty pass's metalness.
650+
* @param {?Node<float>} [roughnessNode=null] - A node that represents the beauty pass's roughness.
651+
* @param {?Camera} [camera=null] - The camera the scene is rendered with.
628652
* @returns {SSRNode}
629653
*/
630-
export const ssr = ( colorNode, depthNode, normalNode, metalnessRoughnessNode, camera, blurred ) => nodeObject( new SSRNode( nodeObject( colorNode ), nodeObject( depthNode ), nodeObject( normalNode ), nodeObject( metalnessRoughnessNode ), camera, blurred ) );
654+
export const ssr = ( colorNode, depthNode, normalNode, metalnessNode, roughnessNode = null, camera = null ) => nodeObject( new SSRNode( nodeObject( colorNode ), nodeObject( depthNode ), nodeObject( normalNode ), nodeObject( metalnessNode ), nodeObject( roughnessNode ), camera ) );

examples/webgpu_postprocessing_ssr.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,15 @@
140140
const metalRoughTexture = scenePass.getTexture( 'metalrough' );
141141
metalRoughTexture.type = THREE.UnsignedByteType;
142142

143-
const customNormal = sample( ( uv ) => {
143+
const sceneNormal = sample( ( uv ) => {
144144

145145
return colorToDirection( scenePassNormal.sample( uv ) );
146146

147147
} );
148148

149149
//
150150

151-
ssrPass = ssr( scenePassColor, scenePassDepth, customNormal, scenePassMetalRough, camera, true );
151+
ssrPass = ssr( scenePassColor, scenePassDepth, sceneNormal, scenePassMetalRough.r, scenePassMetalRough.g );
152152

153153
// blend SSR over beauty
154154

0 commit comments

Comments
 (0)