Fullscreen Raymarching with Depth Check
For Godot 4.3.
Modified from this fullscreen raymarching shader.
Thank you asod asfo for the fix!
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_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);
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;
}
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?
I noticed the same, still don’t know what distorts the perspective
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);
will update, thank you!