Created
February 14, 2026 03:30
-
-
Save bolducke/00805ddf144ed53fdfc191ff354036d9 to your computer and use it in GitHub Desktop.
Uniform Sampling of Surfaces
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define SELF iChannel0 | |
| void mainImage(out vec4 fragColor, in vec2 fragCoord) | |
| { | |
| if (iFrame < 3) { | |
| ivec2 seed = ivec2(fragCoord.xy); | |
| vec3 ro_sample; | |
| vec3 rd_sample; | |
| random_sample_ray(seed, ro_sample, rd_sample); | |
| float[] t_rec = raymarch(ro_sample, rd_sample); | |
| fragColor = vec4(t_rec[0], t_rec[1], t_rec[2], t_rec[3]); | |
| } | |
| else { | |
| fragColor = texelFetch(SELF, ivec2(gl_FragCoord.xy), 0); | |
| } | |
| } | |
| void random_sample_ray(ivec2 seed, inout vec3 ro, inout vec3 rd) | |
| { | |
| vec3 pcenter_disk = point_on_sphere(seed, 1.); | |
| rd = normalize(vec3(0.) - pcenter_disk); | |
| ro = point_on_disk(seed/2, pcenter_disk, rd, 1.); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // Invariant | |
| // | |
| #define PI 3.14159265359 | |
| #define TAU 2.*PI | |
| #define RAYMARCH_MAX_INTERSECTION 4 | |
| // | |
| // Variant | |
| // | |
| #define RAYMARCH_STEP 100 | |
| #define RAYMARCH_MAX_LENGTH 10.0 | |
| #define RAYMARCH_TOLERANCE 0.001 | |
| // MAX_DRAW_SAMPLES includes rejected points so the total displayed will be equal or lower | |
| #define MAX_DRAW_SAMPLES 3000 // MAX: iResolution.x * iResolution.y | |
| #define SAMPLE_RADIUS 0.02 | |
| #define RADIUS_CAMERA 3. | |
| #define SDF_COLOR vec3(1.0, 0.5, 0.3) | |
| #define LIGHT_DIR normalize(vec3(-0.5, 0.8, -1.0)) | |
| // ------------------------------------------------------------ | |
| // Random functions | |
| // ------------------------------------------------------------ | |
| vec2 hash22(vec2 p) { | |
| vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); | |
| p3 += dot(p3, p3.yzx+33.33); | |
| return fract((p3.xx+p3.yz)*p3.zy); | |
| } | |
| vec3 point_on_disk(ivec2 seed, vec3 center, vec3 normal, float radius) { | |
| vec2 uv = hash22(vec2(seed)); | |
| vec3 u = normalize(cross(normal, abs(normal.x) > 0.99 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0))); | |
| vec3 v = normalize(cross(normal, u)); | |
| float r = sqrt(uv.x) * radius; | |
| float theta = TAU * uv.y; | |
| return center + r * cos(theta) * u + r * sin(theta) * v; | |
| } | |
| vec3 point_on_sphere(ivec2 seed, float radius) { | |
| vec2 u = hash22(vec2(seed)); | |
| float z = 1.0 - 2.0 * u.x; | |
| float a = TAU * u.y; | |
| float r = sqrt(1.0 - z * z); | |
| return radius * vec3(r * cos(a), r * sin(a), z); | |
| } | |
| // ------------------------------------------------------------ | |
| // SDF Primitives | |
| // ------------------------------------------------------------ | |
| float sdSphere(vec3 p, float r) { | |
| return length(p) - r; | |
| } | |
| float sdTorus(vec3 p, vec2 t) { | |
| vec2 q = vec2(length(p.xz)-t.x, p.y); | |
| return length(q)-t.y; | |
| } | |
| // ------------------------------------------------------------ | |
| // Scene | |
| // ------------------------------------------------------------ | |
| float sdScene(vec3 p) { | |
| return sdTorus(p, vec2(0.5, 0.3)); | |
| } | |
| vec3 nScene(vec3 p) { | |
| float h = 0.001; | |
| vec2 k = vec2(1,-1); | |
| return normalize( | |
| k.xyy * sdScene(p + k.xyy*h) + | |
| k.yyx * sdScene(p + k.yyx*h) + | |
| k.yxy * sdScene(p + k.yxy*h) + | |
| k.xxx * sdScene(p + k.xxx*h) | |
| ); | |
| } | |
| float[RAYMARCH_MAX_INTERSECTION] raymarch(vec3 ro, vec3 rd) { | |
| float t = 0.0; | |
| int index_insert = 0; | |
| float[] store_t = float[4](-1., -1., -1., -1.); | |
| for(int i = 0; | |
| i < RAYMARCH_STEP && | |
| index_insert < RAYMARCH_MAX_INTERSECTION && | |
| t < RAYMARCH_MAX_LENGTH; | |
| i++) | |
| { | |
| vec3 p = ro + t * rd; | |
| float d = abs(sdScene(p)); | |
| if(d < RAYMARCH_TOLERANCE) { | |
| store_t[index_insert] = t; | |
| index_insert += 1; | |
| } | |
| while(d < RAYMARCH_TOLERANCE) { | |
| t += max(RAYMARCH_TOLERANCE, d); | |
| p = ro + t * rd; | |
| d = abs(sdScene(p)); | |
| } | |
| t += d; | |
| } | |
| return store_t; | |
| } | |
| // ------------------------------------------------------------ | |
| // Utilities | |
| // ------------------------------------------------------------ | |
| vec2 intersect_line_sphere(vec3 ro, vec3 rd, vec3 sc, float sr) { | |
| vec3 oc = ro - sc; | |
| float a = dot(rd, rd); | |
| float b = 2.0 * dot(oc, rd); | |
| float c = dot(oc, oc) - sr * sr; | |
| float discriminant = b * b - 4.0 * a * c; | |
| if (discriminant < 0.0) return vec2(-1.0); | |
| float sqrtD = sqrt(discriminant); | |
| float t0 = (-b - sqrtD) / (2.0 * a); | |
| float t1 = (-b + sqrtD) / (2.0 * a); | |
| return vec2(t0, t1); | |
| } | |
| vec3 orbital_position(float yaw, float pitch, float radius, vec3 target) { | |
| float x = radius * cos(pitch) * sin(yaw); | |
| float y = radius * sin(pitch); | |
| float z = radius * cos(pitch) * cos(yaw); | |
| return target + vec3(x, y, z); | |
| } | |
| float remap(float uv, float omin, float omax, float nmin, float nmax) { | |
| float t = (uv - omin) / (omax - omin); | |
| return t * (nmax - nmin) + nmin; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define TEX_REC_INTERSECTION iChannel0 | |
| void mainImage(out vec4 fragColor, in vec2 fragCoord) | |
| { | |
| vec2 mouse = iMouse.xy / iResolution.xy; | |
| vec2 aspect_ratio = vec2(iResolution.xy / iResolution.yy); | |
| vec2 uv_centered = ((gl_FragCoord.xy / iResolution.xy) - vec2(0.5)) * aspect_ratio; | |
| vec3 ro_camera; | |
| vec3 rd_camera; | |
| { | |
| float yaw = TAU * mouse.x; | |
| float pitch = PI * mouse.y; | |
| const vec3 target = vec3(0.); | |
| ro_camera = orbital_position(yaw, pitch, RADIUS_CAMERA, target); | |
| vec3 forward = normalize(target - ro_camera); | |
| vec3 right = normalize(cross(vec3(0.0, 1.0, 0.0), forward)); | |
| vec3 up = cross(forward, right); | |
| vec3 plane_center = ro_camera + forward * 1.0; | |
| vec3 target_ray = plane_center + uv_centered.x * right + uv_centered.y * up; | |
| rd_camera = normalize(target_ray - ro_camera); | |
| } | |
| float t = raymarch(ro_camera, rd_camera)[0]; | |
| vec3 col = vec3(0.0); | |
| if (t > 0.0) { | |
| vec3 p = ro_camera + rd_camera * t; | |
| vec3 n = nScene(p); | |
| float diffuse = clamp(dot(n, LIGHT_DIR), 0.0, 1.0); | |
| diffuse = remap(diffuse, 0., 1., 0.2, 1.); | |
| col = SDF_COLOR * diffuse; | |
| for (int i = 0; i < MAX_DRAW_SAMPLES; i++) { | |
| ivec2 seed = ivec2(i % int(iResolution.x), | |
| i / int(iResolution.x)); | |
| vec3 ro_sample; | |
| vec3 rd_sample; | |
| random_sample_ray(seed, ro_sample, rd_sample); | |
| vec4 t_rec = texelFetch(TEX_REC_INTERSECTION, seed, 0); | |
| for (int c = 0; c < RAYMARCH_MAX_INTERSECTION; c++) { | |
| float t_c = t_rec[c]; | |
| if (t_c >= 0.) { | |
| vec3 p_tc = ro_sample + rd_sample * t_c; | |
| vec2 t_inter = intersect_line_sphere( | |
| ro_camera, | |
| rd_camera, | |
| p_tc, | |
| SAMPLE_RADIUS | |
| ); | |
| if ((t_inter.x > 0. && t_inter.x < t) || | |
| (t_inter.y > 0. && t_inter.y < t)) | |
| { | |
| col = vec3(0.8, 0.4, 1.); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| fragColor = vec4(col, 1.0); | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Original implementation here: https://www.shadertoy.com/view/WfcXWB
Code extacted with LLM since shadertoy code is unavailable.