# Decal Example

A relatively simple decal shader that uses the depth buffer to draw over the geometry in the scene. The shader works great with a default Godot cube.

One thing to note: The shader does NOT take the normals of the scene into account and will draw over anything within the cube. I tried writing the shader so it would reconstruct the normals from the depth buffer (which kinda worked) but the normals were relative to the camera rotation and not the world position and I couldn’t figure out how to transform it for use with decals.

For the drawing over anything within the cube, color masking could be used for this! I didn’t implement it in the shader, but I have written a tutorial on colormasking on my website RandomMomentania, which may be helpful as a reference.

This shader is not optimized! I just wrote it as a shader experiment/test and wanted to share the results.

Credit to Andon M. Coleman on StackOverflow for posting the snippet for getting a world position from the depth buffer. Also, credit to Ronja’s tutorials for the inspiration to make this little shader experiment.

``````shader_type spatial;
uniform vec4 albedo : hint_color;
uniform sampler2D texture_albedo : hint_albedo;

uniform float cube_half_size = 1.0;

// Credit: https://stackoverflow.com/questions/32227283/getting-world-position-from-depth-buffer-value
vec3 world_pos_from_depth(float depth, vec2 screen_uv, mat4 inverse_proj, mat4 inverse_view) {
float z = depth * 2.0 - 1.0;

vec4 clipSpacePosition = vec4(screen_uv * 2.0 - 1.0, z, 1.0);
vec4 viewSpacePosition = inverse_proj * clipSpacePosition;

viewSpacePosition /= viewSpacePosition.w;

vec4 worldSpacePosition = inverse_view * viewSpacePosition;

return worldSpacePosition.xyz;
}

void fragment() {
float depth = texture(DEPTH_TEXTURE, SCREEN_UV).x;
vec3 world_pos = world_pos_from_depth(depth, SCREEN_UV, INV_PROJECTION_MATRIX, (CAMERA_MATRIX));
vec4 test_pos = (inverse(WORLD_MATRIX) * vec4(world_pos, 1.0));

if (abs(test_pos.x) > cube_half_size ||abs(test_pos.y) > cube_half_size || abs(test_pos.z) > cube_half_size) {
}
ALBEDO = texture(texture_albedo, (test_pos.xz * 0.5) + 0.5).rgb * albedo.rgb;
}
``````
###### Tags
decal, godot
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

### Quick Example Fresnel Outline

Subscribe
Notify of

Inline Feedbacks
NekotoArts
2 years ago

icon.png has seen better days XD. Nice work tho!

SonnyBonds
1 year ago

Great starting point for decal shaders!

An optimization tip is to inverse the world matrix in the vertex shader and send it to fragment in a varying mat4 instead of inverting it in the fragment shader. This yields a massive speedup, at least on the fairly bad graphics card I’ve got in this laptop…

bengtsts
6 months ago