허준혁Junhyeok Heo
Home

WebGPU lab

FFT로 만든 바다와 파티클 수만 개의 물리를 GPU가 매 프레임 계산합니다.

01FFT ocean

드래그해서 둘러볼 수 있고, 바람 세기를 바꾸면 GPU가 파도 스펙트럼을 다시 계산합니다.

  • JONSWAP 스펙트럼으로 바람·취송거리에 맞는 파도를 만들고, 크기가 다른 4개 캐스케이드(733m–7m)를 256² IFFT로 매 프레임 되돌립니다.
  • 행·열 IFFT를 각각 한 번의 디스패치로 끝냅니다. 워크그룹 공유 메모리에서 버터플라이 8단계를 돌고, 결과를 밉맵까지 컴퓨트로 채웁니다.
  • 야코비안이 1 아래로 접히는 곳에 거품을 쌓고 천천히 지워서 물마루 뒤로 흰 자국이 남습니다. 수면은 거리 기반 CDLOD 격자 하나를 인스턴싱해 수평선까지 덮습니다.
  • Tessendorf FFT
  • JONSWAP
  • Workgroup Memory
  • Storage Texture
  • CDLOD
  • GGX
row IFFT (TSL workgroup memory)
const shared = workgroupArray('vec4', N * 2);// 한 워크그룹이 한 행(256점)을 공유 메모리에서 끝낸다for (let s = 0; s < LOG2N; s++) {  const half = 1 << s;  const pos = t.bitAnd(half - 1);  const i = t.shiftRight(s).shiftLeft(s + 1).bitOr(pos);  const j = i.add(half);  // 트위들 팩터 e^(iπ·pos/half)  const w = vec2(cos(ang), sin(ang));  const a = shared.element(i);  const b = cmul(shared.element(j), w);  shared.element(i).assign(a.add(b));  shared.element(j).assign(a.sub(b));  workgroupBarrier();}

02Compute particles

포인터를 움직이면 파티클이 밀려납니다. 입력이 없으면 자동으로 휘젓습니다.
  • three.js WebGPURenderer 위에서 TSL(Three Shading Language)로 셰이더를 TypeScript로 작성하고, WGSL로 컴파일합니다.
  • 위치·속도를 GPU 스토리지 버퍼에 두고 컴퓨트 패스에서 스프링·반발·감쇠를 적분하므로 CPU는 유니폼만 넘깁니다.
  • WebGPU가 없으면 같은 TSL 코드가 GLSL로 컴파일되어 WebGL2에서 돌고, 그마저 없으면 정지 이미지로 내려갑니다.
  • three/webgpu
  • TSL
  • WGSL
  • Compute Shader
  • Storage Buffer
compute pass (TSL)
const update = Fn(() => {  const p = pos.element(instanceIndex);  const v = vel.element(instanceIndex);  // 제자리로 끌어당기는 스프링  const force = target.sub(p).mul(SPRING).toVar();  // 포인터 근처에서는 밀어낸다  const d = p.sub(uPointer);  const push = smoothstep(0, RADIUS, length(d)).oneMinus();  force.addAssign(normalize(d).mul(push.mul(REPEL)));  v.addAssign(force.mul(uDelta));  v.mulAssign(exp(uDelta.mul(-DAMPING)));  p.addAssign(v.mul(uDelta));})().compute(COUNT);