Shadow volume without stencil buffer
Stencil-like shadows based on alpha blending (You can create shadow-volume without Stencil-buffer operations)
This requires a complex material of 4 shaders.
This implementation includes a simple volume generator. It does not support flat-shaded models and non-closed geometry.
Tested renderers:
- Forward + : Most likely works on any hardware
- Compatibility : It’s not working May work when render_priority is balanced – [-1, 0, 1, 0] (Only works on some graphics cards)
- GLES 3 (Godot 3) : Works but probably depends on the hardware
- GLES 2 : It’s not working
Tested hardware:
- [Intel HD 4000] : Forward+, Compatibility, GLES 3
- [Quadro M1000M]: Forward+, Compatibility, GLES 3
- [Radeon R5 (Stoney Ridge)]: Forward+, Compatibility, GLES 3
If you have any ideas how to run it in GLES 2 – post in comments
It looks like the Compatibility render contains bugs in the implementation, I don’t recommend using it with this technique.
It may depend on your hardware, so if you tested and it didn’t work for you, please post your hardware in the comments.
Shader code
shader_type spatial;
//render_mode unshaded, cull_front, blend_add, world_vertex_coords;
//render_mode unshaded, cull_back, blend_sub, world_vertex_coords;
//render_mode unshaded, cull_front, blend_sub, depth_test_disabled, world_vertex_coords;
//render_mode unshaded, cull_back, blend_add, depth_test_disabled, world_vertex_coords;
//For this to work, you need to create 4 materials with different render_mode and nest each one into the next_pass of the next. (Don't try to realize this, just download Demo from github and see the structure of the material)
uniform vec3 light_position;
uniform float light_radius = 50.0;
void vertex() {
vec3 rd = VERTEX - light_position;
vec3 rn = normalize(rd);
if (dot(NORMAL, rn) > 0.0) {
VERTEX += rn*clamp(light_radius-length(rd), 0.0, light_radius);
}
else {
VERTEX -= NORMAL*0.01;
}
}
void fragment() {
ALPHA = 0.5;
}
LOL. You’re a mad genius
Great proof-of-concept. To make this approach more usable, a user would probably want to make an addon to allow for multiple lights, and handle the shadow mesh setup automatically.
Imported the project into Godot 4.4, the torus shadow has some artifacts:
I thought this was LOD-related, but selecting the debug mode “disable Mesh LOD” still shows it. 4.4 definitely has some LOD weirdness going on though, so it may still be the cause.
I wonder if it’d be possible to prevent the shadow meshes from drawing on top of the regular meshes, that would make unshaded materials usable without showing the ugly self-shadowing. Older games that used stencil shadows tended to use simpler geometry for the shadow mesh, especially for characters; so prevent self-shadowing would be essential in that case.
Sorry, I don’t have your image displayed, but I’m guessing what artifacts you’re talking about. “White areas.” – are the result of incorrect geometry generation for the shadow volume in the vertex shader. They are not on the video, because in the first version of the project the shadow volumes were modeled manually in Blender. In any case, it is solvable. I thought for a long time how to mix different light sources and tried different implementations, but came to the conclusion that the best option is to render the shadows in another buffer and then mix them with the final image based on screen normals. This approach can also solve the problem of masking shadows for self-shadowing and beyond. Without using RenderingDevice, you could do this with SubViewport.