Simple fullscreen raymarching
This shader uses the same method as in the tutorial for advanced post-processing in the documentation:
https://docs.godotengine.org/en/stable/tutorials/shading/advanced_postprocessing.html
To use it you need to add a quadmesh and set both its width and height to 2, and of course apply the shader to the material. To avoid culling when the camera isn´t pointing at the mesh, increase the extra_cull_margin under geometry to as large as possible. This way the shader works well in the editor also.
In Godot 4, check Flip Faces on the quad mesh and INV_VIEW_MATRIX instead of CAMERA_MATRIX in the shader code.
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;
void vertex() {
POSITION = vec4(VERTEX, 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 t = 0.0;
vec3 p = ray_origin;
int i = 0;
for (i = 0; i < MAX_STEPS; i++)
{
float d = get_distance(p);
t += d;
if (t > MAX_DISTANCE)
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() {
vec2 uv = SCREEN_UV * 2.0 - 1.0;
vec4 camera = CAMERA_MATRIX * INV_PROJECTION_MATRIX * vec4(uv, 1, 1);
vec3 ray_origin = CAMERA_MATRIX[3].xyz;
vec3 ray_dir = normalize(camera.xyz);
vec4 col = raymarch(ray_origin, ray_dir);
ALPHA = col.a;
ALBEDO = col.rgb;
}
I tried tens of times to find something like this, nearly succeeded in writing my own but had trouble figuring out the camera origin, and then searching for the solution to the camera origin problem turned up this page! Thanks!
this is cool and works well!, but I don’t necessarily understand how ray origin works? like what is at CAMERA_MATRIX[3] (or INV_VIEW_MATRIX[3] in case of godot 4)
My understanding is that these mat4 matrices store the basis (rotation and scale) in the first three rows and the origin (position) in the fourth row.
CAMERA_MATRIX[3] is thus simply referencing the fourth row.
Below would be the CAMERA_MATRIX of a camera rotated so that it is looking straight in the -Z axis, as that is the view direction in Godot.
1 0 0 0
0 1 0 0
0 0 1 0
x y z w <= position
This is exactly what I was looking for. Good to use as a base for other shaders. Now I just have to figure out how to actually make something that looks nice.
For anyone on 4.3, here’s the changes that should be made.
Add this to the top of your shader.
Change the top couple of lines of your fragment function to this.
And change your vertex function to this for good measure: