- Sign In
- Sign Up
Tracing Boilerplate
A simple starting point for simple tracing scenes
Created by marcogomez on Sun, 22 May 2022 09:36:48 GMT.
#version 300 es precision highp float; out vec4 fragColor; uniform sampler2D prgm1Texture; uniform vec2 resolution; uniform float time; void main(void) { vec2 uv = gl_FragCoord.xy / resolution.xy; vec4 tex = texture(prgm1Texture, uv); vec3 col = tex.xyz / tex.w; col = mix(col, pow(col, vec3(0.4545)), 0.5); fragColor = vec4(col, 1.0); }
#version 300 es precision highp float; uniform sampler2D prgm1Texture; uniform float time; uniform vec2 resolution; uniform vec4 mousedrag; const float PI = acos(-1.0); const float TAU = PI * 2.0; const float HALF_PI = PI * 0.5; out vec4 fragColor; const vec3 sunDir = normalize(vec3(0.8, 0.5, -1.0)); const vec3 sunCol = vec3(0.5, 0.7, 1.0); struct Ray { vec3 ro; vec3 rd; }; struct Hit { int id; vec3 p; vec3 n; float t; }; struct Material { vec3 albedo; bool is_metal; float fuzz; bool isGlass; float refID; vec3 phong; }; float mtime = 0.0; float sphereIntersect(Ray ray, vec4 sph) { vec3 c = sph.xyz; float r = sph.w; vec3 co = ray.ro - c; float b = dot(co, ray.rd); float d = b * b - dot(co, co) + r * r; if (d < 0.0) { return -1.0; } float sd = sqrt(d); vec2 t = vec2(-b - sd, -b + sd); if (t.x < 0.0) { return t.y; } return t.x; } float planeIntersect(Ray ray, vec3 n) { return -dot(ray.ro, n) / dot(ray.rd, n); } vec3 sphereNormal(vec3 p, vec4 sph) { return normalize(p - sph.xyz); } float sphereShadow(vec3 ro, vec3 rd, vec4 sph, float k) { vec3 oc = ro - sph.xyz; float b = dot(oc, rd); float c = dot(oc, oc) - sph.w * sph.w; float h = b * b - c; float d = -sph.w + sqrt(max(0.0, sph.w * sph.w - h)); float t = -b - sqrt(max(0.0, h)); return (t < 0.0) ? 1.0 : smoothstep(0.0, 1.0, k * d / t); } float fresnel(Ray ir, Hit hit, float eta) { float r0 = (1.0 - eta) / (1.0 + eta); r0 *= r0; float cos_t = dot(-ir.rd, hit.n); cos_t = clamp(cos_t, 0.0, 1.0); return r0 + (1.0 - r0) * pow(1.0 - cos_t, 5.0); } float hash21(vec2 p) { vec3 p3 = fract(vec3(p.xyx) * 0.1031); p3 += dot(p3, p3.yzx + 33.33); return fract((p3.x + p3.y) * p3.z); } vec2 hash22(vec2 p) { vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973)); p3 += dot(p3, p3.yzx + 33.33); return fract((p3.xx + p3.yz) * p3.zy); } float hash31(vec3 p) { p = fract(p * 0.1031); p += dot(p, p.zyx + 31.32); return fract((p.x + p.y) * p.z); } vec2 hash12(float p) { vec3 p3 = fract(vec3(p) * vec3(0.1031, 0.1030, 0.0973)); p3 += dot(p3, p3.yzx + 33.33); return fract((p3.xx + p3.yz) * p3.zy); } vec3 sphereRND(vec3 p) { float f = hash31(p); float theta = TAU * hash21(vec2(f * 0.3482, f * 2.18622)); float phi = acos(1.0 - 2.0 * hash21(vec2(f * 1.9013, f * 0.94312))); float x = sin(phi) * cos(theta); float y = sin(phi) * sin(theta); float z = cos(phi); return vec3(x,y,z); } vec4 spheres[] = vec4[]( vec4(vec3(0.0), 0.7), vec4(vec3(0.0), 0.7), vec4(vec3(0.0), 0.7), vec4(vec3(0.0), 0.7), vec4(vec3(0.0), 0.7), vec4(vec3(0.0), 0.7) ); // materials[id] is the material of the object with this id const Material materials[] = Material[]( Material(vec3(0.7, 0.7, 0.7), true, 0.50, false, 0.0, vec3(1.0, 2.0, 10.0)), Material(vec3(0.5, 0.4, 0.3), false, 0.00, false, 0.0, vec3(1.0, 10.0, 10.0)), Material(vec3(1.0, 1.0, 1.0), false, 0.00, true, 1.4, vec3(0.0, 1.0, 100.0)), Material(vec3(0.4, 0.7, 0.3), true, 0.50, false, 0.0, vec3(1.0, 0.5, 50.0)), Material(vec3(0.8, 0.8, 0.8), true, 0.20, false, 0.0, vec3(1.0, 2.0, 72.0)), Material(vec3(0.3, 0.2, 0.9), false, 0.00, false, 0.0, vec3(1.0, 0.0, 0.0)), Material(vec3(0.9, 0.3, 0.2), true, 0.05, false, 0.0, vec3(1.0, 20.0, 1000.0)) ); void closest(float test_t, int test_id, inout float t, inout int id) { if (test_t > 0.0 && test_t < t) { t = test_t; id = test_id; } } bool sceneIntersect(Ray ray, inout Hit hit) { float angle = TAU / float(6); float t = 10000.0; int id = -1; vec3 groundNormal = vec3(0.0, 1.0, 0.0); closest(planeIntersect(ray, groundNormal), 0, t, id); for (int i = 0; i < 6; i++) { float bounce = fract(mousedrag.w * 0.8 + sin(float(i) / float(6) - 0.25)) - 0.5; spheres[i].xyz = vec3( cos(float(-i) * angle) * 2.0, spheres[i].w + 3.0 * (0.25 - bounce * bounce), sin(float(-i) * angle) * 2.0 ); vec4 sph = spheres[i]; closest(sphereIntersect(ray, sph), i + 1, t, id); } vec3 p = ray.ro + ray.rd * t; vec3 n = groundNormal; if (id > 0) { n = sphereNormal(p, spheres[id - 1]); } hit = Hit(id, p, n, t); return id >= 0; } vec3 background(Ray ray) { vec3 ca = vec3(0.95, 0.65, 0.55); vec3 cb = vec3(0.3, 0.6, 1.0); float f = dot(ray.rd, vec3(0.0, 1.0, 0.0)); f = max(0.0, f); f = pow(f, 0.3); vec3 col = mix(ca, cb, f); f = dot(ray.rd, sunDir); f = max(0.0, f); float k = smoothstep(0.9, 0.999, f * f); col += vec3(1.0, 0.8, 0.4) * k * 0.1; col += step(0.9997, f); return clamp(col, 0.0, 1.0); } float shadow(Hit hit) { Ray ray = Ray(hit.p + hit.n * 0.001, sunDir); float s = 1.0; for (int i = 0; i < 6; i++) { s *= sphereShadow(ray.ro, ray.rd, spheres[i], 12.0); } return s; } vec3 directLighting(Ray ir, Hit hit, Material mat, vec3 surfaceColor) { float kd = mat.phong.x; float ks = mat.phong.y; float sh = mat.phong.z; vec3 v = normalize(ir.ro - hit.p); vec3 r = reflect(-sunDir, hit.n); vec3 h = normalize(sunDir + v); float diff = kd * max(0.0, dot(sunDir, hit.n)); float spec = ks * pow(max(0.0, dot(hit.n, h)), sh); float cos_t = dot(h, sunDir); vec3 r0 = mat.is_metal ? surfaceColor : vec3(0.1); vec3 fre = r0 + (1.0 - r0) * pow(abs(clamp(1.0 - cos_t, 0.0, 1.0)), 5.0); float shad = shadow(hit); vec3 col = vec3(0.0); if (!mat.is_metal) { col += surfaceColor * sunCol * diff * shad; } col += sunCol * diff * spec * shad * fre; return clamp(col, 0.0, 1.0); } Ray lambertScatter(Ray ir, Hit hit, Material mat) { vec3 ro, rd; rd = hit.n + sphereRND(hit.p + time); if (dot(rd, rd) < 0.001) { rd = hit.n; } rd = normalize(rd); ro = hit.p + hit.n * 0.001; return Ray(ro, rd); } Ray metalScatter(Ray ir, Hit hit, Material mat) { vec3 rd = reflect(ir.rd, hit.n); vec3 f = mat.fuzz * sphereRND(hit.p + time); rd = normalize(rd + f); vec3 ro = hit.p + hit.n * 0.001; return Ray(ro, rd); } Ray glassScatter(Ray ir, Hit hit, Material mat) { vec3 rd, ro; float eta = mat.refID; if (dot(ir.rd, hit.n) < 0.0) { eta = 1.0 / eta; if (fresnel(ir, hit, eta) > hash31(hit.p + time)) { rd = reflect(ir.rd, hit.n); ro = hit.p + hit.n * 0.001; } else { rd = refract(ir.rd, hit.n, eta); ro = hit.p - hit.n * 0.001; } } else { // inside the sphere rd = refract(ir.rd, -hit.n, eta); ro = hit.p + hit.n * 0.001; } return Ray(ro, rd); } float hash(vec2 uv) { return fract(sin(dot(uv.xy, vec2(12.9898, 78.233))) * 43758.5453123); } vec2 truchetPattern(vec2 uv, float index) { index = fract(((index - 0.5) * 2.0)); if (index > 0.75) { uv = vec2(1.0) - uv; } else if (index > 0.50) { uv = vec2(1.0 - uv.x, uv.y); } else if (index > 0.25) { uv = 1.0 - vec2(1.0 - uv.x, uv.y); } return uv; } float curvedTruchet(vec2 uv) { vec2 ouv = uv; uv *= 1.0; vec2 ipos = floor(uv); vec2 fpos = fract(uv); vec2 tile = truchetPattern(fpos, hash(ipos)); float a = ( (step(length(tile), 0.6) - step(length(tile), 0.4)) + (step(length(tile - vec2(1.0)), 0.6) - step(length(tile - vec2(1.0)), 0.4)) ); float curves = a / length(ouv * 0.8) * 0.5; return clamp(curves, 0.0, 1.0); } vec3 surfaceTexture(Hit hit) { if (hit.id == 0) { // Checker texture vec2 uv = hit.p.xz; float ct = curvedTruchet(uv); return mix(vec3(0.1, 0.1, 0.3), vec3(1.0), ct); } return vec3(1.0); } vec3 render(Ray ray){ // color of one ray sample const int depth = 12; // number of rays vec3 colorMask = vec3(1.0); vec3 accumulatedColor = vec3(0.0); for (int i = 0; i < depth; i++) { Hit hit; if (sceneIntersect(ray, hit)) { Material mat = materials[hit.id]; vec3 surfaceColor = mat.albedo * surfaceTexture(hit); accumulatedColor += directLighting(ray, hit, mat, surfaceColor * colorMask); colorMask *= surfaceColor; if (mat.is_metal) { ray = metalScatter(ray, hit, mat); } else if (mat.isGlass) { ray = glassScatter(ray, hit, mat); } else { ray = lambertScatter(ray, hit, mat); } } else { accumulatedColor += colorMask * background(ray); break; } } return accumulatedColor; } vec3 getCameraPosition(float mx, float my) { float acc = 0.0; const float camHeight = 0.5; const float camDistanceRadius = 6.5; float camPosX = sin(mx * PI * 2.0) * camDistanceRadius; float camPosY = camHeight + (my * 0.5 + 0.5) * 5.0; float camPosZ = cos(mx * PI * 2.0) * camDistanceRadius; vec3 ro = vec3(camPosX, camPosY, camPosZ); return ro; } mat3 calcLookAtMatrix(vec3 origin, vec3 target, float roll) { vec3 rr = vec3(sin(roll), cos(roll), 0.0); vec3 ww = normalize(target - origin); vec3 uu = normalize(cross(ww, rr)); vec3 vv = normalize(cross(uu, ww)); return mat3(uu, vv, ww); } vec3 getCameraTarget(vec2 uv, vec3 ro, float aaSamples) { vec3 col = vec3(0.0); vec3 camTarget = vec3(0.0, 0.5, 0.0); float camRoll = 0.0; float fov = 1.25; mat3 camMatrix = calcLookAtMatrix(ro, camTarget, camRoll); for (float i = 0.0; i < aaSamples; i++) { vec2 rnd = (1.0 / resolution.x) * (-1.0 + 2.0 * hash12(i + time)); vec3 rd = normalize(camMatrix * vec3(uv + rnd, fov)); Ray ray = Ray(ro, rd); col += render(ray); } col /= aaSamples; return col; } void main(void) { vec2 uv = gl_FragCoord.xy / resolution.xy; vec4 tex = texture(prgm1Texture, uv); if (mousedrag.z == 1.0) { tex *= 0.0; } uv -= 0.5; uv.x *= resolution.x / resolution.y; vec3 ro = getCameraPosition(mousedrag.x, mousedrag.y); vec3 col = vec3(0.0); col += getCameraTarget(uv, ro, 8.0); col = clamp(col, 0.0, 1.0); tex += vec4(col, 1.0); fragColor = tex; }
xxxxxxxxxx
precision highp float;
out vec4 fragColor;
uniform sampler2D prgm1Texture;
uniform vec2 resolution;
uniform float time;
void main(void) {
vec2 uv = gl_FragCoord.xy / resolution.xy;
vec4 tex = texture(prgm1Texture, uv);
vec3 col = tex.xyz / tex.w;
col = mix(col, pow(col, vec3(0.4545)), 0.5);
fragColor = vec4(col, 1.0);
}
97 fps 15ms
00:00:00.32
0.00