简体   繁体   中英

ThreeJS SSAO with SSAA

i'd like to integrate the SSAO-Shader (Screen Space Ambient Occlusion) into my antialiasing render stack (Super Sampling Anti-Aliasing). The AA is necessary for high-quality rendering, the default antialiasing delivered by my gpu isn't always sufficient. Now i've already integrated SSAO into the usual render process, but my new goal is to combine both techniques.

For this, i've set up a fiddle. The first EffectComposer renders the scene onto a renderTarget with twice the resolution of the canvas. From this, i'd like to use the depthTarget for SSAO. The final step is to draw the rendered image to a plane with the size of the canvas, which results in downsampling, so we have the antialiasing effect.

Link to the fiddle: SSAO+SSAA

The stack is set up like this:

function initManualAntiAliasing2(width, height, wStepMax, hStepMax) {

    var parameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };

    // render image with double size
    var rw1 = wStepMax * width;
    var rh1 = hStepMax * height;
    var myRenderTarget1 = new THREE.WebGLRenderTarget( rw1, rh1, parameters );
    var myRenderTargetSSAO = new THREE.WebGLRenderTarget( rw1, rh1, parameters );

    composer = new THREE.EffectComposer( renderer, myRenderTarget1 );
    var renderPass = new THREE.RenderPass(scene, camera);
    composer.addPass(renderPass);

    var renderSceneSSAO = new THREE.TexturePass(composer.renderTarget2);

    composerSSAO = new THREE.EffectComposer( renderer, myRenderTargetSSAO );
    composerSSAO.addPass(renderSceneSSAO);


    var depthShader = THREE.ShaderLib[ "depthRGBA" ];
    var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );

    depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } );
    depthMaterial.blending = THREE.NoBlending;

    var parametersDepth = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat };

    myRenderTargetDepth = new THREE.WebGLRenderTarget( rw1, rh1, parametersDepth );

    ssaoEffect = new THREE.ShaderPass( THREE.SSAOShader );
    ssaoEffect.uniforms[ 'tDepth' ].value = myRenderTargetDepth;
    ssaoEffect.uniforms[ 'size' ].value.set( rw1, rh1 );
    ssaoEffect.uniforms[ 'cameraNear' ].value = camera.near;
    ssaoEffect.uniforms[ 'cameraFar' ].value = camera.far;
    ssaoEffect.uniforms[ 'aoClamp' ].value = 0.4;
    ssaoEffect.uniforms[ 'lumInfluence' ].value = 0.4;
    ssaoEffect.uniforms[ 'onlyAO' ].value = 1; // debug: when ssao shader works, we will definitely see it with this option
    ssaoEffect.renderToScreen = true;
    composerSSAO.addPass( ssaoEffect );

    var renderScene1 = new THREE.TexturePass(composer.renderTarget2);

    // sample down to screen size
    composer1 = new THREE.EffectComposer(renderer);
    composer1.addPass(renderScene1);

    var renderScene2 = new THREE.TexturePass(composer1.renderTarget2);

    var effectCopy = new THREE.ShaderPass( THREE.CopyShader );
    effectCopy.renderToScreen = true;
    composer1.addPass(effectCopy);
}

The render function is set up like this:

function renderAA2() {
    renderer.autoClear = false;
    renderer.clear();
    scene.overrideMaterial = myRenderTargetDepth;
    composer.render();
    composerSSAO.render();
    scene.overrideMaterial = null;
    composer1.render();
}

I have not found a similar situation, so my question: how to set up the whole stack, so that ssao is used.

Greetings, Thomas

If anyone is still looking for a solution i succeed in combine the SSAO pass with the MSAA pass by using the two examples available on three.js website.

Here is how the code appears:

function initPostprocessing() {
    // Setup render pass
    var renderPass = new THREE.RenderPass( scene, camera );
    effectComposer = new THREE.EffectComposer( renderer );

    // Setup depth pass
    depthMaterial = new THREE.MeshDepthMaterial();
    depthMaterial.depthPacking = THREE.RGBADepthPacking;
    depthMaterial.blending = THREE.NoBlending;

    var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter,format: THREE.RGBAFormat, stencilBuffer: false };
    depthRenderTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, pars );

    // Setup Anti Aliasing pass
    msaaRenderPass = new THREE.ManualMSAARenderPass( scene, camera );
    msaaRenderPass.unbiased = false;
    msaaRenderPass.sampleLevel = 2;

    // Setup Ambient Occlusion pass
    ssaoPass = new THREE.ShaderPass( THREE.SSAOShader );
    ssaoPass.renderToScreen = true;
    ssaoPass.uniforms[ 'tDepth' ].value = depthRenderTarget.texture;
    ssaoPass.uniforms[ 'size' ].value.set( window.innerWidth, window.innerHeight );
    ssaoPass.uniforms[ 'cameraNear' ].value = camera.near;
    ssaoPass.uniforms[ 'cameraFar' ].value = camera.far;
    ssaoPass.uniforms[ 'onlyAO' ].value = false;
    ssaoPass.uniforms[ 'aoClamp' ].value = 1.0;
    ssaoPass.uniforms[ 'lumInfluence' ].value = 0.7;

    effectComposer.addPass( renderPass );
    effectComposer.addPass( msaaRenderPass );
    effectComposer.addPass( ssaoPass );
}
function updatePostprocessing() {
    scene.overrideMaterial = depthMaterial;
    renderer.render( scene, camera, depthRenderTarget, true );
    scene.overrideMaterial = null;
    effectComposer.render();
}

The two examples mixed in this code are:

https://threejs.org/examples/?q=post#webgl_postprocessing_msaa

https://threejs.org/examples/?q=post#webgl_postprocessing_ssao

I hope it could help somebody else 'cause it took me hours to solve this problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM