diff --git a/examples/jsm/tsl/display/GTAONode.js b/examples/jsm/tsl/display/GTAONode.js index 32248d3d9b203c..0134ebe37f82d9 100644 --- a/examples/jsm/tsl/display/GTAONode.js +++ b/examples/jsm/tsl/display/GTAONode.js @@ -1,5 +1,5 @@ import { DataTexture, RenderTarget, RepeatWrapping, Vector2, Vector3, PostProcessingUtils } from 'three'; -import { getViewPosition, QuadMesh, TempNode, nodeObject, Fn, float, NodeUpdateType, uv, uniform, Loop, vec2, vec3, vec4, int, dot, max, pow, abs, If, textureSize, sin, cos, PI, texture, passTexture, mat3, add, normalize, mul, cross, div, mix, sqrt, sub, acos, clamp, NodeMaterial } from 'three/tsl'; +import { getScreenPosition, getViewPosition, QuadMesh, TempNode, nodeObject, Fn, float, NodeUpdateType, uv, uniform, Loop, vec2, vec3, vec4, int, dot, max, pow, abs, If, textureSize, sin, cos, PI, texture, passTexture, mat3, add, normalize, mul, cross, div, mix, sqrt, sub, acos, clamp, NodeMaterial } from 'three/tsl'; const _quadMesh = /*@__PURE__*/ new QuadMesh(); const _size = /*@__PURE__*/ new Vector2(); @@ -92,24 +92,14 @@ class GTAONode extends TempNode { const sampleDepth = ( uv ) => this.depthNode.uv( uv ).x; const sampleNoise = ( uv ) => this.noiseNode.uv( uv ); - const getSceneUvAndDepth = Fn( ( [ sampleViewPos ] )=> { - - const sampleClipPos = this.cameraProjectionMatrix.mul( vec4( sampleViewPos, 1.0 ) ); - let sampleUv = sampleClipPos.xy.div( sampleClipPos.w ).mul( 0.5 ).add( 0.5 ).toVar(); - sampleUv = vec2( sampleUv.x, sampleUv.y.oneMinus() ); - const sampleSceneDepth = sampleDepth( sampleUv ); - return vec3( sampleUv, sampleSceneDepth ); - - } ); - const ao = Fn( () => { - const depth = sampleDepth( uvNode ); + const depth = sampleDepth( uvNode ).toVar(); depth.greaterThanEqual( 1.0 ).discard(); - const viewPosition = getViewPosition( uvNode, depth, this.cameraProjectionMatrixInverse ); - const viewNormal = this.normalNode.rgb.normalize(); + const viewPosition = getViewPosition( uvNode, depth, this.cameraProjectionMatrixInverse ).toVar(); + const viewNormal = this.normalNode.rgb.normalize().toVar(); const radiusToUse = this.radius; @@ -122,23 +112,23 @@ class GTAONode extends TempNode { const bitangent = vec3( tangent.y.mul( - 1.0 ), tangent.x, 0.0 ); const kernelMatrix = mat3( tangent, bitangent, vec3( 0.0, 0.0, 1.0 ) ); - const DIRECTIONS = this.SAMPLES.lessThan( 30 ).select( 3, 5 ); - const STEPS = add( this.SAMPLES, DIRECTIONS.sub( 1 ) ).div( DIRECTIONS ); + const DIRECTIONS = this.SAMPLES.lessThan( 30 ).select( 3, 5 ).toVar(); + const STEPS = add( this.SAMPLES, DIRECTIONS.sub( 1 ) ).div( DIRECTIONS ).toVar(); const ao = float( 0 ).toVar(); Loop( { start: int( 0 ), end: DIRECTIONS, type: 'int', condition: '<' }, ( { i } ) => { - const angle = float( i ).div( float( DIRECTIONS ) ).mul( PI ); + const angle = float( i ).div( float( DIRECTIONS ) ).mul( PI ).toVar(); const sampleDir = vec4( cos( angle ), sin( angle ), 0., add( 0.5, mul( 0.5, noiseTexel.w ) ) ); sampleDir.xyz = normalize( kernelMatrix.mul( sampleDir.xyz ) ); - const viewDir = normalize( viewPosition.xyz.negate() ); - const sliceBitangent = normalize( cross( sampleDir.xyz, viewDir ) ); + const viewDir = normalize( viewPosition.xyz.negate() ).toVar(); + const sliceBitangent = normalize( cross( sampleDir.xyz, viewDir ) ).toVar(); const sliceTangent = cross( sliceBitangent, viewDir ); const normalInSlice = normalize( viewNormal.sub( sliceBitangent.mul( dot( viewNormal, sliceBitangent ) ) ) ); - const tangentToNormalInSlice = cross( normalInSlice, sliceBitangent ); + const tangentToNormalInSlice = cross( normalInSlice, sliceBitangent ).toVar(); const cosHorizons = vec2( dot( viewDir, tangentToNormalInSlice ), dot( viewDir, tangentToNormalInSlice.negate() ) ).toVar(); Loop( { end: STEPS, type: 'int', name: 'j', condition: '<' }, ( { j } ) => { @@ -147,9 +137,10 @@ class GTAONode extends TempNode { // x - const sampleSceneUvDepthX = getSceneUvAndDepth( viewPosition.add( sampleViewOffset ) ); - const sampleSceneViewPositionX = getViewPosition( sampleSceneUvDepthX.xy, sampleSceneUvDepthX.z, this.cameraProjectionMatrixInverse ); - const viewDeltaX = sampleSceneViewPositionX.sub( viewPosition ); + const sampleScreenPositionX = getScreenPosition( viewPosition.add( sampleViewOffset ), this.cameraProjectionMatrix ).toVar(); + const sampleDepthX = sampleDepth( sampleScreenPositionX ).toVar(); + const sampleSceneViewPositionX = getViewPosition( sampleScreenPositionX, sampleDepthX, this.cameraProjectionMatrixInverse ).toVar(); + const viewDeltaX = sampleSceneViewPositionX.sub( viewPosition ).toVar(); If( abs( viewDeltaX.z ).lessThan( this.thickness ), () => { @@ -160,9 +151,10 @@ class GTAONode extends TempNode { // y - const sampleSceneUvDepthY = getSceneUvAndDepth( viewPosition.sub( sampleViewOffset ) ); - const sampleSceneViewPositionY = getViewPosition( sampleSceneUvDepthY.xy, sampleSceneUvDepthY.z, this.cameraProjectionMatrixInverse ); - const viewDeltaY = sampleSceneViewPositionY.sub( viewPosition ); + const sampleScreenPositionY = getScreenPosition( viewPosition.sub( sampleViewOffset ), this.cameraProjectionMatrix ).toVar(); + const sampleDepthY = sampleDepth( sampleScreenPositionY ).toVar(); + const sampleSceneViewPositionY = getViewPosition( sampleScreenPositionY, sampleDepthY, this.cameraProjectionMatrixInverse ).toVar(); + const viewDeltaY = sampleSceneViewPositionY.sub( viewPosition ).toVar(); If( abs( viewDeltaY.z ).lessThan( this.thickness ), () => { @@ -173,7 +165,7 @@ class GTAONode extends TempNode { } ); - const sinHorizons = sqrt( sub( 1.0, cosHorizons.mul( cosHorizons ) ) ); + const sinHorizons = sqrt( sub( 1.0, cosHorizons.mul( cosHorizons ) ) ).toVar(); const nx = dot( normalInSlice, sliceTangent ); const ny = dot( normalInSlice, viewDir ); const nxb = mul( 0.5, acos( cosHorizons.y ).sub( acos( cosHorizons.x ) ).add( sinHorizons.x.mul( cosHorizons.x ).sub( sinHorizons.y.mul( cosHorizons.y ) ) ) ); diff --git a/examples/jsm/tsl/display/SSRNode.js b/examples/jsm/tsl/display/SSRNode.js index 15c9691ca5a309..5848af10979336 100644 --- a/examples/jsm/tsl/display/SSRNode.js +++ b/examples/jsm/tsl/display/SSRNode.js @@ -1,5 +1,5 @@ import { NearestFilter, RenderTarget, Vector2, PostProcessingUtils } from 'three'; -import { getViewPosition, sqrt, mul, div, cross, float, Continue, Break, Loop, int, max, abs, sub, If, dot, reflect, normalize, screenCoordinate, QuadMesh, TempNode, nodeObject, Fn, NodeUpdateType, passTexture, NodeMaterial, uv, uniform, perspectiveDepthToViewZ, orthographicDepthToViewZ, vec2, vec3, vec4 } from 'three/tsl'; +import { getScreenPosition, getViewPosition, sqrt, mul, div, cross, float, Continue, Break, Loop, int, max, abs, sub, If, dot, reflect, normalize, screenCoordinate, QuadMesh, TempNode, nodeObject, Fn, NodeUpdateType, passTexture, NodeMaterial, uv, uniform, perspectiveDepthToViewZ, orthographicDepthToViewZ, vec2, vec3, vec4 } from 'three/tsl'; const _quadMesh = /*@__PURE__*/ new QuadMesh(); const _size = /*@__PURE__*/ new Vector2(); @@ -151,14 +151,6 @@ class SSRNode extends TempNode { } ); - const viewPositionToSceneUv = Fn( ( [ sampleViewPos ] )=> { - - const sampleClipPos = this._cameraProjectionMatrix.mul( vec4( sampleViewPos, 1.0 ) ); - const sampleUv = sampleClipPos.xy.div( sampleClipPos.w ).mul( 0.5 ).add( 0.5 ).toVar(); - return vec2( sampleUv.x, sampleUv.y.oneMinus() ); - - } ); - const ssr = Fn( () => { const metalness = this.metalnessNode.uv( uvNode ).r; @@ -195,7 +187,7 @@ class SSRNode extends TempNode { // d0 and d1 are the start and maximum points of the reflection ray in screen space const d0 = screenCoordinate.xy.toVar(); - const d1 = viewPositionToSceneUv( d1viewPosition ).mul( this._resolution ).toVar(); + const d1 = getScreenPosition( d1viewPosition, this._cameraProjectionMatrix ).mul( this._resolution ).toVar(); // below variables are used to control the raymarching process diff --git a/src/nodes/utils/PostProcessingUtils.js b/src/nodes/utils/PostProcessingUtils.js index 1a6e69e49753e7..825efa786d2947 100644 --- a/src/nodes/utils/PostProcessingUtils.js +++ b/src/nodes/utils/PostProcessingUtils.js @@ -1,6 +1,15 @@ import { Fn, vec2, vec3, vec4 } from '../tsl/TSLBase.js'; import { WebGPUCoordinateSystem } from '../../constants.js'; +/** +* Computes a position in view space based on a fragment's screen position expressed as uv coordinates, the fragments +* depth value and the camera's inverse projection matrix. +* +* @param {vec2} screenPosition - The fragment's screen position expressed as uv coordinates. +* @param {float} depth - The fragment's depth value. +* @param {mat4} projectionMatrixInverse - The camera's inverse projection matrix. +* @return {vec3} The fragments position in view space. +*/ export const getViewPosition = /*@__PURE__*/ Fn( ( [ screenPosition, depth, projectionMatrixInverse ], builder ) => { let clipSpacePosition; @@ -21,3 +30,19 @@ export const getViewPosition = /*@__PURE__*/ Fn( ( [ screenPosition, depth, proj return viewSpacePosition.xyz.div( viewSpacePosition.w ); } ); + +/** +* Computes a screen position expressed as uv coordinates based on a fragment's position in view space +* and the camera's projection matrix +* +* @param {vec3} viewPosition - The fragments position in view space. +* @param {mat4} projectionMatrix - The camera's projection matrix. +* @return {vec2} Teh fragment's screen position expressed as uv coordinates. +*/ +export const getScreenPosition = /*@__PURE__*/ Fn( ( [ viewPosition, projectionMatrix ] ) => { + + const sampleClipPos = projectionMatrix.mul( vec4( viewPosition, 1.0 ) ); + const sampleUv = sampleClipPos.xy.div( sampleClipPos.w ).mul( 0.5 ).add( 0.5 ).toVar(); + return vec2( sampleUv.x, sampleUv.y.oneMinus() ); + +} );