ray_march.glsl
1 layout (local_size_x=1, local_size_y=1, local_size_z=1) in; 2 layout(rgba32f, binding = 0) uniform image2D imgOutput; 3 4 // file: raymarch.glsl 5 // author: chmod777 6 // license: GNU AGPL v3 7 8 layout(std140, binding = 5) buffer Spheres { 9 vec4 pallet_a; 10 vec4 pallet_b; 11 vec4 pallet_c; 12 vec4 pallet_d; 13 vec4 sp_pos[SPHERE_COUNT]; 14 vec4 sp_speed[SPHERE_COUNT]; 15 float sp_radius[SPHERE_COUNT]; // alignment [float, pad, pad, pad] 16 }; 17 18 layout(std430, binding = 7) buffer Camera { 19 vec4 cam_pos; 20 vec4 cam_front; 21 vec4 cam_xAxis; 22 vec4 cam_yAxis; 23 float cam_fov; 24 }; 25 uniform float time; 26 27 // Resources 28 // https://iquilezles.org/articles/palettes/ 29 vec4 palette_impl(float t, vec4 a, vec4 b, vec4 c, vec4 d) { 30 // return a + b*cos( 6.28312 * (c*t+d) ) 31 return fma(b, cos(6.28312 * fma(c, vec4(t), d)), a); 32 } 33 vec4 palette(float t) { 34 return palette_impl(t, pallet_a, pallet_b, pallet_c, pallet_d); 35 } 36 37 struct Sphere { 38 vec3 pos; // 4 39 float radius; // 8 40 }; 41 Sphere localSpheres[SPHERE_COUNT]; 42 43 struct RayHit { 44 float dist; 45 int id; 46 vec3 normal; 47 }; 48 49 float op_union(float a, float b) { 50 return (a < b) ? a : b; 51 } 52 float op_smooth_union(float a, float b, float k) { 53 float diff = a - b; 54 float h_raw = fma(diff/k, 0.5, 0.5); 55 float h = clamp(h_raw, 0.0, 1.0); 56 float d = fma(-k, h*(1.0 - h), mix(a, b, h)); 57 return d; 58 } 59 60 float signDistanceSphere(vec3 point, Sphere sphere) { 61 return length(point - sphere.pos) - sphere.radius; 62 } 63 64 float sdf(vec3 point) { 65 float a = signDistanceSphere(point, localSpheres[0]); 66 for (int i = 1; i < SPHERE_COUNT; i++) { 67 float b = signDistanceSphere(point, localSpheres[i]); 68 a = op_smooth_union(a, b, float(SMOOTHING_FACTOR)); 69 } 70 return a; 71 } 72 73 vec3 normal(vec3 p) { 74 vec2 e = vec2(0.0001, 0.0); 75 float d = sdf(p); 76 vec3 n = d - vec3( 77 sdf(p - e.xyy), 78 sdf(p - e.yxy), 79 sdf(p - e.yyx) 80 ); 81 return normalize(n); 82 } 83 RayHit rayMarch(vec3 origin, vec3 dir) { 84 RayHit dummy = RayHit(-1.0, -1, vec3(0.0, 1.0, 0.0)); 85 float t = 0.0; 86 for (int i = 0; i < MAX_STEPS; i++) { 87 vec3 p = fma(dir, vec3(t), origin); 88 float res = sdf(p); 89 if (res < (MIN_DISTANCE)) 90 return RayHit(t, 0, normal(p)); 91 if (res > MAX_DISTANCE) 92 return dummy; 93 t += res; 94 } 95 96 return dummy; 97 } 98 float map(float value, float min1, float max1, float min2, float max2) { 99 return min2 + (value - min1) * (max2 - min2) / (max1 - min1); 100 } 101 102 void main() { 103 ivec2 pixelCoord = ivec2(gl_GlobalInvocationID.xy); 104 105 vec2 pixelCoordF = vec2(pixelCoord); 106 vec2 dims = vec2(float(WIDTH), float(HEIGHT)); 107 vec2 uv = pixelCoordF / dims * 2.0; 108 uv.x = uv.x - 1.0; 109 uv.y = 1.0 - uv.y; 110 111 vec3 origin = cam_pos.xyz; 112 vec3 dir = normalize( 113 fma(vec3(cam_xAxis), vec3(uv.x), 114 fma(vec3(cam_yAxis), vec3(uv.y), 115 vec3(cam_front) * radians(cam_fov) 116 ) 117 ) 118 ); 119 120 float t = time * TIMESCALE; 121 for (int i = 0; i < SPHERE_COUNT; i++) { 122 Sphere sp = Sphere( 123 fma(sin(sp_speed[i].xyz * t), vec3(MOVESCALE), sp_pos[i].xyz), 124 sp_radius[i] 125 ); 126 localSpheres[i] = sp; 127 } 128 129 vec4 pixel = vec4(0.0); 130 131 RayHit hit = rayMarch(origin, dir); 132 if (hit.dist != -1.0) { 133 pixel = vec4(hit.normal, 1.0); 134 float t = dot(hit.normal, dir) 135 + time * TIMESCALE * 0.05; 136 float a = 1.0; // map(hit.dist, 4.0, 12.0, 1.0, 0.5); 137 pixel = vec4(palette(t).xyz, a); 138 } 139 140 imageStore(imgOutput, pixelCoord, pixel); 141 }