Search code examples
animationthree.jsshadernormals

Update normals of animated skinned mesh in three.js?


I have a simple animated model, animated throught skinning, and I am giving it a ShaderMaterial which displays its normals:

gl_FragColor = vec4(vNormal, 1.0);

https://codepen.io/marco_fugaro/pen/ZEEBjKz?editors=0010

The problem is the normals aren't updated with the skinning of the model, and they always stay the same from the object's non animated position (see VertexNormalsHelper).

How do I get the normals to update, or how do i get the animated vertices' normals?

model.geometry.computeVertexNormals() doesn't work

model


Solution

  • I ended up monkeyPatching the MeshNormalMaterial vertex shader, and removing the logic that the normals are relative to the camera, here is the final code:

    import * as THREE from 'three'
    import normalVert from 'three/src/renderers/shaders/ShaderLib/normal_vert.glsl'
    
    // like MeshNormalMaterial, but the normals are relative to world not camera
    const normalMaterialGlobalvert = normalVert.replace(
      '#include <defaultnormal_vertex>',
      THREE.ShaderChunk['defaultnormal_vertex'].replace(
        'transformedNormal = normalMatrix * transformedNormal;',
        // take into consideration only the model matrix
        'transformedNormal =  mat3(modelMatrix) * transformedNormal;'
      )
    )
    

    And then use it like:

    mesh.material = new THREE.ShaderMaterial({
      vertexShader: normalMaterialGlobalvert,
      fragmentShader: `
        varying vec3 vNormal;
    
        void main() {
          gl_FragColor = vec4(vNormal, 1.0);
        }
      `,
    })
    

    Thanks gman for pointing me in the right direction!