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:

  1.  Forward + : Most likely works on any hardware
  2. Compatibility : It’s not working May work when render_priority is balanced – [-1, 0, 1, 0] (Only works on some graphics cards)
  3. GLES 3 (Godot 3) : Works but probably depends on the hardware
  4. 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;
}
Tags
shadow
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from RAS

Colored Glass

Related shaders

Depth Buffer Object Edge Dissolve

2D Cast shadow

2D Pixel Shadow/Outline

Subscribe
Notify of
guest

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
tentabrobpy
15 days ago

LOL. You’re a mad genius

cwook
cwook
4 days ago

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: comment image
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.