No still was sent with this entry.
Photon prism path tracer
Source
"use typeshade";
class Uniforms {
time: f32
resolution: vec2
mouse: vec2
}
declare const u: uniform<Uniforms>;
// 전역 상태 변수 모방 (BP는 main에서 계산 후 할당)
let BP: vec2 = vec2(0.0);
const W: i32 = 5;
function bx(p: vec2, b: vec2): f32 {
const d: vec2 = abs(p) - b;
return length(max(d, vec2(0.0))) + min(max(d.x, d.y), 0.0);
}
function rt(a: f32): mat2 {
const c: f32 = cos(a);
const s: f32 = sin(a);
return mat2(c, -s, s, c);
}
function S(p: vec2): f32 {
return min(-bx(p, vec2(1.9, 0.85)),
min(bx(p - BP, vec2(0.14, 0.35)),
min(bx(rt(0.6) * (p - vec2(0.05, -0.7)), vec2(0.15)),
bx(rt(-0.3) * (p - vec2(0.9, 0.1)), vec2(0.22, 0.05)))));
}
function G(p: vec2): f32 {
const k: f32 = 1.7320508;
let p_mod: vec2 = p - vec2(-0.6, -0.05);
p_mod.x = abs(p_mod.x) - 0.3;
p_mod.y = p_mod.y + (0.3 / k);
if (p_mod.x + k * p_mod.y > 0.0) {
p_mod = vec2(p_mod.x - k * p_mod.y, -k * p_mod.x - p_mod.y) / 2.0;
}
p_mod.x = p_mod.x - clamp(p_mod.x, -0.6, 0.0);
return -length(p_mod) * sign(p_mod.y);
}
function gs(x: f32, m: f32, a: f32, b: f32): f32 {
const denom: f32 = x < m ? a : b;
const x_norm: f32 = (x - m) / denom;
return exp(-0.5 * x_norm * x_norm);
}
function spec(l: f32): vec3 {
const c: vec3 = vec3(
1.056 * gs(l, 599.8, 37.9, 31.0) + 0.362 * gs(l, 442.0, 16.0, 26.7) - 0.065 * gs(l, 501.1, 20.4, 26.2),
0.821 * gs(l, 568.8, 46.9, 40.5) + 0.286 * gs(l, 530.9, 16.3, 31.1),
1.217 * gs(l, 437.0, 11.8, 36.0) + 0.681 * gs(l, 459.0, 26.0, 13.8)
);
// GLSL mat3 행/열 순서 1:1 매칭 변환
const m3: mat3 = mat3(
3.2406, -1.5372, -0.4986,
-0.9689, 1.8758, 0.0415,
0.0557, -0.204, 1.057
);
return max(m3 * c, vec3(0.0));
}
@fragment
export function main(@location(0) uv: vec2): vec4 {
const res: vec2 = u.resolution;
// 정규화 화면 좌표 p 구성
const p: vec2 = ((uv * u.resolution) - 0.5 * res) / res.y * 2.0;
const e: vec2 = vec2(0.002, 0.0);
const E: vec2 = vec2(-1.7, -0.28);
// 마우스 인터랙션 바인딩 및 가두기
if (u.mouse.x > 0.0) {
BP = clamp(((u.mouse * u.resolution) - 0.5 * res) / res.y * 2.0, vec2(-1.72, -0.49), vec2(1.72, 0.49));
} else {
BP = vec2(0.85, -0.5);
}
const t: f32 = u.time;
const d: f32 = S(p);
const sol: f32 = step(d, 0.0);
let h: f32 = 0.0;
let k: f32 = 0.0;
const a: f32 = 0.32 + 0.05 * sin(t * 0.4);
const N: vec2 = normalize(vec2(
S(p + e) - S(p - e),
S(p + vec2(e.y, e.x)) - S(p - vec2(e.y, e.x))
));
const q: vec2 = p + sol * N * (0.03 - d);
let C: vec3 = vec3(0.01);
let B: vec3 = vec3(0.0);
// 프리즘 스펙트럼 광선 분산 루프
for (let i: i32 = 0; i < W; i++) {
const lam: f32 = 400.0 + 300.0 * (f32(i) + 0.5) / f32(W);
const l: f32 = lam * 0.001;
const nu: f32 = 1.5 + 0.03 / (l * l);
let fl: f32 = 1.0;
let cum: f32 = 0.0;
const col: vec3 = spec(lam) * 2.8 / f32(W);
let o: vec2 = E;
let r: vec2 = vec2(cos(a), sin(a));
let x: vec2 = o;
let g: vec2 = vec2(0.0);
let in_refract: bool = false;
let hit: i32 = 0;
// 바운스 레이 트레이싱 루프
for (let s: i32 = 0; s < 8; s++) {
k = 0.0;
for (let j: i32 = 0; j < 48; j++) {
x = o + r * k;
h = in_refract ? -G(x) : min(G(x), S(x));
if (h < 0.0015 || k > 5.0) { break; }
k = k + h;
}
if (h > 0.02 || k > 5.0) { break; }
const ni: f32 = in_refract ? nu : 1.0;
const pa: vec2 = p - o;
const u_dot: f32 = clamp(dot(pa, r), 0.0, k);
const dv: vec2 = pa - r * u_dot;
B = B + col * fl * 0.0002 / (dot(dv, dv) + 0.0002);
for (let j: i32 = 0; j < 1; j++) {
const sp: f32 = fract(t * 0.22 + f32(j) * 0.5) * 7.0 - cum;
if (sp > 0.0 && sp < k * ni) {
const pp: vec2 = p - o - r * sp / ni;
B = B + col * fl * 0.0008 / (dot(pp, pp) + 0.0008) * 4.0;
}
}
cum = cum + k * ni;
if (in_refract || G(x) < S(x)) {
g = normalize(vec2(
G(x + e) - G(x - e),
G(x + vec2(e.y, e.x)) - G(x - vec2(e.y, e.x))
));
if (in_refract) { g = -g; }
let f: vec2 = refract(r, g, in_refract ? nu : 1.0 / nu);
if (dot(f, f) < 0.5) {
f = reflect(r, g);
} else {
in_refract = !in_refract;
}
r = f;
o = x + r * 0.006;
} else {
g = normalize(vec2(
S(x + e) - S(x - e),
S(x + vec2(e.y, e.x)) - S(x - vec2(e.y, e.x))
));
B = B + col * fl * 0.0012 / (dot(p - x, p - x) + 0.0012) * 2.0;
if (hit < 3) {
const v_dir: vec2 = x + g * 0.03 - q;
const D: f32 = length(v_dir) + 0.0001;
let vis: f32 = 1.0;
let tt: f32 = 0.012;
const v_norm: vec2 = v_dir / D;
for (let j: i32 = 0; j < 14; j++) {
h = S(q + v_norm * tt);
vis = min(vis, D * h / (0.05 * tt));
tt = tt + clamp(h, 0.015, 0.2);
if (vis < 0.01 || tt > D - 0.03) { break; }
}
C = C + col * fl * clamp(vis, 0.0, 1.0) * max(dot(g, -v_norm), 0.0)
* mix(1.0, max(dot(N, v_norm), 0.0), sol) * mix(0.5, 1.0, sol) * 0.25 / (D + 0.2);
}
r = reflect(r, g);
o = x + g * 0.006;
fl = fl * 0.55;
hit = hit + 1;
}
}
}
const gl: f32 = G(p);
C = C * mix(1.0, 0.9 * exp(4.0 * d), sol);
C = C + vec3(0.5, 0.7, 1.0) * (0.03 * step(gl, 0.0) + 0.08 * exp(-abs(gl) * 80.0)) + B
+ 0.3 * 0.0004 / (dot(p - E, p - E) + 0.0004);
return vec4(pow(1.0 - exp(-2.0 * C), vec3(0.4545)), 1.0);
}