Skip to content
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
Binary file modified examples/screenshots/webgpu_postprocessing_ao.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
87 changes: 69 additions & 18 deletions examples/webgpu_postprocessing_ao.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,28 @@
<script type="module">

import * as THREE from 'three';
import { pass, mrt, output, transformedNormalView } from 'three/tsl';
import { pass, mrt, output, transformedNormalView, texture, ao } from 'three/tsl';

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { SimplexNoise } from 'three/addons/math/SimplexNoise.js';

import Stats from 'three/addons/libs/stats.module.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

let camera, scene, renderer, postProcessing, controls, clock, stats, mixer;

let aoPass;
let aoPass, blendPassAO, blendPassDenoise, scenePassColor;

const params = {
blendIntensity: 1,
distanceExponent: 1,
distanceFallOff: 1,
radius: 0.25,
scale: 1,
thickness: 1,
denoised: true,
enabled: true
};

Expand All @@ -57,10 +58,10 @@
clock = new THREE.Clock();

const hdrloader = new RGBELoader();
const texture = await hdrloader.loadAsync( 'textures/equirectangular/quarry_01_1k.hdr' );
texture.mapping = THREE.EquirectangularReflectionMapping;
const envMap = await hdrloader.loadAsync( 'textures/equirectangular/quarry_01_1k.hdr' );
envMap.mapping = THREE.EquirectangularReflectionMapping;

scene.environment = texture;
scene.environment = envMap;

renderer = new THREE.WebGPURenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
Expand All @@ -86,13 +87,22 @@
normal: transformedNormalView
} ) );

const scenePassColor = scenePass.getTextureNode( 'output' );
scenePassColor = scenePass.getTextureNode( 'output' );
const scenePassNormal = scenePass.getTextureNode( 'normal' );
const scenePassDepth = scenePass.getTextureNode( 'depth' );

aoPass = scenePassColor.ao( scenePassDepth, scenePassNormal, camera );
// ao

postProcessing.outputNode = aoPass;
aoPass = ao( scenePassDepth, scenePassNormal, camera );
blendPassAO = aoPass.getTextureNode().mul( scenePassColor );

// denoise (optional)

const noiseTexture = texture( generateNoise() );
const denoisePass = aoPass.getTextureNode().denoise( scenePassDepth, scenePassNormal, noiseTexture, camera );
blendPassDenoise = denoisePass.mul( scenePassColor );

postProcessing.outputNode = blendPassDenoise;

//

Expand All @@ -119,34 +129,43 @@

const gui = new GUI();
gui.title( 'AO settings' );
gui.add( params, 'blendIntensity' ).min( 0 ).max( 1 ).onChange( updateParameters );
gui.add( params, 'distanceExponent' ).min( 1 ).max( 4 ).onChange( updateParameters );
gui.add( params, 'distanceFallOff' ).min( 0.01 ).max( 1 ).onChange( updateParameters );
gui.add( params, 'radius' ).min( 0.01 ).max( 1 ).onChange( updateParameters );
gui.add( params, 'scale' ).min( 0.01 ).max( 2 ).onChange( updateParameters );
gui.add( params, 'thickness' ).min( 0.01 ).max( 2 ).onChange( updateParameters );
gui.add( params, 'denoised' ).onChange( updatePassChain );
gui.add( params, 'enabled' ).onChange( updatePassChain );

}

function updatePassChain() {

if ( params.enabled === true ) {

gui.add( params, 'enabled' ).onChange( ( value ) => {

if ( value === true ) {
if ( params.denoised === true ) {

postProcessing.outputNode = aoPass;
postProcessing.outputNode = blendPassDenoise;

} else {

postProcessing.outputNode = scenePassColor;
postProcessing.outputNode = blendPassAO;

}

postProcessing.needsUpdate = true;
} else {

postProcessing.outputNode = scenePassColor;

}

postProcessing.needsUpdate = true;

} );

}

function updateParameters() {

aoPass.blendIntensity.value = params.blendIntensity;
aoPass.distanceExponent.value = params.distanceExponent;
aoPass.distanceFallOff.value = params.distanceFallOff;
aoPass.radius.value = params.radius;
Expand All @@ -155,6 +174,38 @@

}

function generateNoise( size = 64 ) {

const simplex = new SimplexNoise();

const arraySize = size * size * 4;
const data = new Uint8Array( arraySize );

for ( let i = 0; i < size; i ++ ) {

for ( let j = 0; j < size; j ++ ) {

const x = i;
const y = j;

data[ ( i * size + j ) * 4 ] = ( simplex.noise( x, y ) * 0.5 + 0.5 ) * 255;
data[ ( i * size + j ) * 4 + 1 ] = ( simplex.noise( x + size, y ) * 0.5 + 0.5 ) * 255;
data[ ( i * size + j ) * 4 + 2 ] = ( simplex.noise( x, y + size ) * 0.5 + 0.5 ) * 255;
data[ ( i * size + j ) * 4 + 3 ] = ( simplex.noise( x + size, y + size ) * 0.5 + 0.5 ) * 255;

}

}

const noiseTexture = new THREE.DataTexture( data, size, size );
noiseTexture.wrapS = THREE.RepeatWrapping;
noiseTexture.wrapT = THREE.RepeatWrapping;
noiseTexture.needsUpdate = true;

return noiseTexture;

}

function onWindowResize() {

const width = window.innerWidth;
Expand Down
43 changes: 13 additions & 30 deletions src/nodes/display/GTAONode.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ import { Color } from '../../math/Color.js';

const _quadMesh = new QuadMesh();
const _currentClearColor = new Color();
const _size = new Vector2();

class GTAONode extends TempNode {

constructor( textureNode, depthNode, normalNode, camera ) {
constructor( depthNode, normalNode, camera ) {

super();

this.textureNode = textureNode;
this.depthNode = depthNode;
this.normalNode = normalNode;

Expand All @@ -36,7 +36,6 @@ class GTAONode extends TempNode {
this.distanceExponent = uniform( 1 );
this.distanceFallOff = uniform( 1 );
this.scale = uniform( 1 );
this.blendIntensity = uniform( 1 );
this.noiseNode = texture( generateMagicSquareNoise() );

this.cameraProjectionMatrix = uniform( camera.projectionMatrix );
Expand All @@ -50,7 +49,13 @@ class GTAONode extends TempNode {
this._material = null;
this._textureNode = passTexture( this, this._aoRenderTarget.texture );

this.updateBeforeType = NodeUpdateType.RENDER;
this.updateBeforeType = NodeUpdateType.FRAME;

}

getTextureNode() {

return this._textureNode;

}

Expand All @@ -65,25 +70,16 @@ class GTAONode extends TempNode {

const { renderer } = frame;

const textureNode = this.textureNode;
const map = textureNode.value;
const size = renderer.getSize( _size );

const currentRenderTarget = renderer.getRenderTarget();
const currentMRT = renderer.getMRT();
renderer.getClearColor( _currentClearColor );
const currentClearAlpha = renderer.getClearAlpha();


const currentTexture = textureNode.value;

_quadMesh.material = this._material;

this.setSize( map.image.width, map.image.height );


const textureType = map.type;

this._aoRenderTarget.texture.type = textureType;
this.setSize( size.width, size.height );

// clear

Expand All @@ -100,17 +96,13 @@ class GTAONode extends TempNode {
renderer.setRenderTarget( currentRenderTarget );
renderer.setMRT( currentMRT );
renderer.setClearColor( _currentClearColor, currentClearAlpha );
textureNode.value = currentTexture;

}

setup( builder ) {

const { textureNode } = this;

const uvNode = uv();

const sampleTexture = ( uv ) => textureNode.uv( uv );
const sampleDepth = ( uv ) => this.depthNode.uv( uv ).x;
const sampleNoise = ( uv ) => this.noiseNode.uv( uv );

Expand Down Expand Up @@ -223,22 +215,13 @@ class GTAONode extends TempNode {

} );

const composite = tslFn( () => {

const beauty = sampleTexture( uvNode );
const ao = this._textureNode.uv( uvNode );

return beauty.mul( mix( vec3( 1.0 ), ao, this.blendIntensity ) );

} );

const material = this._material || ( this._material = builder.createNodeMaterial() );
material.fragmentNode = ao().context( builder.getSharedContext() );
material.needsUpdate = true;

//

return composite();
return this._textureNode;

}

Expand Down Expand Up @@ -328,7 +311,7 @@ function generateMagicSquare( size ) {

}

export const ao = ( node, depthNode, normalNode, camera ) => nodeObject( new GTAONode( nodeObject( node ).toTexture(), nodeObject( depthNode ), nodeObject( normalNode ), camera ) );
export const ao = ( depthNode, normalNode, camera ) => nodeObject( new GTAONode( nodeObject( depthNode ), nodeObject( normalNode ), camera ) );

addNodeElement( 'ao', ao );

Expand Down