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

PostProcessingUtils: Add getScreenPosition(). #29599

Merged
merged 2 commits into from
Oct 9, 2024
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
46 changes: 19 additions & 27 deletions examples/jsm/tsl/display/GTAONode.js
Original file line number Diff line number Diff line change
@@ -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();
Expand Down Expand Up @@ -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;

Expand All @@ -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 } ) => {
Expand All @@ -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 ), () => {

Expand All @@ -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 ), () => {

Expand All @@ -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 ) ) ) );
Expand Down
12 changes: 2 additions & 10 deletions examples/jsm/tsl/display/SSRNode.js
Original file line number Diff line number Diff line change
@@ -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();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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

Expand Down
25 changes: 25 additions & 0 deletions src/nodes/utils/PostProcessingUtils.js
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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() );

} );