Search code examples
javascriptthree.jsshaderraytracingshadow-mapping

three.js: how to let transparent png sprites cast and receive shadows?


Is there a feature, option, or some shader, that allows sprites to cast and receive shadows? Also including that sprite's alpha channel is not rendered as a shadow.

I have all my assets as transparent PNGs, and I am using sprites in three.js to map the textures onto sprites. This is working great apart from the problem of shadows. Ideally, it would be great that shadow casted from the sprite does not include the PNG's alpha channel*, so that light passes through the alpha channel of the png, although I am finding little research on this in the documentations of threejs.

*I am thinking of a similar style to PaRappa the Rapper or Adventure Xpress.


Solution

  • These are the shaders I ended up using.

    Fragment shader. You can change the pixel.a which is the alpha value of the pixel. The fragment shader is discarded on this pixel if the alpha value falls below 0.5 (thus leaving it to appear transparent).

    #include <packing>
    
    uniform sampler2D texture;
    varying vec2 vUV;
    
    void main() {
    
        vec4 pixel = texture2D( texture, vUV );
        if ( pixel.a < 0.5 ) discard;
        gl_FragData[ 0 ] = packDepthToRGBA( gl_FragCoord.z );
    
    }
    

    Vertex shader. This is nothing special, I thought I would leave this here just incase your vertex shader is causing issues, this one I can confirm to be compatible with the above fragment shader.

    varying vec2 vUV;
    
    void main() {
    
        vUV = uv;
        vec4 mvPosition = modelViewMatrix * vec4( position, 1 );
        gl_Position = projectionMatrix * mvPosition;
    
    }