Moving Decal

This spatial shader creates a moving, circular decal with consistent alpha blending, ideal for projecting textures onto surfaces in 3D space. It uses depth reconstruction to accurately place the decal on any geometry, with customizable parameters for radius, thickness, color, and animation speed. To use, apply this shader to a mesh that encompasses your target projection area, then adjust the uniform variables to fine-tune the decal’s appearance and behavior.

Shader code
shader_type spatial;
render_mode unshaded, depth_draw_always, cull_disabled, blend_mix;

uniform sampler2D depth_texture : hint_depth_texture;
uniform sampler2D decal_texture : source_color;

uniform float decal_radius = 1.0;
uniform float intersection_thickness = 0.1;
uniform float decal_scale = 1.0;
uniform float time_scale = 0.1;
uniform vec4 decal_color : source_color = vec4(1.0, 1.0, 1.0, 0.5);

void fragment() {
    // Get the depth and reconstruct world position
    float depth = textureLod(depth_texture, SCREEN_UV, 0.0).r;
    vec4 upos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, depth, 1.0);
    vec3 world_pos = (INV_VIEW_MATRIX * (upos / upos.w)).xyz;
    
    // Transform the world position to object space
    vec3 obj_pos = (inverse(MODEL_MATRIX) * vec4(world_pos, 1.0)).xyz;
    
    // Calculate distance from decal center
    float dist_from_center = length(obj_pos);
    
    // Calculate distance from decal surface
    float dist_from_surface = abs(dist_from_center - decal_radius);
    
    // Determine if we should render this fragment
    bool should_render = dist_from_surface <= intersection_thickness;
    
    // Calculate decal UV based on object space position
    vec2 decal_uv = (obj_pos.xz / decal_radius * 0.5 + 0.5 + vec2(TIME * time_scale)) * decal_scale;
    
    // Sample decal texture
    vec4 decal = texture(decal_texture, decal_uv);
    
    // Calculate fade based on distance from surface
    float fade = 1.0 - clamp(dist_from_surface / intersection_thickness, 0.0, 1.0);
    
    // Combine color and decal
    vec4 final_color = decal_color * decal;
    final_color.a *= fade;
    
    if (should_render) {
        ALBEDO = final_color.rgb;
        ALPHA = final_color.a;
    } else {
        // Discard fragments outside the decal area
        discard;
    }
}
Tags
caustics, decal
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.

More from StealthixDev

Dynamic Progress Bar with Waves and Particles

Related shaders

Moving RGB Rainbow Stripes

Decal Example

Raymarched 3D Noise Decal

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments