I've been attempting to get the SSAO post-processing shader to work with the latest (r77) version of three.js. I've been using the EffectComposer, with the code entirely duplicated from the example page here:
http://threejs.org/examples/webgl_postprocessing_ssao.html
The relevant code being:
var renderPass = new THREE.RenderPass( Engine.scene, Engine.camera );
ssaoPass = new THREE.ShaderPass( THREE.SSAOShader );
ssaoPass.renderToScreen = true;
// ...various ShaderPass setup parameters
Engine.effectComposer = new THREE.EffectComposer( Engine.renderer );
Engine.effectComposer.addPass(renderPass);
Engine.effectComposer.addPass(ssaoPass);
The issue I have been having is that that SSAO doesn't seem to work with SkinnedMeshes. It seems to take into account the position of the meshes before the skinning calculations are performed.
It looks like this:
Problem with SSAO on SkinnedMesh
Does anyone have any experience with this on the latest version? I've looked all over the place, but can't find any documentation about how to start fixing this at all.
I found mention of a fix for this in another SO post ( ThreeJS SSAO Shader w/ Skinned/Animated Models ), but the solution has been deprecated.
Thanks in advance, and happy to go into more detail if needed.
As requested, here is the complete code for the simple demo page :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="js/libs/jquery.min.js"></script>
<script type="text/javascript" src="js/libs/three.min.js"></script>
<script type="text/javascript" src="js/libs/postprocessing/CopyShader.js"></script>
<script type="text/javascript" src="js/libs/postprocessing/EffectComposer.js"></script>
<script type="text/javascript" src="js/libs/postprocessing/MaskPass.js"></script>
<script type="text/javascript" src="js/libs/postprocessing/RenderPass.js"></script>
<script type="text/javascript" src="js/libs/postprocessing/ShaderPass.js"></script>
<script type="text/javascript" src="js/libs/postprocessing/DotScreenShader.js"></script>
<script type="text/javascript" src="js/libs/postprocessing/SSAOShader.js"></script>
<link rel="stylesheet" type="text/css" href="demo.css" />
</head>
<body>
<div id="demo-container"></div>
</body>
</html>
<script>
$(document).ready(function() {
window.doPostPro = 0;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 1, 1000);
camera.position.set(0, 200, 200);
camera.lookAt(new THREE.Vector3(0, 0, 0));
clock = new THREE.Clock();
// Setup the renderer.
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xFFFFFF );
function setupPostProcessing() {
// Setup render pass
var renderPass = new THREE.RenderPass( scene, camera );
// Setup depth pass
depthMaterial = new THREE.MeshDepthMaterial();
depthMaterial.depthPacking = THREE.RGBADepthPacking;
depthMaterial.blending = THREE.NoBlending;
depthRenderTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
stencilBuffer: true
});
// Setup SSAO pass
ssaoPass = new THREE.ShaderPass( THREE.SSAOShader );
ssaoPass.renderToScreen = true;
//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[ 'onlyAO' ].value = ( postprocessing.renderMode == 1 );
ssaoPass.uniforms[ 'aoClamp' ].value = 0.3;
ssaoPass.uniforms[ 'lumInfluence' ].value = 0.5;
// Add pass to effect composer
effectComposer = new THREE.EffectComposer( renderer );
effectComposer.addPass( renderPass );
effectComposer.addPass( ssaoPass );
};
setupPostProcessing();
// Load the mesh.
var loader = new THREE.JSONLoader();
loader.load( "js/zombie.js", function( geometry, materials ) {
var originalMaterial = materials[ 0 ];
originalMaterial.skinning = true;
geometry.computeVertexNormals();
var mesh = new THREE.SkinnedMesh(geometry, originalMaterial);
window.animMixer = new THREE.AnimationMixer(mesh);
var animAction = animMixer.clipAction(geometry.animations[0]);
animAction.play();
scene.add(mesh);
});
var ambientLight = new THREE.AmbientLight( 0xCCCCCC );
scene.add( ambientLight );
$("#demo-container").append( renderer.domElement );
function render() {
if ( doPostPro ) {
// Render depth into depthRenderTarget
scene.overrideMaterial = depthMaterial;
renderer.render( scene, camera, depthRenderTarget, true );
// Render renderPass and SSAO shaderPass
scene.overrideMaterial = null;
effectComposer.render();
}
else {
renderer.render( scene, camera );
}
}
function animate() {
requestAnimationFrame( animate );
if ( window.animMixer != undefined ) {
var deltaTime = clock.getDelta();
animMixer.update(deltaTime);
}
render();
}
animate();
$(document).keyup(function(e) {
// P is pressed.
if ( e.which == 80 ) {
window.doPostPro = !window.doPostPro;
}
});
});
</script>
If you are skinning, and using this pattern in your render loop
// Render depth into depthRenderTarget
scene.overrideMaterial = depthMaterial;
renderer.render( scene, camera, depthRenderTarget, true );
you have to make sure to set
depthMaterial.skinning = true;
Thing is, if there are other elements in the scene that are not skinned, doing so will throw errors. In which case, this may be a three.js design issue that will have to be addressed.
three.js r.77
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.