Real-time path traced voxel tunnel.
Log in to post a comment.
precision highp float; // Forked from "Fractal cube" by reinder // https://oneshader.net/shader/e94495f6e9 uniform float iTime; uniform vec2 iResolution; #define PATH_LENGTH 3 #define SAMPLES_PER_PIXEL 8 #define MAX_DIST 1e10 #define PI 3.14159265359 #define MAX_FLOAT 1e5 #define EPSILON 0.001 #define LAMBERTIAN 0. #define METAL 1. #define DIFFUSE_LIGHT 2. uniform float speed; // value=10, min=5, max=50, step=0.1 uniform float gridFill;// value=1.6, min=1., max=4., step=0.01 uniform float lightFill;// value=0.9, min=0.75, max=0.98, step=0.01 uniform float matType;// value=1, min=0, max=1, step=1 (Lambertian, Metal) uniform float matRoughness;// value=0.15, min=0.05, max=1, step=0.01 uniform float colorScale;// value=0.3, min=0, max=1, step=0.01 uniform float colorOffset;// value=5.6, min=0, max=6.4, step=0.01 float seed; float mat_hash; vec3 bgCol = (.6 + .4 * cos(12.5663706144 * colorScale + colorOffset + vec3(0., 0.6, 1.2))); // Hash without Sine // MIT License... // Copyright (c)2014 David Hoskins. // https://www.shadertoy.com/view/4djSRW float hash1(inout float p) { p = fract((p+=0.1) * .1031); p *= p + 33.33; p *= p + p; return fract(p); } vec2 hash2(inout float p) { vec3 p3 = fract(vec3(p+=1.) * vec3(.1031, .1030, .0973)); p3 += dot(p3, p3.yzx + 33.33); return fract((p3.xx+p3.yz)*p3.zy); } vec3 hash3(inout float p) { vec3 p3 = fract(vec3(p+=1.) * vec3(.1031, .1030, .0973)); p3 += dot(p3, p3.yzx+33.33); return fract((p3.xxy+p3.yzz)*p3.zyx); } float gpuIndepentHash(float p) { p = fract(p * .1031); p *= p + 19.19; p *= p + p; return fract(p); } float grid(in vec3 ro, in vec3 rd, in vec2 distBound, inout vec3 normal) { const int steps = 32; vec3 ros = ro; vec3 pos = floor(ros + rd * distBound.x); vec3 ri = 1.0/rd; vec3 rs = sign(rd); vec3 dis = (pos-ros + 0.5 + rs*0.5) * ri; float res = 0.0, grid_seed; vec3 mm = vec3(0.0); bool hit = false; for (int i=0; i<steps; i++) { mm = step(dis.xyz, dis.yxy) * step(dis.xyz, dis.zzx); dis += mm * rs * ri; pos += mm * rs; vec3 hash_pos = pos + .5; hash_pos = abs(hash_pos); grid_seed = dot(hash_pos, vec3(sqrt(5.), sqrt(2.), sqrt(3.))); // grid_seed = dot(hash_pos, vec3(1)); // grid_seed = dot(hash_pos, vec3(1,1,1)); grid_seed += floor(grid_seed); float grid_hash = hash1(grid_seed); if (length(pos.xy + .5) > 2.5 + grid_hash * gridFill) { hit = true; break; } } if (hit) { // intersect the cube vec3 mini = (pos-ros + 0.5 - 0.5*vec3(rs))*ri; float t = max (mini.x, max (mini.y, mini.z)); mat_hash = hash1(grid_seed); normal = -mm*rs; // matCol *= .5; return t; } else { return MAX_DIST; } } // // Ray tracer helper functions // vec3 cosWeightedRandomHemisphereDirection(const vec3 n, inout float seed) { vec2 r = hash2(seed); vec3 uu = normalize(cross(n, abs(n.y) > .5 ? vec3(1., 0., 0.) : vec3(0., 1., 0.))); vec3 vv = cross(uu, n); float ra = sqrt(r.y); float rx = ra*cos(6.28318530718*r.x); float ry = ra*sin(6.28318530718*r.x); float rz = sqrt(1.-r.y); vec3 rr = vec3(rx*uu + ry*vv + rz*n); return normalize(rr); } vec3 modifyDirectionWithRoughness(const vec3 normal, const vec3 n, const float roughness, inout float seed) { vec2 r = hash2(seed); vec3 uu = normalize(cross(n, abs(n.y) > .5 ? vec3(1., 0., 0.) : vec3(0., 1., 0.))); vec3 vv = cross(uu, n); float a = roughness*roughness; float rz = sqrt(abs((1.0-r.y) / clamp(1.+(a - 1.)*r.y, .00001, 1.))); float ra = sqrt(abs(1.-rz*rz)); float rx = ra*cos(6.28318530718*r.x); float ry = ra*sin(6.28318530718*r.x); vec3 rr = vec3(rx*uu + ry*vv + rz*n); vec3 ret = normalize(rr); return dot(ret, normal) > 0. ? ret : normalize(ret + 2. * dot(ret, normal) * n); } vec2 randomInUnitDisk(inout float seed) { vec2 h = hash2(seed) * vec2(1, 6.28318530718); float phi = h.y; float r = sqrt(h.x); return r*vec2(sin(phi), cos(phi)); } // // Scene description // float worldhit(in vec3 ro, in vec3 rd, in vec2 dist, out vec3 normal) { return grid(ro, rd, dist, normal); } vec3 getSkyColor(vec3 rd) { float amb = 6. - 2. * rd.y; float sun = clamp(dot(normalize(vec3(.4, .7, 1.2)), rd), 0., 1.); sun = (pow(sun, 4.) + 20.*pow(sun, 32.)); return (.6 + .4 * cos(12.5663706144 * colorScale + colorOffset + vec3(0., 0.6, 1.2))) * sun + amb; } // // Simple ray tracer // vec3 render(in vec3 ro, in vec3 rd) { vec3 col = vec3(0), normal, albedo, emit; vec3 emitted = vec3(0); float type, roughness; // bounding box float d = min(abs(1.99/rd.y), abs(1.99/rd.x)); for (int i=0; i<PATH_LENGTH; i++) { float res = worldhit(ro, rd, vec2(i == 0 ? d : .0001, MAX_DIST), normal); if (res < MAX_DIST) { ro += rd * res; // cube const float ga = 0.39996322972865332; if (matType < .5) { albedo = .5 + .4 * cos(mat_hash * (12.5663706144 * colorScale) + colorOffset + vec3(0., 0.6, 1.2)); albedo *= albedo; } else { type = 1.; albedo = .4 + .3 * cos((12.5663706144 * colorScale) + colorOffset + vec3(0., 0.6, 1.2)); albedo *= albedo; roughness = mat_hash * mat_hash * matRoughness; } float l = smoothstep(lightFill, 1., abs(fract(gpuIndepentHash(mat_hash) + iTime * 0.1) * 2. - 1.)); if (l > 0.) { emit = bgCol * (75. * l); } emit += (1. - exp(-0.0015*res)) * bgCol; emitted += i == 0 ? emit : col * emit; col = i == 0 ? albedo : col * albedo; if (matType < LAMBERTIAN+.5) { rd = cosWeightedRandomHemisphereDirection(normal, seed); } else { rd = modifyDirectionWithRoughness(normal, reflect(rd, normal), roughness, seed); } } else { return emitted + (.5 * bgCol);// + col * getSkyColor(rd); } // if(dot(col,col) < 0.0001) return emitted + col * getSkyColor(rd); } return emitted; } void main() { float fpd = 20.; vec3 col = vec3(0); vec2 fc = gl_FragCoord.xy; for (int i=0; i<SAMPLES_PER_PIXEL; i++) { seed = iTime + 100.*(float(i)*2.399+hash1(fc.x)+hash1(fc.y)); // AA vec2 p = (2. * gl_FragCoord.xy - iResolution) / iResolution.y; p += 2.*hash2(seed)/iResolution.y; p *= 1. + .25 * dot(p,p); vec3 ro = vec3(0., 0., 6. - speed * (iTime + 0.05 * gpuIndepentHash(seed))); vec3 rd = normalize(vec3(p.x, p.y, -2.15)); vec3 normal; // DOF vec3 fp = ro + rd * fpd; ro = ro + vec3(randomInUnitDisk(seed), 0.)*.05; rd = normalize(fp - ro); vec3 outcol = render(ro, rd); outcol = max(vec3(0), outcol - 0.004); outcol = (outcol*(6.2*outcol + .5)) / (outcol*(6.2*outcol+1.7) + 0.06); col += outcol; } col *= 1./float(SAMPLES_PER_PIXEL); col += vec3(hash1(seed)) * 0.02; gl_FragColor = vec4(col, 1); }