Achieving successful implementation of SSAO shader on SkinnedMesh models

Trying to implement the SSAO post-processing shader with the most recent version (r77) of three.js has been a challenge for me. I have been utilizing the EffectComposer, with the code completely replicated from the example page provided here:

The specific code snippet is as follows:

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 challenge I've encountered is that the SSAO functionality does not seem to work properly with SkinnedMeshes. It appears to consider the position of the meshes prior to the skinning calculations being executed.

Here is an illustration of the issue:

Problem with SSAO on SkinnedMesh

If anyone has dealt with this issue on the latest version, I would greatly appreciate any insights or guidance. I have searched extensively but have been unable to find any documentation on how to address this.

I came across a solution to this problem in another Stack Overflow post (ThreeJS SSAO Shader w/ Skinned/Animated Models), but unfortunately, the solution has been deprecated.

Thank you in advance, and I am willing to provide more details if necessary.

As requested, here is the complete code for the basic 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();

    // Renderer setup
    renderer = new THREE.WebGLRenderer({
        antialias: true
    });
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.setClearColor( 0xFFFFFF );

    function setupPostProcessing() {

        // Render pass setup
        var renderPass = new THREE.RenderPass( scene, camera );

        // Depth pass setup
        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
        });

        // SSAO pass setup
        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[ '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();

    // Mesh loading
    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 ) {

            scene.overrideMaterial = depthMaterial;
            renderer.render( scene, camera, depthRenderTarget, true );

            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) {

        if ( e.which == 80 ) {

            window.doPostPro = !window.doPostPro;
        }
    });

});



</script>

Answer №1

If you are working on skinning and incorporating this specific pattern into your render loop

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

it is crucial to ensure that you set

depthMaterial.skinning = true;

However, if there are other elements in the scene that are not skinned, this action may result in errors. This could potentially be a design flaw within the three.js framework that needs to be resolved.

Version: three.js r.77

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Inheritance through Parasitism in JavaScript

Just finished a Douglas Crockford lecture where he introduced the concept of parasitic inheritance in JavaScript. This involves one constructor calling another to modify the object. The code example he provided is: function gizmo(id, secret) { secret = ...

"Proceeding without waiting for resolution from a Promise's `.then`

I am currently integrating Google Identity Services for login on my website. I am facing an issue where the .then function is being executed before the Promise returned by the async function is resolved. I have temporarily used setTimeout to manage this, b ...

I'm only appending the final element to the JavaScript array

Currently, I have the following code: I'm endeavoring to create a new JSON object named dataJSON by utilizing properties from the GAJSON object. However, my issue arises when attempting to iterate over the GAJSOn object; only its last element is added ...

Using asynchronous functions in a loop in Node.js

Although this question may have been asked before, I am struggling to understand how things work and that is why I am starting a new thread. con.query(sql,[req.params.quizId],(err,rows,fields)=>{ //rows contains questions if(err) throw err; ...

Issue with toggling functionality in Vue.js between two identical components

Within the template of another component, I have two components that can be toggled based on clicks on "reply" and "edit" buttons. <comment-form :model="model" :model-id="modelId" :comment="comment" v-if="showEditForm && canComment" @closeForm= ...

Fade background when the youtube video in the iframe begins playing

Hey there! I'm looking to create a cool effect on my (wordpress) site where the background dims when a YouTube video starts playing. The video is embedded in this way: <iframe frameborder="0" width="660" height="371" allowfullscreen="" src="https ...

Discovering Unconventional Columns Through Sharepoint REST Api Filtration

I am working on recreating SharePoint's front end in my app and want to add columns to my table just like a user would in SP. The challenge I am facing is determining which columns were custom generated by the user rather than standard ones. Although ...

What are the steps to implement camera controls using datgui in three.js?

Is there a more efficient method to incorporate dat-gui controls for the threejs camera in the basic threejs example provided on this page: https://github.com/mrdoob/three.js/ var camera, scene, renderer; var geometry, material, mesh; init(); animate(); ...

Transforming conversion code snippet from jQuery to Dojo - utilizing AJAX techniques

I am in the process of converting my code from jQuery to Dojo. I just need an equivalent snippet that works. The jQuery code is functioning properly, but the Dojo code is not working as expected. JQUERY <script type="text/javascript"> $(docume ...

Choosing the following choice using the Material-UI Select tool

Looking for a way to enhance my dropdown select from MUI in a Nextjs application by adding two arrows for navigating to the next/previous option. Here's what my code currently looks like: <StyledFormControl> <Select value={cu ...

Difficulty: Issue with displaying Backbone collection using Mustache template

I'm new to backbone js and Mustache. I want to load a backbone collection on page load from rails json object to avoid making an extra call. However, I'm facing issues when trying to render the backbone collection using a mustache template. Here ...

The compilation of PKG using Axios 1.x encounters an error

Despite attempting numerous strategies, I have not been successful. I developed a Node.js application with API requests managed using axios. However, I am unable to convert it into an executable file. Trying to downgrade Axios to version 0.27.0 resolved th ...

Dispatch keystrokes to a designated text field if they are not taken in by any other input

Is there a way to achieve the functionality seen in apps like Discord, where users can type into the message box even when it's not in focus? I am interested in implementing this feature only if no other input field on the page is currently focused. ...

Struggles with loading order in Knockout.JS

I've encountered an issue with loading my scripts properly for a page utilizing a knockout.js form. Upon page load, my viewmodel js file isn't immediately loaded, resulting in errors that cause the validation messages to flash and hidden divs to ...

Which is the better option: using a nonce for each function or one for all AJAX calls?

My approach to security in WordPress includes the use of nonces, which serve as an additional layer of protection. These nonces are essentially hashes that are sent to the server and change every few hours. If this hash is missing, the request will be dee ...

Reorganizing an array using a custom prioritized list

Is it possible to sort an array but override precedence for certain words by placing them at the end using a place_last_lookup array? input_place_last_lookup = ["not","in"]; input_array = [ "good", "in", "all&qu ...

When you click on the text, the calendar will pop up for you to

When the text "SetExpiryDate" is clicked, a date picker opens. After selecting a date, the text changes to "Expires ${date}" where the selected date is inserted. If no date is selected, the text remains as it is. I'm curious how I can implement this ...

Issue with scrolling functionality on dynamically inserted items in jQuery mobile list

I have encountered an issue where the scrolling on my page is not working properly after dynamically adding jQuery mobile list items using jQuery ajax response object. The function responsible for handling AJAX success looks like this: success: function( ...

An error occurred at line 120 in the index.js file of the http-proxy library: "socket hang up"

I encountered an issue while running expressJS in one of the containers within docker-compose. When I repeatedly refresh the landing page by pressing CMD+R (approximately every 3-4 seconds), it displays an error message "Error: socket hang up" causing the ...

What Causes the Undefined Value of "this" in Vue 3 Functions?

Here is a basic example of a component in Vue 3: <script> import { defineComponent } from 'vue' export default defineComponent({ name: 'Test', setup(){ return{ one, two } } }) function one(){ console. ...