Open WoodNeck opened 5 years ago
#define FLT_MAX 3.402823466e+38 precision mediump float; uniform vec4 uScreenSize; uniform float uTime; const int NUM_OBJECTS = 4; const int LAMBERTIAN = 0; const int METAL = 1; struct ray { vec3 o, d; }; struct record { float t; vec3 p, n; }; struct material { int type; vec3 albedo; }; struct hitable { vec3 c; float r; material mat; }; float rand(vec2 co) { return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453) * 2. - 1.; } vec3 randomInUnitSphere(float sd) { return vec3( rand(vec2(sd += .1, sd += .1)), rand(vec2(sd += .1, sd += .1)), rand(vec2(sd += .1, sd += .1)) ); } vec3 rayDirection(float fov, vec2 size, vec2 fragCoord) { vec2 xy = fragCoord - size / 2.0; float z = size.y / tan(radians(fov) / 2.0); return normalize(vec3(xy, -z)); } bool sphere(hitable sp, ray r, float tMin, inout record hr, out material mat) { vec3 oc = r.o - sp.c; float a = dot(r.d, r.d); float b = dot(oc, r.d); float c = dot(oc, oc) - sp.r * sp.r; float d = b * b - a * c; if (d < 0.) return false; float s = sqrt(d); float val = (-b - s) / a; if (val > tMin && val < hr.t) { hr.p = r.o + val * r.d; hr.n = (hr.p - sp.c) / sp.r; hr.t = val; mat = sp.mat; return true; } val = (-b + s) / a; if (val > tMin && val < hr.t) { hr.p = r.o + val * r.d; hr.n = (hr.p - sp.c) / sp.r; hr.t = val; mat = sp.mat; return true; } return false; } bool worldHit(ray r, float tMin, float tMax, hitable[NUM_OBJECTS] sp, out record rec, out material mat) { bool hit = false; rec.t = tMax; for (int i = 0; i < NUM_OBJECTS; i++) { hit = sphere(sp[i], r, tMin, rec, mat) || hit; } return hit; } bool scatLamb(inout ray r, record rec, float sd) { vec3 t = normalize(rec.n + randomInUnitSphere(sd)); r.o = rec.p; r.d = t; return true; } bool scatMetal(inout ray r, record rec) { vec3 reflected = reflect(normalize(r.d), rec.n); r.o = rec.p; r.d = reflected; return (dot(reflected, rec.n) > 0.); } vec3 color(ray r, hitable[NUM_OBJECTS] sp, float sd) { const int MAX_RECURSION = 50; float tMax = FLT_MAX; vec3 col = vec3(1); record hr; for (int i = 0; i < MAX_RECURSION; i++) { material mat; if (worldHit(r, 0.001, FLT_MAX, sp, hr, mat)) { bool scat = mat.type == LAMBERTIAN ? scatLamb(r, hr, sd) : scatMetal(r, hr); if (scat) { col *= mat.albedo; } else { return vec3(0, 0, 0); } } else { float t = .5 * r.d.y + .5; col *= mix(vec3(1), vec3(.5, .7, 1.), t); return col; } } return col; } void main() { vec3 eye = vec3(0., 0., 5.); const int ns = 100; hitable spheres[NUM_OBJECTS]; spheres[0] = hitable(vec3(0, 0, -1), .5, material(LAMBERTIAN, vec3(.8, .3, .3))); spheres[1] = hitable(vec3(0, -100.5, -1), 100., material(LAMBERTIAN, vec3(.8, .8, 0))); spheres[2] = hitable(vec3(1, 0, -1), .5, material(METAL, vec3(.8, .6, .2))); spheres[3] = hitable(vec3(-1, 0, -1), .5, material(METAL, vec3(.8, .8, .8))); float sd = rand(gl_FragCoord.xy); vec3 col = vec3(0, 0, 0); float ins = 1. / float(ns); for (int i = 0; i < ns; i++) { float rv = rand(gl_FragCoord.xy + float(i) * ins); vec3 rd = rayDirection(45., uScreenSize.xy, gl_FragCoord.xy + rv); ray r = ray(eye, rd); col += color(r, spheres, sd); sd += 0.1; } col = col * ins; col = vec3(sqrt(col[0]), sqrt(col[1]), sqrt(col[2])); gl_FragColor = vec4(col, 1); }