---
title: "WebGPU로 브라우저에서 실시간 글로벌 일루미네이션 구현하기 — Surfel 기반 파이프라인"
published: 2026-01-29T23:05:18.000Z
canonical: https://jeff.news/article/1272
---
# WebGPU로 브라우저에서 실시간 글로벌 일루미네이션 구현하기 — Surfel 기반 파이프라인

Surfel(Surface Element) 기반 글로벌 일루미네이션을 WebGPU로 브라우저에서 구현한 프로젝트. 13개 이상의 컴퓨트 패스, 소프트웨어 BVH 레이 트레이싱, MSME 시간적 안정화까지 TypeScript+WGSL 약 3000줄로 60fps 달성.

## WebGPU로 브라우저에서 실시간 글로벌 일루미네이션을 구현한 이야기

- Surfel(Surface Element)이라는 3D 공간의 납작한 디스크를 이용해 **웹 브라우저에서 실시간 글로벌 일루미네이션(GI)**을 구현한 프로젝트임. 위치·법선·반지름으로 정의되는 surfel로 조명 계산을 스크린 해상도에서 분리해, 5만 개의 surfel만 셰이딩해도 200만 픽셀의 GI를 처리할 수 있다는 게 핵심

- EA SEED가 SIGGRAPH 21에서 발표한 surfel 기반 GI 기법에서 영감을 받았고, SIGGRAPH 2025 밴쿠버에서 본 "SurfelPlus" 포스터의 "저사양 GPU에서도 풍부한 동적 간접 조명을 실시간으로" 라는 문구가 "저사양 GPU ≈ 웹"이라는 발상으로 이어진 거임

## 파이프라인: 프레임당 13개 이상의 컴퓨트 패스

### 1. Surfelization — 지오메트리를 surfel로 변환

- G-buffer(깊이, 법선, 알베도)를 렌더링한 뒤, 빠진 곳에 surfel을 스폰하고, 기존 surfel과 비교해서 원자적 병렬 경쟁을 거쳐 승자만 살아남는 방식. 프로덕션 수준에서는 공간 데이터 구조 유지·라이프사이클 관리 등 10개 이상의 컴퓨트 패스가 필요함

### 2. 그리드 — 공간 가속 구조

- Kajiya 렌더러에서 영감받은 카메라 중심 캐스케이드 3D 공간 인덱스. 가까운 surfel은 정밀한 셀, 먼 surfel은 큰 셀로 관리하는 멀티-레졸루션 구조임
- 빌드 과정: 셀 카운터 초기화 → 원자적 증가로 셀별 surfel 수 카운트 → prefix-sum 스캔 → atomic decrement 트릭으로 슬로팅. 결과적으로 O(1)로 셀의 surfel 인덱스에 접근 가능
- 이거 없으면 픽셀마다 512개 surfel을 전부 비교해야 해서 사실상 불가능

### 3. 레이 트레이싱 — 하드웨어 RT 없이

- WebGPU에는 하드웨어 레이 트레이싱 지원이 없음. 대신 **three-mesh-bvh** 라이브러리를 사용해 CPU에서 BVH(Bounding Volume Hierarchy)를 빌드하고 GPU 컴퓨트 셰이더에서 쿼리하는 방식으로 에뮬레이션
- 머티리얼 샘플링은 2D 배열 텍스처에 모든 디퓨즈 텍스처를 레이어로 쌓고, 삼각형마다 matId를 저장해서 히트 시 (uv, matId)로 샘플링하는 해킹적 접근

### 4. 가이딩 — 빛이 오는 방향 학습

- 각 surfel이 반구 위에 8×8(64 bin) 가중치 그리드를 유지함. 레이가 밝은 방향을 발견하면 해당 bin의 가중치를 올리고, 시간이 지나면 밝은 방향으로 레이를 더 많이 쏘는 구조
- 탐색(exploration)과 활용(exploitation) 균형을 위해 가이딩 확률과 코사인 반구 샘플링을 혼합하고, **혼합 확률밀도함수(mixPdf)**로 편향 없는 추정을 유지함
- 새로 태어난 surfel은 탐색을 많이 하고, 성숙한 surfel은 활용을 많이 하는 설계가 귀여움

### 5. 시간적 안정성 — MSME

- 단순 지수 이동 평균(EMA)은 반응이 빠르면 노이즈가 심하고, 안정적이면 느림. **MSME(Multi-Scale Mean Estimator)**는 장기/단기 두 개의 평균을 추적해, 실제 변화에는 빠르게 반응하되 노이즈에는 과잉반응하지 않음
- EA SEED의 PICA PICA 파이프라인(Ray Tracing Gems 25장)에서 소개된 알고리즘

### 6. 빛 누수 해결 — Radial Depth Atlas

- Surfel이 벽 가장자리에 있으면 반대편으로 빛이 새는 문제가 있음. 각 surfel에 360도 깊이 카메라(4×4 픽셀 타일)를 달아서 주변 지오메트리까지의 거리를 기록하고, **Moment Shadow Mapping(MSM)**으로 부드러운 가시성 함수를 재구성해 벽 뒤로 빛이 새는 걸 차단

### 7. Resolve — surfel에서 픽셀로

- 모든 픽셀에 대해 G-buffer 깊이로 월드 좌표를 계산하고, 그리드에서 주변 surfel을 찾아서 거리·방향·나이·오클루전 가중치를 적용해 최종 색상을 결정

## 결과와 한계

> [!IMPORTANT]
> 전체 파이프라인이 TypeScript + WGSL **약 3,000줄**로 구현됨. 적당한 복잡도의 씬에서 60fps로 동작하고, iPhone 14의 모바일 Safari에서도 Cornell Box 씬이 60fps

- 한계: Chrome의 스토리지 버퍼 상한이 컴퓨트 패스당 **10개**라 read-write float 스토리지 텍스처로 우회하는 등 바인딩 한계와 싸워야 했음. Firefox/Safari는 더 많은 바인딩을 지원하지만 float 스토리지 텍스처를 못 씀
- 하드웨어 RT가 없어서 다수 광원, 동적 지오메트리 지원이 어려움. 현재는 단일 디렉셔널 라이트 + 환경 맵의 정적 지오메트리 디퓨즈 반사만 지원
- 스페큘러/글로시 반사, 투명도, AO, 이미시브 없음. 그래도 브라우저에서 물리 기반 빛 반사와 시간적 안정성이 돌아가는 것 자체가 "미래에 와 있는" 느낌이라고

## 핵심 포인트

- Surfel로 조명 계산을 스크린 해상도에서 분리해 5만 개로 200만 픽셀 GI 처리
- 하드웨어 RT 없이 three-mesh-bvh로 BVH 에뮬레이션
- 가이딩 시스템으로 밝은 방향에 레이를 집중하고 MSME로 시간적 안정화
- Radial Depth Atlas + MSM으로 빛 누수 문제 해결
- TypeScript+WGSL 3000줄, iPhone 14 Safari에서도 60fps

## 인사이트

WebGPU의 성숙도를 증명하는 프로젝트. 몇 년 전에는 불가능했던 컴퓨트 중심 렌더링 파이프라인이 브라우저에서 돌아간다는 게 인상적
