프롤로그 — WebGL은 어른이 되었고, WebGPU는 어제 일이 되었다
2010년대 후반, 웹에서 3D를 한다는 건 "WebGL"을 한다는 뜻이었다. Three.js가 그 위에 사람답게 쓸 수 있는 추상을 얹었고, 우리는 GLSL 셰이더를 두 벌(WebGL용·WebGPU용)로 유지하며 살았다.
2026년 1월, 그 풍경이 완전히 바뀌었다. Safari 26이 macOS Tahoe와 iOS에서 WebGPU를 정식 출시하면서, **WebGPU는 Baseline이 되었다.** Chrome·Edge·Firefox·Safari 모두 기본으로 켜져 있고, 전역 커버리지는 약 95%다. 나머지 5%는 Three.js의 자동 폴백이 WebGL 2로 처리한다.
이 한 줄로 끝나는 변화가 아니다.
- Three.js r182(2025년 12월 릴리스)가 `WebGPURenderer`를 **권장 렌더러**로 올렸다.
- **TSL(Three Shading Language)** — 한 번 짠 셰이더가 WGSL과 GLSL로 동시에 컴파일된다. 두 벌 유지가 끝났다.
- React Three Fiber v9이 **비동기 `gl` prop**을 받아 WebGPU 초기화를 자연스럽게 처리한다.
- **Gaussian Splatting**이 폴리곤 메시와 나란히 — 폴리곤 없이 — 사진실적 씬을 실시간으로 그리는 새로운 표현이 되었다.
- Meshy·Tripo·Rodin은 텍스트 한 줄로 PBR 텍스처 입은 메시를 뽑는다.
이 글은 2026년의 웹 3D 스택을 **한 호흡으로** 정리한다. 처음 씬을 띄우는 코드부터 R3F·WebGPU·gsplat·AI 3D까지, 그리고 그 사이에서 "어디서 어떤 도구를 쓸지" 결정하는 매트릭스까지.
1장 · 렌더링 파이프라인 — 3D는 어떻게 그려지는가
먼저 그림 한 장. 도구를 알기 전에, 도구가 **무엇을 하는지**부터 봐야 한다.
[Scene Graph]
| (mesh / light / camera 트리)
v
[CPU: JS] -- 매트릭스·컬링·정렬 ----+
|
v
[Draw Call]
|
GPU 파이프라인 ──────────────────┴────────────────
| |
v v
Vertex Shader -> Rasterizer -> Fragment Shader
(정점 변환) (픽셀로 자르기) (픽셀 색)
| |
v v
Z-buffer / Blend / Output
|
v
[Framebuffer]
|
v
이 파이프라인의 어디를 누가 책임지는가가 곧 스택 선택의 기준이 된다.
- **CPU 쪽** — 씬 그래프, 변환 행렬, 컬링, 정렬. 여기서 끝까지 책임지는 건 Three.js다. R3F는 그 위에 React식 선언으로 얹는다.
- **드로우 콜** — GPU로 던지는 명령 단위. **이게 적을수록 빠르다.** 인스턴싱·머지·아틀라스가 다 이걸 줄이는 기술이다.
- **셰이더(Vertex·Fragment)** — GPU에서 도는 작은 프로그램. WebGL은 GLSL, WebGPU는 WGSL. **TSL이 둘을 하나로 묶는다.**
- **출력 합성** — Z-buffer·블렌딩·후처리(post-processing).
기억할 한 줄: **"드로우 콜이 모든 것의 절반이고, 셰이더가 나머지 절반이다."**
2장 · Three.js — 웹 3D의 사실상 표준
숫자부터. Three.js는 npm 주간 다운로드 **270만**으로 Babylon.js의 약 270배, PlayCanvas의 약 337배다. "사실상 표준"이 아니라 **그냥 표준**이다.
가장 작은 씬을 띄우는 코드. 세 가지가 필요하다: **씬·카메라·렌더러**, 그리고 안에 들어갈 **메시**.
// 1. 씬 — 모든 것이 들어가는 컨테이너
const scene = new THREE.Scene()
// 2. 카메라 — 어디서 보는가
const camera = new THREE.PerspectiveCamera(
75, // fov(시야각, degree)
window.innerWidth / window.innerHeight,
0.1, // near clip
1000 // far clip
)
camera.position.z = 5
// 3. 렌더러 — 2026년 기본은 WebGPURenderer
const renderer = new WebGPURenderer({ antialias: true })
await renderer.init() // 비동기 초기화 — 중요
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
// 4. 메시 = Geometry + Material
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshStandardMaterial({ color: 0x44aa88 })
const cube = new THREE.Mesh(geometry, material)
scene.add(cube)
// 5. 라이트 — 표준 머티리얼은 빛이 없으면 검정으로 보인다
scene.add(new THREE.AmbientLight(0xffffff, 0.4))
const dir = new THREE.DirectionalLight(0xffffff, 1.0)
dir.position.set(5, 10, 7.5)
scene.add(dir)
// 6. 루프 — requestAnimationFrame이 아니라 setAnimationLoop
renderer.setAnimationLoop(() => {
cube.rotation.x += 0.01
cube.rotation.y += 0.01
renderer.render(scene, camera)
})
세 가지를 짚는다.
1. **`await renderer.init()`** — WebGPU는 비동기다. 이 한 줄을 잊으면 첫 프레임이 검정이다.
2. **`MeshStandardMaterial`은 라이트가 필요하다** — 화면이 검정이면 라이트부터 의심한다.
3. **`setAnimationLoop`** — `requestAnimationFrame` 대신. WebXR이 자동으로 잡힌다.
이게 모든 Three.js 코드의 뼈대다. 나머지는 이 위에 얹는 것이다.
3장 · React Three Fiber + drei — React식 3D
명령형 코드는 작을 때는 깔끔하지만, 씬이 50개 노드를 넘어가면 빠르게 누더기가 된다. **React Three Fiber(R3F)** 는 Three.js를 React 컴포넌트 트리로 표현한다.
같은 큐브를 R3F로 다시 쓰면:
function Cube() {
return (
)
}
export default function Scene() {
return (
)
}
같은 일을 한다. 그런데:
- 씬 그래프가 **React 트리**다. 조건부 렌더링·상태 관리·Hooks가 그대로 통한다.
- `<Canvas>` 는 리사이즈·렌더 루프·픽셀 비율을 알아서 잡는다.
- **drei** — Poimandres 팀의 헬퍼 라이브러리. `OrbitControls`·`Environment`·`useGLTF`·`Html`·`Text` 같은 매일 쓰는 것들이 다 있다.
R3F v9의 WebGPU — 비동기 `gl` prop
R3F v9이 `gl` prop을 **비동기 팩토리**로 받을 수 있게 됐다. WebGPU 초기화가 자연스럽게 묶인다.
gl={async (props) => {
const renderer = new WebGPURenderer(props)
await renderer.init()
return renderer
}}
>
{/* ...씬... */}
2026년 5월 현재, R3F의 WebGPU 통합은 아직 완전히 매끄럽지는 않지만 — Poimandres 팀이 적극적으로 다듬는 중이고 — 위 패턴은 프로덕션에서 충분히 돈다. WebGL 2 폴백이 필요하면 `WebGLRenderer`를 던지면 된다.
`useFrame` — 매 프레임 훅
R3F의 가장 React스러운 부분. 컴포넌트가 매 프레임 호출되는 콜백을 등록한다.
function Spinner() {
const ref = useRef(null)
useFrame((state, delta) => {
if (ref.current) ref.current.rotation.y += delta
})
return (
)
}
`delta`는 이전 프레임으로부터의 초 단위 경과. **프레임률에 안 흔들리는 애니메이션의 출발점.**
4장 · WebGPU와 TSL — 셰이더 두 벌이 한 벌로
WebGL과 WebGPU의 차이를 한 문장: **WebGL은 OpenGL ES 2.0의 웹 포팅, WebGPU는 Vulkan·Metal·DX12 시대의 현대적 GPU API.**
실무적으로 무엇이 달라지는가:
- **드로우 콜 비용이 낮다** — 드로우 콜이 많은 씬(파티클·인스턴스 다수)에서 2~10배 빨라진다.
- **컴퓨트 셰이더가 1급 시민** — GPGPU(파티클·물리·시뮬레이션·포스트프로세싱)가 메인 파이프라인 안에서 자연스럽다.
- **WGSL** — WebGL의 GLSL 대신 새로운 셰이더 언어.
마지막이 항상 골치였다. WebGL 시대에 GLSL을 짰는데, WebGPU로 가려면 WGSL로 다시 써야 했다. **TSL이 이걸 끝낸다.**
**TSL = Three Shading Language.** 노드 기반 셰이더 추상. 한 번 짜면 Three.js가 내부적으로 **WGSL(WebGPU용)·GLSL(WebGL용) 양쪽으로 컴파일**한다.
간단한 노이즈 셰이더(머티리얼 색을 노이즈로 흔드는 예):
const speed = uniform(1.0)
const wave = sin(positionLocal.y.mul(8.0).add(time.mul(speed)))
const color = mix(vec3(0.1, 0.4, 0.9), vec3(1.0, 0.4, 0.2), wave.mul(0.5).add(0.5))
const material = new MeshStandardNodeMaterial()
material.colorNode = color
`positionLocal`·`time`·`mix`·`sin` 다 노드다. JS로 셰이더를 조립한다. **GLSL 텍스트도 WGSL 텍스트도 손으로 안 짠다.**
작은 WGSL 한 조각이 어떻게 생겼는지만 참고로 (TSL이 내부에서 비슷한 걸 만든다):
@fragment
fn fs_main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
let c = mix(vec3(0.1, 0.4, 0.9), vec3(1.0, 0.4, 0.2), sin(uv.y * 8.0) * 0.5 + 0.5);
return vec4(c, 1.0);
}
요는 — **2026년에는 직접 짤 일이 거의 없다.** TSL이 처리한다. WGSL을 한 번 읽어두는 정도면 충분하다.
5장 · glTF — 3D의 JPEG
폴리곤 모델을 웹으로 옮기는 표준은 **glTF 2.0**이다. "3D의 JPEG"라고 부른다. PBR 머티리얼·애니메이션·스킨·드라코 압축까지 한 파일에 들어간다.
Three.js의 로더:
const draco = new DRACOLoader()
draco.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/')
const loader = new GLTFLoader()
loader.setDRACOLoader(draco)
loader.load('/models/robot.glb', (gltf) => {
scene.add(gltf.scene)
// gltf.animations 에는 AnimationClip 배열이 들어있다
})
R3F + drei로는 한 줄이다:
function Robot() {
const { scene } = useGLTF('/models/robot.glb')
return <primitive object={scene} />
}
useGLTF.preload('/models/robot.glb')
`useGLTF`는 Suspense로 묶이고, 같은 모델을 여러 곳에서 쓰면 한 번만 로드한다. `preload`로 미리 받아둘 수도 있다.
glTF 최적화 — 3가지만 기억
1. **Draco 압축** — 정점 데이터를 압축. 파일 크기 5~10배 작아진다.
2. **KTX2 / Basis 텍스처** — JPG·PNG 대신 GPU가 바로 먹는 압축 텍스처. 메모리·로드 시간 절약.
3. **`gltf-transform` CLI** — 위 둘을 한 번에 해주는 도구. CI에 박아두면 더 이상 신경 안 써도 된다.
npx @gltf-transform/cli optimize input.glb output.glb \
--texture-compress webp --simplify 0.5
6장 · 애니메이션 — 클립부터 스프링까지
3D 애니메이션은 크게 세 갈래다.
1. **glTF에 들어있는 본/스킨 애니메이션** — Blender·Maya에서 만든 걸 그대로 재생.
2. **수학으로 도는 애니메이션** — `useFrame` 안에서 회전·트랜슬레이션.
3. **인터랙션 기반** — 호버·드래그·스크롤에 반응. 보통 **스프링 물리**로.
glTF 클립 재생
function Robot() {
const { scene, animations } = useGLTF('/models/robot.glb')
const { actions, names } = useAnimations(animations, scene)
useEffect(() => {
actions[names[0]]?.reset().fadeIn(0.3).play()
}, [actions, names])
return <primitive object={scene} />
}
스프링 애니메이션 — `react-spring/three`
function Box({ hovered }) {
const { scale } = useSpring({ scale: hovered ? 1.3 : 1.0 })
return (
)
}
값이 튀지 않고 **물리적으로 자연스럽게** 보간된다. 포트폴리오·랜딩 페이지의 미세한 디테일에 결정적이다.
7장 · 포스트프로세싱 — 한 끗 차이의 마감
같은 씬이라도 **블룸·SSAO·필름 그레인** 한 번 거치면 영상미가 다른 차원이 된다. 표준 라이브러리는 `postprocessing` (Vanruesc), R3F 래퍼는 `@react-three/postprocessing`.
{/* ...씬... */}
**조심할 점:** 포스트프로세싱은 **풀스크린 패스**다 — 픽셀이 많을수록 비싸다. 모바일에서는 항상 `pixelRatio`를 캡(보통 1.5~2.0)하고, 효과 두세 개만 고른다.
8장 · 성능 — 드로우 콜이 모든 것의 절반
3D 웹 성능은 거의 항상 **드로우 콜 수**와 **셰이더 비용** 두 곳에서 갈린다. 2026년의 핵심 패턴 다섯.
1. 인스턴싱 — 같은 메시 1만 개를 한 번에
같은 지오메트리·머티리얼의 메시를 여러 개 그려야 할 때(나무·풀·박스 더미), **인스턴싱**을 쓰면 드로우 콜이 1로 줄어든다.
{positions.map((p, i) => (
))}
WebGPU는 인스턴싱 비용이 더 낮다. **WebGL에서 5천 인스턴스가 한계였다면, WebGPU에서는 5만이 종종 돈다.**
2. 프러스텀 컬링·LOD
Three.js는 기본으로 카메라 시야 밖 객체를 그리지 않는다(프러스텀 컬링). 단, `Mesh.frustumCulled`는 기본 true니까 **끄지 말 것.** LOD(Level of Detail)는 카메라 거리에 따라 메시 해상도를 바꾼다.
3. 머티리얼·지오메트리 공유
같은 머티리얼·지오메트리는 메모리에서 단 한 벌만. R3F에서는 컴포넌트 바깥에서 만들어 공유한다.
4. 텍스처 — KTX2와 mipmap
JPG·PNG는 CPU에서 디코드 후 GPU로 업로드. KTX2(Basis Universal)는 **GPU가 압축 그대로 먹는다.** 로드는 빠르고, VRAM도 적게 쓴다.
5. `pixelRatio` 캡
레티나에서 `devicePixelRatio`가 3이면 화면 픽셀이 9배다. 항상 캡한다.
9장 · WebXR — VR·AR을 웹으로
`setAnimationLoop` 한 줄과 `WebXRManager` 덕에 Three.js의 WebXR은 거의 공짜다. R3F에는 `@react-three/xr`이 있다.
const store = createXRStore()
{/* ...씬... */}
WebGPU + WebXR 조합은 2026년에 의외로 무겁지 않다 — Apple Vision Pro·Quest 3·Quest 3S 모두 WebGPU 기반 WebXR을 안정적으로 돌린다. 마케팅·교육·헬스케어 쪽에서 빠르게 채택 중.
10장 · Three.js vs Babylon.js vs PlayCanvas
엔진 비교는 짧게.
| 항목 | Three.js | Babylon.js | PlayCanvas |
|------|----------|-----------|-----------|
| 라이선스 | MIT | Apache 2.0 | MIT (엔진) |
| 강점 | 거대한 생태계·예제·커뮤니티 | 게임 기능 풍부(피직스·오디오·머티리얼 에디터) | 비주얼 에디터·클라우드 IDE |
| 약점 | 게임용 기능은 직접 조립 | 생태계 작음 | 코드 우선은 약함 |
| WebGPU | r182 기본 권장 | Babylon 7+에서 안정 | 엔진 차원에서 지원 |
| 주간 다운로드(npm) | ~2.7M | ~10K | ~8K |
| 대표 영역 | 포트폴리오·제품·아트·시각화 | 브라우저 게임·시뮬레이션 | 광고·게임·구성 도구 |
**한 줄 추천:**
- **창작·아트·포트폴리오·제품 시각화** → Three.js (+ R3F).
- **게임형 인터랙션·물리 비중 큰 앱** → Babylon.js.
- **에디터로 시각적 협업이 중요** → PlayCanvas.
생태계 크기가 깡패다. **모르면 Three.js다.**
11장 · Gaussian Splatting — 폴리곤 없는 사진실적 3D
여기서부터 새로운 페이지다.
**Gaussian Splatting(이하 gsplat)** 은 폴리곤 메시가 아니다. 씬을 **수백만 개의 작은 3D 가우시안 점들**(각자 위치·색·투명도·방향성을 가진 타원체)로 표현한다. 카메라가 그 점들을 화면에 "스플랫"(투영해서 펴)으로써 이미지를 만든다.
폴리곤 메시: Gaussian Splatting:
┌── 정점·면 데이터 ┌── 수백만 개 가우시안
├── UV·텍스처 │ (위치·SH 색·스케일·회전·α)
├── 노멀·머티리얼 ├── 텍스처 없음
└── 라이트로 셰이딩 └── 캡처 당시의 라이팅이 굽혀짐
**왜 흥분되는가?**
1. **사진실적** — 30장~수백 장의 사진/영상에서 학습. 출력이 사진과 거의 같다.
2. **실시간** — GPU 친화적. 웹에서 60fps 가능.
3. **메시 모델링 0** — Blender도, UV도, 텍스처도, 노멀도 필요 없다. **카메라만 있으면 된다.**
4. **NeRF의 후계** — NeRF가 학술적 마일스톤이었다면, gsplat은 실무적 도구다(빠른 학습·실시간 렌더링).
한계도 분명하다
- 라이팅이 "구워져" 있다 — **씬을 동적으로 비추기 어렵다.**
- 충돌·물리 시뮬레이션이 어렵다 — 메시가 아니니까.
- 편집이 까다롭다 — SuperSplat 같은 전용 에디터가 필요.
- 파일이 크다 — 수십~수백 MB.
요는 — **존재하는 공간을 통째로 캡처해서 보여주는 것**에는 무적이다. 부동산·문화재·박물관·콘서트·이벤트·전시.
2026년의 도구 풍경
- **Polycam** — 모바일 캡처의 시장 선도자. iOS LiDAR + 포토그래메트리 + gsplat. 평균 평점 4.7. iOS 리뷰 54만 개. 가장 쉬운 진입.
- **Luma AI** — 클라우드 처리로 **시각 품질이 가장 좋다**고 평가되는 무료 gsplat 플랫폼. 임베드 가능.
- **SuperSplat** — PlayCanvas 엔진 위에 만든 **무료 오픈소스 브라우저 기반 gsplat 에디터**. 라이브 어노테이션·핫스팟·후처리(블룸·비네트)·카메라 애니메이션·WebXR까지. HTML 뷰어로 내보내 GitHub Pages·Netlify·Vercel에 그대로 호스팅.
- **NeRF Studio** — 연구 지향. 로컬 학습·실험에 강함.
웹에 띄우기 — `@mkkellogg/gaussian-splats-3d`
Three.js 호환의 가벼운 gsplat 뷰어. R3F 환경에서:
function Splat({ url }) {
const { scene, camera, gl } = useThree()
useEffect(() => {
const viewer = new GaussianSplats3D.Viewer({
threeScene: scene,
camera,
renderer: gl,
selfDrivenMode: false,
})
viewer.addSplatScene(url)
return () => viewer.dispose()
}, [url, scene, camera, gl])
return null
}
브라우저에서 수백만 가우시안을 60fps로 그린다. 5년 전에는 SF였다.
12장 · AI로 3D를 만든다 — Meshy · Tripo · Rodin
마지막 한 갈래. **텍스트나 사진에서 3D 메시를 뽑는 AI.** 2026년에는 더 이상 실험이 아니라 워크플로의 일부다.
세 강자.
- **Meshy 6** — 가장 균형 잡힌 제품. 텍스트→3D, 이미지→3D, **PBR 텍스처**, 토폴로지 제어, 폭넓은 익스포트. 생성 40~60초. "기본값 추천."
- **Tripo AI** — 가장 빠른 생성(20~30초). 기본값이 영리해서 초기 진입 마찰이 가장 낮다. 텍스트·이미지 둘 다.
- **Rodin AI(Gen-2)** — 100억 파라미터. **가장 높은 품질**. 캐릭터·구조화된 자산에 강함. 생성 60~180초.
워크플로 예:
1. **컨셉 단계** — Tripo에서 빠른 변형 30초.
2. **마음에 드는 안** — Meshy에서 PBR 텍스처 깔끔하게 다시.
3. **최종 캐릭터** — Rodin Gen-2로 고품질 메시.
4. **glTF로 내보내** Three.js/R3F 씬에 박는다.
Idea ─▶ Tripo (탐색)
└─▶ Meshy (정제·PBR)
└─▶ Rodin (피니시·캐릭터)
└─▶ glTF
└─▶ R3F 씬에 useGLTF
**중요한 현실:** AI 생성 메시는 토폴로지가 깔끔하지 않다. **포트폴리오·시각화·게임 백그라운드**에는 충분하지만, **리깅·애니메이션이 중요한 캐릭터**는 보통 Blender에서 리토폴로지가 필요하다.
13장 · "무엇으로 무엇을 만들까" — 유스케이스 매트릭스
| 유스케이스 | 추천 스택 | 비고 |
|----------|---------|------|
| 개발자 포트폴리오 | R3F + drei + Bloom | drei의 Float/Text 한 줌으로 충분 |
| 제품 컨피규레이터 | R3F + glTF + KTX2 | 색·텍스처 옵션은 머티리얼 교체 |
| 부동산 가상 투어 | gsplat (Luma·Polycam) + SuperSplat | 사진실적·실측 공간 |
| 박물관·전시 | gsplat + WebXR | 핫스팟·어노테이션 |
| 브라우저 게임 | Babylon.js 또는 Three.js + Rapier | 물리·충돌 필요 |
| 데이터 시각화 | R3F + 카메라 워크 | 인스턴싱 적극 활용 |
| AR 마케팅 | R3F + `@react-three/xr` + WebXR | iOS Quick Look 병행 |
| 인터랙티브 아트 | Three.js + TSL (셰이더 직접) | 노드 셰이더 자유도 |
| 캐릭터 중심 인터랙션 | R3F + AI 생성(Rodin) + Mixamo 리타게팅 | 토폴로지 정리 한 번 |
| LiDAR 캡처 자산 | Polycam → glTF or gsplat | 모바일만으로 종결 |
**룰 오브 섬:**
- "공간을 통째로 보여줘야 한다" → **gsplat**.
- "조작할 수 있어야 한다(색·옵션·물리)" → **폴리곤(glTF) + R3F**.
- "조금 만들어 빨리 띄워야 한다" → **R3F + AI 생성**.
14장 · 포트폴리오 사이트 만들기 — 30분 레시피
가장 흔한 첫 프로젝트. 골격을 한 번에 본다.
function Hero() {
const { scene } = useGLTF('/hero.glb')
return <primitive object={scene} scale={1.4} />
}
export default function Portfolio() {
return (
)
}
체크리스트:
- 모델은 Meshy/Tripo로 뽑거나, sketchfab CC0에서 받아 `gltf-transform optimize` 한 번.
- 배경은 단색 + Environment HDR 한 장(스튜디오/시티).
- Float·ContactShadows·Bloom으로 "AI 생성스러움"을 가린다.
- `dpr={[1, 2]}` 로 레티나 폭주 막기.
- 모바일에서는 Bloom을 끈다(미디어 쿼리 + 조건부 렌더).
에필로그 — 웹은 진짜로 3D가 되었다
2026년의 웹 3D는 더 이상 "한번 보고 마는 데모"의 자리가 아니다. 제품 페이지, 부동산, 박물관, 광고, 학습 도구가 일상적으로 3D를 깔고 있다. 그리고 그 일상의 도구는:
- **Three.js + R3F** — 폴리곤 기반 표준 스택.
- **WebGPU + TSL** — 셰이더 두 벌이 한 벌로.
- **Gaussian Splatting** — 카메라만 있으면 사진실적 공간.
- **AI 3D 생성** — 텍스트 한 줄로 메시.
마지막으로 두 가지를 남긴다.
14개 항목 체크리스트
1. WebGPURenderer를 기본으로 두고 WebGL 2 폴백을 확인했는가?
2. `renderer.init()` 의 비동기 처리를 빠뜨리지 않았는가?
3. glTF가 Draco·KTX2로 압축됐는가?
4. 인스턴싱이 필요한 대량 메시를 그냥 그리고 있지 않은가?
5. `pixelRatio`를 모바일에서 캡했는가?
6. 프러스텀 컬링을 끄지 않았는가?
7. 같은 머티리얼/지오메트리를 중복 생성하고 있지 않은가?
8. 포스트프로세싱 효과 수를 모바일에서 줄였는가?
9. Suspense로 로딩 UX를 잡았는가?
10. WebXR 진입은 사용자 제스처(클릭) 안에서 호출하는가?
11. gsplat 자산은 압축 포맷(SPZ·KSPLAT)으로 내보냈는가?
12. AI 생성 메시의 토폴로지를 (필요하면) 한 번 정리했는가?
13. `setAnimationLoop` 한 곳에서만 도는가(중복 루프 없음)?
14. 첫 프레임 검정이 라이트 없음/init 누락은 아닌가?
안티패턴 10가지
1. WebGPU 코드에 `await renderer.init()`을 빼고 첫 프레임이 검정.
2. 라이트 없이 `MeshStandardMaterial`을 쓰고 검정.
3. 같은 모델 인스턴스를 매 프레임 다시 로드.
4. `frustumCulled = false` 를 그냥 켜둠.
5. JPG·PNG를 압축 없이 그대로 GPU에.
6. 데스크톱·모바일 같은 `dpr` 설정.
7. 포스트프로세싱 5개를 모바일에서도 돌림.
8. AI 생성 메시를 토폴로지 정리 없이 캐릭터 리깅에 쓰기.
9. gsplat을 폴리곤 워크플로(편집·물리)로 다루려 함.
10. `useGLTF` 대신 매 컴포넌트에서 `GLTFLoader.load`를 직접 호출.
다음 글 예고
다음 글 후보: **WebGPU 컴퓨트 셰이더 실전 — GPGPU로 파티클 100만 개 돌리기**, **Gaussian Splatting 워크플로 — 캡처부터 웹 임베드까지**, **R3F + Rapier 물리 엔진 — 인터랙티브 3D 게임 한 시간 만에**.
> "웹은 진짜로 3D가 되었다. 폴리곤은 메시로, 사진은 가우시안으로, 텍스트는 AI로. 그 사이를 잇는 건 여전히 Three.js다."
— 웹의 3D 개발 2026, 끝.
참고 / References
- [Three.js 공식 사이트](https://threejs.org/)
- [Three.js WebGPURenderer 매뉴얼](https://threejs.org/manual/en/webgpurenderer.html)
- [Three.js GitHub 릴리스 노트](https://github.com/mrdoob/three.js/releases)
- [React Three Fiber 문서](https://r3f.docs.pmnd.rs/)
- [drei 헬퍼 라이브러리](https://github.com/pmndrs/drei)
- [@react-three/postprocessing](https://github.com/pmndrs/react-postprocessing)
- [@react-three/xr](https://github.com/pmndrs/xr)
- [WebGPU W3C 명세](https://www.w3.org/TR/webgpu/)
- [WGSL 명세](https://www.w3.org/TR/WGSL/)
- [TSL — Three Shading Language 가이드](https://blog.maximeheckel.com/posts/field-guide-to-tsl-and-webgpu/)
- [Babylon.js 공식](https://www.babylonjs.com/)
- [PlayCanvas 공식](https://playcanvas.com/)
- [SuperSplat — gsplat 에디터](https://superspl.at/)
- [Polycam — 모바일 3D 캡처](https://poly.cam/)
- [Luma AI](https://lumalabs.ai/)
- [NeRF Studio](https://docs.nerf.studio/)
- [Meshy AI](https://www.meshy.ai/)
- [Tripo AI](https://www.tripo3d.ai/)
- [Rodin AI (Hyper3D)](https://hyper3d.ai/)
- [gltf-transform — 최적화 CLI](https://gltf-transform.dev/)
- [Mkkellogg gaussian-splats-3d](https://github.com/mkkellogg/GaussianSplats3D)
현재 단락 (1/335)
2010년대 후반, 웹에서 3D를 한다는 건 "WebGL"을 한다는 뜻이었다. Three.js가 그 위에 사람답게 쓸 수 있는 추상을 얹었고, 우리는 GLSL 셰이더를 두 벌(We...