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

SAOPass: Improve performance, fix visuals. #26599

Merged
merged 2 commits into from
Aug 18, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
121 changes: 23 additions & 98 deletions examples/jsm/postprocessing/SAOPass.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import {
DstAlphaFactor,
DstColorFactor,
HalfFloatType,
MeshDepthMaterial,
MeshNormalMaterial,
NearestFilter,
NoBlending,
RGBADepthPacking,
ShaderMaterial,
UniformsUtils,
UnsignedShortType,
DepthStencilFormat,
UnsignedInt248Type,
Vector2,
WebGLRenderTarget,
ZeroFactor
Expand All @@ -23,15 +22,14 @@ import { SAOShader } from '../shaders/SAOShader.js';
import { DepthLimitedBlurShader } from '../shaders/DepthLimitedBlurShader.js';
import { BlurShaderUtils } from '../shaders/DepthLimitedBlurShader.js';
import { CopyShader } from '../shaders/CopyShader.js';
import { UnpackDepthRGBAShader } from '../shaders/UnpackDepthRGBAShader.js';

/**
* SAO implementation inspired from bhouston previous SAO work
*/

class SAOPass extends Pass {

constructor( scene, camera, useDepthTexture = false, useNormals = false, resolution = new Vector2( 256, 256 ) ) {
constructor( scene, camera, resolution = new Vector2( 256, 256 ) ) {

super();

Expand All @@ -41,9 +39,6 @@ class SAOPass extends Pass {
this.clear = true;
this.needsSwap = false;

this.supportsDepthTextureExtension = useDepthTexture;
this.supportsNormalTexture = useNormals;

this.originalClearColor = new Color();
this._oldClearColor = new Color();
this.oldClearAlpha = 1;
Expand All @@ -65,30 +60,17 @@ class SAOPass extends Pass {

this.saoRenderTarget = new WebGLRenderTarget( this.resolution.x, this.resolution.y, { type: HalfFloatType } );
this.blurIntermediateRenderTarget = this.saoRenderTarget.clone();
this.beautyRenderTarget = this.saoRenderTarget.clone();

const depthTexture = new DepthTexture();
depthTexture.format = DepthStencilFormat;
depthTexture.type = UnsignedInt248Type;

this.normalRenderTarget = new WebGLRenderTarget( this.resolution.x, this.resolution.y, {
minFilter: NearestFilter,
magFilter: NearestFilter,
type: HalfFloatType
type: HalfFloatType,
depthTexture: depthTexture
} );
this.depthRenderTarget = this.normalRenderTarget.clone();

let depthTexture;

if ( this.supportsDepthTextureExtension ) {

depthTexture = new DepthTexture();
depthTexture.type = UnsignedShortType;

this.beautyRenderTarget.depthTexture = depthTexture;
this.beautyRenderTarget.depthBuffer = true;

}

this.depthMaterial = new MeshDepthMaterial();
this.depthMaterial.depthPacking = RGBADepthPacking;
this.depthMaterial.blending = NoBlending;

this.normalMaterial = new MeshNormalMaterial();
this.normalMaterial.blending = NoBlending;
Expand All @@ -100,10 +82,8 @@ class SAOPass extends Pass {
uniforms: UniformsUtils.clone( SAOShader.uniforms )
} );
this.saoMaterial.extensions.derivatives = true;
this.saoMaterial.defines[ 'DEPTH_PACKING' ] = this.supportsDepthTextureExtension ? 0 : 1;
this.saoMaterial.defines[ 'NORMAL_TEXTURE' ] = this.supportsNormalTexture ? 1 : 0;
this.saoMaterial.defines[ 'PERSPECTIVE_CAMERA' ] = this.camera.isPerspectiveCamera ? 1 : 0;
this.saoMaterial.uniforms[ 'tDepth' ].value = ( this.supportsDepthTextureExtension ) ? depthTexture : this.depthRenderTarget.texture;
this.saoMaterial.uniforms[ 'tDepth' ].value = depthTexture;
this.saoMaterial.uniforms[ 'tNormal' ].value = this.normalRenderTarget.texture;
this.saoMaterial.uniforms[ 'size' ].value.set( this.resolution.x, this.resolution.y );
this.saoMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.copy( this.camera.projectionMatrixInverse );
Expand All @@ -116,10 +96,10 @@ class SAOPass extends Pass {
vertexShader: DepthLimitedBlurShader.vertexShader,
fragmentShader: DepthLimitedBlurShader.fragmentShader
} );
this.vBlurMaterial.defines[ 'DEPTH_PACKING' ] = this.supportsDepthTextureExtension ? 0 : 1;
this.vBlurMaterial.defines[ 'DEPTH_PACKING' ] = 0;
this.vBlurMaterial.defines[ 'PERSPECTIVE_CAMERA' ] = this.camera.isPerspectiveCamera ? 1 : 0;
this.vBlurMaterial.uniforms[ 'tDiffuse' ].value = this.saoRenderTarget.texture;
this.vBlurMaterial.uniforms[ 'tDepth' ].value = ( this.supportsDepthTextureExtension ) ? depthTexture : this.depthRenderTarget.texture;
this.vBlurMaterial.uniforms[ 'tDepth' ].value = depthTexture;
this.vBlurMaterial.uniforms[ 'size' ].value.set( this.resolution.x, this.resolution.y );
this.vBlurMaterial.blending = NoBlending;

Expand All @@ -129,10 +109,10 @@ class SAOPass extends Pass {
vertexShader: DepthLimitedBlurShader.vertexShader,
fragmentShader: DepthLimitedBlurShader.fragmentShader
} );
this.hBlurMaterial.defines[ 'DEPTH_PACKING' ] = this.supportsDepthTextureExtension ? 0 : 1;
this.hBlurMaterial.defines[ 'DEPTH_PACKING' ] = 0;
this.hBlurMaterial.defines[ 'PERSPECTIVE_CAMERA' ] = this.camera.isPerspectiveCamera ? 1 : 0;
this.hBlurMaterial.uniforms[ 'tDiffuse' ].value = this.blurIntermediateRenderTarget.texture;
this.hBlurMaterial.uniforms[ 'tDepth' ].value = ( this.supportsDepthTextureExtension ) ? depthTexture : this.depthRenderTarget.texture;
this.hBlurMaterial.uniforms[ 'tDepth' ].value = depthTexture;
this.hBlurMaterial.uniforms[ 'size' ].value.set( this.resolution.x, this.resolution.y );
this.hBlurMaterial.blending = NoBlending;

Expand All @@ -153,13 +133,6 @@ class SAOPass extends Pass {
this.materialCopy.blendDstAlpha = ZeroFactor;
this.materialCopy.blendEquationAlpha = AddEquation;

this.depthCopy = new ShaderMaterial( {
uniforms: UniformsUtils.clone( UnpackDepthRGBAShader.uniforms ),
vertexShader: UnpackDepthRGBAShader.vertexShader,
fragmentShader: UnpackDepthRGBAShader.fragmentShader,
blending: NoBlending
} );

this.fsQuad = new FullScreenQuad( null );

}
Expand All @@ -176,20 +149,11 @@ class SAOPass extends Pass {

}

if ( this.params.output === 1 ) {

return;

}

renderer.getClearColor( this._oldClearColor );
this.oldClearAlpha = renderer.getClearAlpha();
const oldAutoClear = renderer.autoClear;
renderer.autoClear = false;

renderer.setRenderTarget( this.depthRenderTarget );
renderer.clear();

this.saoMaterial.uniforms[ 'bias' ].value = this.params.saoBias;
this.saoMaterial.uniforms[ 'intensity' ].value = this.params.saoIntensity;
this.saoMaterial.uniforms[ 'scale' ].value = this.params.saoScale;
Expand Down Expand Up @@ -218,26 +182,8 @@ class SAOPass extends Pass {

}

// Rendering scene to depth texture
renderer.setClearColor( 0x000000 );
renderer.setRenderTarget( this.beautyRenderTarget );
renderer.clear();
renderer.render( this.scene, this.camera );

// Re-render scene if depth texture extension is not supported
if ( ! this.supportsDepthTextureExtension ) {

// Clear rule : far clipping plane in both RGBA and Basic encoding
this.renderOverride( renderer, this.depthMaterial, this.depthRenderTarget, 0x000000, 1.0 );

}

if ( this.supportsNormalTexture ) {

// Clear rule : default normal is facing the camera
this.renderOverride( renderer, this.normalMaterial, this.normalRenderTarget, 0x7777ff, 1.0 );

}
// render normal and depth
this.renderOverride( renderer, this.normalMaterial, this.normalRenderTarget, 0x7777ff, 1.0 );

// Rendering SAO texture
this.renderPass( renderer, this.saoMaterial, this.saoRenderTarget, 0xffffff, 1.0 );
Expand All @@ -250,24 +196,10 @@ class SAOPass extends Pass {

}

let outputMaterial = this.materialCopy;
// Setting up SAO rendering
if ( this.params.output === 3 ) {

if ( this.supportsDepthTextureExtension ) {

this.materialCopy.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.depthTexture;
this.materialCopy.needsUpdate = true;
const outputMaterial = this.materialCopy;

} else {

this.depthCopy.uniforms[ 'tDiffuse' ].value = this.depthRenderTarget.texture;
this.depthCopy.needsUpdate = true;
outputMaterial = this.depthCopy;

}

} else if ( this.params.output === 4 ) {
// Setting up SAO rendering
if ( this.params.output === SAOPass.OUTPUT.Normal ) {

this.materialCopy.uniforms[ 'tDiffuse' ].value = this.normalRenderTarget.texture;
this.materialCopy.needsUpdate = true;
Expand All @@ -279,8 +211,8 @@ class SAOPass extends Pass {

}

// Blending depends on output, only want a CustomBlending when showing SAO
if ( this.params.output === 0 ) {
// Blending depends on output
if ( this.params.output === SAOPass.OUTPUT.Default ) {

outputMaterial.blending = CustomBlending;

Expand Down Expand Up @@ -359,11 +291,9 @@ class SAOPass extends Pass {

setSize( width, height ) {

this.beautyRenderTarget.setSize( width, height );
this.saoRenderTarget.setSize( width, height );
this.blurIntermediateRenderTarget.setSize( width, height );
this.normalRenderTarget.setSize( width, height );
this.depthRenderTarget.setSize( width, height );

this.saoMaterial.uniforms[ 'size' ].value.set( width, height );
this.saoMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.copy( this.camera.projectionMatrixInverse );
Expand All @@ -382,17 +312,14 @@ class SAOPass extends Pass {

this.saoRenderTarget.dispose();
this.blurIntermediateRenderTarget.dispose();
this.beautyRenderTarget.dispose();
this.normalRenderTarget.dispose();
this.depthRenderTarget.dispose();

this.depthMaterial.dispose();
this.normalMaterial.dispose();
this.saoMaterial.dispose();
this.vBlurMaterial.dispose();
this.hBlurMaterial.dispose();
this.materialCopy.dispose();
this.depthCopy.dispose();

this.fsQuad.dispose();

Expand All @@ -401,11 +328,9 @@ class SAOPass extends Pass {
}

SAOPass.OUTPUT = {
'Beauty': 1,
'Default': 0,
'SAO': 2,
'Depth': 3,
'Normal': 4
'SAO': 1,
'Normal': 2
};

export { SAOPass };
13 changes: 0 additions & 13 deletions examples/jsm/shaders/SAOShader.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ const SAOShader = {
defines: {
'NUM_SAMPLES': 7,
'NUM_RINGS': 4,
'NORMAL_TEXTURE': 0,
'DIFFUSE_TEXTURE': 0,
'DEPTH_PACKING': 1,
'PERSPECTIVE_CAMERA': 1
},
uniforms: {
Expand Down Expand Up @@ -56,10 +54,7 @@ const SAOShader = {
#endif

uniform sampler2D tDepth;

#if NORMAL_TEXTURE == 1
uniform sampler2D tNormal;
#endif

uniform float cameraNear;
uniform float cameraFar;
Expand Down Expand Up @@ -87,11 +82,7 @@ const SAOShader = {
}

float getDepth( const in vec2 screenPosition ) {
#if DEPTH_PACKING == 1
return unpackRGBAToDepth( texture2D( tDepth, screenPosition ) );
#else
return texture2D( tDepth, screenPosition ).x;
#endif
}

float getViewZ( const in float depth ) {
Expand All @@ -111,11 +102,7 @@ const SAOShader = {
}

vec3 getViewNormal( const in vec3 viewPosition, const in vec2 screenPosition ) {
#if NORMAL_TEXTURE == 1
return unpackRGBToNormal( texture2D( tNormal, screenPosition ).xyz );
#else
return normalize( cross( dFdx( viewPosition ), dFdy( viewPosition ) ) );
#endif
}

float scaleDividedByCameraFar;
Expand Down
Binary file modified examples/screenshots/webgl_postprocessing_sao.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 7 additions & 10 deletions examples/webgl_postprocessing_sao.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,11 @@
container = document.createElement( 'div' );
document.body.appendChild( container );

const width = window.innerWidth || 1;
const height = window.innerHeight || 1;
const devicePixelRatio = window.devicePixelRatio || 1;
const width = window.innerWidth;
const height = window.innerHeight;

renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setClearColor( 0x000000 );
renderer.setPixelRatio( devicePixelRatio );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( width, height );
document.body.appendChild( renderer.domElement );

Expand Down Expand Up @@ -117,18 +115,16 @@
composer = new EffectComposer( renderer );
renderPass = new RenderPass( scene, camera );
composer.addPass( renderPass );
saoPass = new SAOPass( scene, camera, false, true );
saoPass = new SAOPass( scene, camera );
composer.addPass( saoPass );
const outputPass = new OutputPass();
composer.addPass( outputPass );

// Init gui
const gui = new GUI();
gui.add( saoPass.params, 'output', {
'Beauty': SAOPass.OUTPUT.Beauty,
'Beauty+SAO': SAOPass.OUTPUT.Default,
'SAO': SAOPass.OUTPUT.SAO,
'Depth': SAOPass.OUTPUT.Depth,
'Default': SAOPass.OUTPUT.Default,
'SAO Only': SAOPass.OUTPUT.SAO,
'Normal': SAOPass.OUTPUT.Normal
} ).onChange( function ( value ) {

Expand All @@ -144,6 +140,7 @@
gui.add( saoPass.params, 'saoBlurRadius', 0, 200 );
gui.add( saoPass.params, 'saoBlurStdDev', 0.5, 150 );
gui.add( saoPass.params, 'saoBlurDepthCutoff', 0.0, 0.1 );
gui.add( saoPass, 'enabled' );

window.addEventListener( 'resize', onWindowResize );

Expand Down