THREEjs change shadows after vertex shader

128 Views Asked by At

I have a vertex shader that moves object's vertices around, but the shadow the objects cast remain static (as if no vert shader was applied)

The objects are rendered using THREE's geometries:

BoxGeometry, CylinderGeometry, TetrahedronBufferGeometry, ConeGeometry

then to each of them I apply MeshPhongMaterial and in material.onBeforeCompile() i set my custom vertex shader.

people online suggested to use customDepthMaterial, as can be seen in the cloth simulation example here, but that didn't seem to work.

One difference is that the example also uses map: clothTexture in the material params and I don't.. don't know if it's relevant

the code is available in https://codepen.io/the-roman-one/pen/VwgVjdW, and for convenience, here's what my material factory looks like this:

make = (shaderUniforms, shader_type) =>
{
    let material
    switch(shader_type)
    {
        case SHADER_TYPES.GRASS:
            material = this.raw_material; break;
        default:
            material = this.phong_material
    }
    material = material.clone()
    material.needsUpdate = true;
    let {uuid} = material
    material.onBeforeCompile = (shader) =>
    {
        shader.uniforms = {
            ...shader.uniforms,
            ...shaderUniforms,
            time: {value: 0},
        }
        
        let shaders = this.shader_maker.make(shader_type)
        shader.vertexShader = shaders.vertex
        shader.fragmentShader = shaders.fragment;

        this.context.shaders[uuid] = shader
    }

    material.customDepthMaterial = new THREE.MeshDepthMaterial({
        depthPacking: THREE.RGBADepthPacking,
        alphaTest: 0.5
      });
    return material
}
1

There are 1 best solutions below

0
Arashtad On

Shadows are usually created based on the depth data from the geometry. When you modify vertex positions, it affects the visual appearance but not the shadows as they're computed separately based on the original geometry.

For the shadows you should update the customDepthMaterial to use a custom depth shader that matches the modifications in your vertex shader.

Look at this example:

make = (shaderUniforms, shader_type) => {
    let material;
    switch (shader_type) {
        case SHADER_TYPES.GRASS:
            material = this.raw_material;
            break;
        default:
            material = this.phong_material;
    }
    material = material.clone();
    material.needsUpdate = true;
    let { uuid } = material;
    material.onBeforeCompile = (shader) => {
        shader.uniforms = {
            ...shader.uniforms,
            ...shaderUniforms,
            time: { value: 0 },
        };

        let shaders = this.shader_maker.make(shader_type);
        shader.vertexShader = shaders.vertex;
        shader.fragmentShader = shaders.fragment;

        this.context.shaders[uuid] = shader;
    };

    // Create a custom depth material with the same vertex shader
    material.customDepthMaterial = new THREE.MeshDepthMaterial({
        depthPacking: THREE.RGBADepthPacking,
        alphaTest: 0.5,
        onBeforeCompile: (shader) => {
            shader.uniforms = {
                ...shader.uniforms,
                ...shaderUniforms,
                time: { value: 0 },
            };

            shader.vertexShader = this.shader_maker.make(shader_type).vertex;
        },
    });

    return material;
};

This way you can adjust changes of the shadows with the changes on the object.