SSAO и несколько сцен в Three.JS
Я застрял в этой проблеме и работаю над ней и исследую ее в течение нескольких часов.
Я пытаюсь визуализировать свою сцену, используя EffectComposer, чтобы мои фоновые объекты не имели SSAO (в моем реальном проекте это процедурный город) и мои объекты переднего плана (которые в моем реальном проекте - это два здания, которые я хочу назвать и что есть другой материал) есть SSAO.
Как вы можете видеть на скрипте ниже, синий куб (который является частью сцены bg) покрыт рендерингом красного куба SSAO (который находится в сцене FG). Очевидно, что этот эффект нежелателен.
Как мне заставить это работать должным образом?
Спасибо!
-Адам
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();
}
Обновить:
Я попытался добавить bgScene с материалом переопределения черного к целевому рендеру глубины, просто чтобы увидеть, не затеняет ли он SSAO. http://jsfiddle.net/5d7Lk7eu/1/ - хотя это трудно увидеть в этой скрипке (но я вижу это в моей реальной сцене проекта)... что на самом деле рендеринг в объектах bgScene является силуэтом fgScene и он больше не передает SSAO полностью поверх bgScene. Итак, я чувствую, что я ближе, но я все еще застрял.
Обновление 2:*
Следующая картина (где видно, что маска Марса видна сквозь Землю), возможно, является более наглядным примером проблемы (хотя эта не использует SSAO, но я полагаю, что эти две проблемы связаны):