Three.js: Apply SSAO (Screen Space Ambient Occlusion) to Displacement map

2.1k views Asked by At

have I've implemented the Screen Space Ambient Occlusion in my Three.js project correctly, and run perfect, like this:

//Setup SSAO 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: true }; //Stancilbuffer true because not effect transparent object
depthRenderTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, pars);
depthRenderTarget.texture.name = "SSAOShader.rt";
ssaoPass = new THREE.ShaderPass(THREE.SSAOShader);
///////ssaoPass.uniforms[ "tDiffuse" ].value will be set by ShaderPass
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['radius'].value = radius;
ssaoPass.uniforms['aoClamp'].value = aoClamp;
ssaoPass.uniforms['lumInfluence'].value = lumInfluence;

But, when I set a material with displacementMap (that run correctly without SSAO enabled), this is the result. Notice that the SSAO is applied "correctly" to the original sphere (with a strange-trasparent-artificat), but I need to apply it to the "displaced vertex" of the sphere)

Incorrect SSAO

This is my composer passes:

   //Main render scene pass
    postprocessingComposer.addPass(renderScene);

    //Post processing pass
    if (ssaoPass) {
        postprocessingComposer.addPass(ssaoPass);
    }

And this is the rendering loop with composer

if (postprocessingComposer) {

    if (ssaoPass) {

        //Render depth into depthRenderTarget
        scene.overrideMaterial = depthMaterial;
        renderer.render(scene, camera, depthRenderTarget, true);

        //Render composer
        scene.overrideMaterial = null;
        postprocessingComposer.render();

        renderer.clearDepth();
        renderer.render(sceneOrtho, cameraOrtho);
    }
    else {
        //Render loop with post processing (no SSAO, becasue need more checks, see above)
        renderer.clear();
        postprocessingComposer.render();        
        renderer.clearDepth();
        renderer.render(sceneOrtho, cameraOrtho);
    }
}
else {
    //Simple render loop (no post-processing)
    renderer.clear();
    renderer.render(scene, camera);
    renderer.clearDepth();
    renderer.render(sceneOrtho, cameraOrtho);
}

How can i archive a correct Screen Space Ambient Occlusion applied to a mesh with Displacement Map? Thanks.

[UPDATE]: After some work i tried to this procedure for every child in the scene, with displacement map, to define a new a new overrideMaterial of the scene equal to a depthMaterial with displacement map parameters of the child material.

                    var myDepthMaterial = new THREE.MeshDepthMaterial({
                        depthPacking: THREE.RGBADepthPacking,
                        displacementMap: child.material.displacementMap,
                        displacementScale: child.material.displacementScale,
                        displacementBias: child.material.displacementBias
                    });
                    child.onBeforeRender = function (renderer, scene, camera, geometry, material, group) {
                        scene.overrideMaterial = myDepthMaterial;     
                    };

This solution sounds good, but doesnt work.

1

There are 1 answers

8
WestLangley On

You are using SSAO with a displacement map. You need to specify the displacement map when you instantiate the depth material.

depthMaterial = new THREE.MeshDepthMaterial( {

    depthPacking: THREE.RGBADepthPacking,

    displacementMap: displacementMap,
    displacementScale: displacementScale,
    displacementBias: displacementBias

} );

three.js r.87