Fullscreen Raymarching with Depth Check

For Godot 4.3.

Modified from this fullscreen raymarching shader.

Allows raymarched objects to intersect with world objects.

Follow this guide to create a fullscreen quad for the effect.

Shader code
shader_type spatial;
render_mode unshaded;

const int MAX_STEPS = 300;
const float MAX_DISTANCE = 1000.0;
const float MIN_DISTANCE = 0.001;

uniform sampler2D DEPTH_TEXTURE : source_color, hint_depth_texture;

void vertex() {
    POSITION = vec4(VERTEX.xy, 1.0, 1.0);
}

float sdSphere (vec3 p, vec3 centrum, float radius) {
    return length(centrum-p) - radius;
}

// infinte repetitions
// adapted from https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
vec3 opRep(vec3 p, vec3 c) {
    vec3 q = mod(p+0.5*c,c)-0.5*c;
    return q;
}

float get_distance(vec3 p) {
    p = opRep(p, vec3(3)); // uncomment for repeating spheres
    return sdSphere(p, vec3(0), 1.0);
}

vec3 get_normal(vec3 p) {
    vec2 e = vec2(1e-3, 0);
    
    vec3 n = get_distance(p) - vec3(
        get_distance(p - e.xyy),
        get_distance(p - e.yxy),
        get_distance(p - e.yyx)
    );
    
    return normalize(n);
}

vec4 raymarch(vec3 ray_origin, vec3 ray_dir, float depth) {
    float t = 0.0;
    vec3 p = ray_origin;
    for (int i = 0; i < MAX_STEPS; i++)
    {
        float d = get_distance(p);
        t += d;
        if (t > MAX_DISTANCE || t >= depth)
            break;
        
        p += d * ray_dir;
        if (abs(d)  < MIN_DISTANCE)
            return vec4(get_normal(p), 1);
     }
    //return vec4(float(i) * 0.01); // uncomment for simple glow effect
    return vec4(0.0);
}

void fragment() {
    float depth = texture(DEPTH_TEXTURE, SCREEN_UV).x;
    vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth);
    vec4 view = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
    view.xyz /= view.w;
    float linear_depth = -view.z;
    
    vec3 weird_uv = vec3(SCREEN_UV * 2.0 - 1.0, 0.0);
    vec4 camera = INV_VIEW_MATRIX * INV_PROJECTION_MATRIX * vec4(weird_uv, 1);
    
    vec3 ray_origin = INV_VIEW_MATRIX[3].xyz;
    vec3 ray_dir = normalize(camera.xyz);
    
    vec4 col = raymarch(ray_origin, ray_dir, linear_depth);
    
    ALPHA = col.a;
    ALBEDO = col.rgb;    
}
Tags
4.3, depth, March, marching, ray, raymarch, raymarching, SDF
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.

Related shaders

Simple fullscreen raymarching

Raymarching with depth writting

Procedural Burberry Check Shader

Subscribe
Notify of
guest

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Huraqan
1 month ago

Not sure if it’s my setup, but there is a slight offset in perspective, mostly noticeable when translating the camera. SDF and polygon geometry will slightly shift away from eachother. Any ideas?

asod asfo
asod asfo
4 days ago
Reply to  Huraqan

I noticed the same, still don’t know what distorts the perspective

asod asfo
asod asfo
4 days ago
Reply to  Huraqan

i found the correct way to sample the depth without distortion:

float depth_raw = texture(DEPTH_TEXTURE, SCREEN_UV,0.0).r;

vec4 upos =INV_PROJECTION_MATRIX* vec4(SCREEN_UV * 2.0 – 1.0, depth_raw,1.0);
vec3 pixel_position = upos.xyz/upos.w;
float linear_depth = length(pixel_position);