5

I'm stuck on this problem and have been working on it and researching it for hours now.

I'm trying to render my scene, using EffectComposer, so that my background objects don't have SSAO (in my real project, it's a procedural city) and my foreground objects (which in my real project are two buildings I want to call out and that have a different material) DO have SSAO.

As you can see in the fiddle below, the blue cube (which is part of the bg scene) is covered by the SSAO render of the red cube (which is in the FG scene). Obviously, this effect is undesirable.

How do I get this to work properly?

Thanks!

-Adam


http://jsfiddle.net/Lbddvnsp/1/

var renderTargetParameters, renderTarget, renderBackground, renderModel, clearMask, renderMask, depthMaterial, depthTarget, composer;
var container, camera, bgScene, fgScene, renderer;

init();
initSSAO();
addObjects();
animate();

function initSSAO() {

    // Depth

    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;

    // Post-processing

    // create a custom render target with a stencil buffer
    // the stencil buffer allows for masking to take place
    renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat, stencilBuffer: true };
    renderTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, renderTargetParameters );
    composer = new THREE.EffectComposer( renderer, renderTarget );

    // add both foreground and background rendering to the composer
    renderBackground = new THREE.RenderPass( bgScene, camera );
    renderModel = new THREE.RenderPass( fgScene, camera );
    // set clear to false while rendering the model to preserve buffer data
    // the information in the stencil buffer is used for the masking pass
    renderModel.clear = false;

    clearMask = new THREE.ClearMaskPass();
    renderMask = new THREE.MaskPass( fgScene, camera );

    depthTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat } );

    var ssaoPass = new THREE.ShaderPass( THREE.SSAOShader );
    ssaoPass.uniforms[ 'tDepth' ].value = depthTarget;
    ssaoPass.uniforms[ 'size' ].value.set( window.innerWidth, window.innerHeight );
    ssaoPass.uniforms[ 'cameraNear' ].value = camera.near;
    ssaoPass.uniforms[ 'cameraFar' ].value = camera.far;
    ssaoPass.uniforms[ 'aoClamp' ].value = 0.4;
    //ssaoPass.renderToScreen = true;

    // fast aproximate anti-alising
    var fxaaPass = new THREE.ShaderPass( THREE.FXAAShader );
    fxaaPass.uniforms[ 'resolution' ].value.set( 1 / window.innerWidth, 1 / window.innerHeight );
    fxaaPass.renderToScreen = true;

    composer.addPass( renderBackground );
    composer.addPass( renderModel );
    composer.addPass( renderMask );
    composer.addPass( ssaoPass );
    composer.addPass( clearMask );
    composer.addPass( fxaaPass );
}

var cube;

function addObjects() {

    // Floor (background scene)
    var floorGeom = new THREE.PlaneGeometry(1000, 1000, 4, 4);
    var floorMat = new THREE.MeshPhongMaterial({color: 0xff0000});

    var floor = new THREE.Mesh(floorGeom, floorMat);
    floor.position.y = -120;
    floor.rotation.x = - 90 * Math.PI / 180;

    bgScene.add(floor);

    var cubeGeom = new THREE.CubeGeometry(100, 100, 100);
    var cubeMat = new THREE.MeshPhongMaterial({color: 0x0000ff});

    var cube2 = new THREE.Mesh(cubeGeom, cubeMat);
    cube2.position.x = 300;

    bgScene.add(cube2)

     // SSAO Objects (foreground scene)
    var cubeGeom = new THREE.CubeGeometry(200, 200, 200);
    var cubeMat = new THREE.MeshLambertMaterial({color: 0x00ff00});

    cube = new THREE.Mesh(cubeGeom, cubeMat);
    cube.rotation.x = - 90 * Math.PI / 180;

    fgScene.add(cube);

}

function init() {

    // Container

    container = document.createElement( 'div' );
    document.body.appendChild( container );

    // Scene 

    bgScene = new THREE.Scene();
    fgScene = new THREE.Scene();

    // Camera

    camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 40000 );
    camera.position.x = 2000;
    camera.position.y = 1000;
    camera.position.z = -1000;

    fgScene.add(camera);

    camera.lookAt( fgScene.position );

    // Lights
    // Screwed around with settings of all lights to get a similar feel to the deferred example

    var ambientLight = new THREE.AmbientLight( 0x404040 );
    ambientLight.color.setHSL( 0.1, 0.1, 0.4 );
    fgScene.add( ambientLight );
    bgScene.add(ambientLight.clone());

    var directionalLight = new THREE.DirectionalLight( 0xffffff );
    directionalLight.color.setHSL( 0.1, 0.1, 0.5 );
    directionalLight.position.x = 1000;
    directionalLight.position.y = 1000;
    directionalLight.position.z = 750;
    directionalLight.position.normalize();
    fgScene.add( directionalLight );
    bgScene.add(directionalLight.clone());

    var directionalLight2 = new THREE.DirectionalLight( 0x808080 );
    directionalLight2.color.setHSL( 0.1, 0.1, 0.45 );
    directionalLight2.position.x = - 1000;
    directionalLight2.position.y = 1000;
    directionalLight2.position.z = - 750;
    directionalLight2.position.normalize();
    fgScene.add( directionalLight2 );
    bgScene.add(directionalLight2.clone());

    var hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.65 );
    hemiLight.color.setHSL( 0.6, 0.35, 0.7 );
    hemiLight.groundColor.setHSL( 0.095, 0.5, 0.6 );
    hemiLight.position.set( 0, 600, 0 );
    fgScene.add( hemiLight );
    bgScene.add(hemiLight.clone());

    // Renderer

    renderer = new THREE.WebGLRenderer({
        antialias: false
    });
    renderer.autoClear = false;
    renderer.setSize( window.innerWidth, window.innerHeight );

    // Gamma settings make things look 'nicer' for some reason
    renderer.gammaInput = true;
    renderer.gammaOutput = true;

    //renderer.physicallyBasedShading = true;

    container.appendChild(renderer.domElement);

}

function render() {

    renderer.clear();
    //renderer.render( bgScene, camera );

    //renderer.clear( false, true, false );

    //camera.position.x += 1;
    camera.lookAt( cube.position );

    fgScene.overrideMaterial = depthMaterial;
    // set force clear to true here so the depth buffer is not preserved
    renderer.render( fgScene, camera, depthTarget, true );    
    fgScene.overrideMaterial = null;

    composer.render();

}

function animate() {

    window.requestAnimationFrame( animate );

    render();

}

Update:

I tried adding the bgScene with an override material of black to the depth target render, just to see if it would obscure the SSAO. http://jsfiddle.net/5d7Lk7eu/1/ -- though its hard to see in this fiddle (but I can see it in my real project scene)...whats actually rendering within the bgScene objects is a silhouette of the fgScene, and its no longer rendering the SSAO pass fully on top of the bgScene. So, I feel like I'm closer, but I'm still stuck.


Update 2:*

The following picture (where you can see that the Mars mask shows through the Earth) is perhaps a clearer visual example of the problem (though this one isn't using SSAO, but I believe the two problems are related):

example of issue

Adam Miskiewicz
  • 621
  • 6
  • 6

0 Answers0