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.
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!