I’m trying to get shadows to work on a plane with a shaderMaterial.
I’ve tried some different approaches but can’t really get it to work (I’m not sure how to add it to the shader).
I tried the ShadowOnlyMaterial (and just place a plane with said material in front of the actual plane) but I can’t get it to only cast shadows that would exist on the texture (and not the transparent parts).
I’ve set up a playground here:
Is it possible to add shadows to the plane with the texture on it?
The issue is that ShaderMaterial is intentionally a “blank slate” — its source has no built-in handling for lights or shadows. Wiring shadow reception in by hand is actually pretty complicated: it’s not just shader changes (pulling in the engine’s shadow include chain — __decl__lightVxFragment, shadowsVertex, __decl__lightFragment, shadowsFragmentFunctions, lightFragment — and declaring every shadow uniform/sampler), there are also JS-side changes (preparing the right shadow defines, then binding all the light + shadow uniforms per-frame the way MaterialHelper does it for StandardMaterial). A lot of boilerplate just to get the standard shadow path.
A friendlier route is to keep StandardMaterial (which already handles lights / shadows / fog / alpha blending correctly) and use a MaterialPlugin to inject just your pixel-perfect sampling into the diffuse step. Then plane.receiveShadows = true is the only extra line needed.
The pixel-perfect sampling is injected at the CUSTOM_FRAGMENT_UPDATE_ALPHA point, where baseColor (the diffuse texture sample) and alpha are in scope — perfect spot to overwrite both with the iq sub-pixel anti-aliased lookup.
With texture.hasAlpha = true + material.useAlphaFromDiffuseTexture = true + plane.receiveShadows = true, the shadow is automatically masked by the texture’s alpha — transparent texels just don’t write to the framebuffer, so no shadow renders on them. That removes the need for the ShadowOnlyMaterial overlay.
Thank you for the clear explanation and playground changes.
Shaders/materials are something I’m still trying to understand better, and this helps a lot!