docs(10_Wiki): Topic_Business/General/Graphic/Programming을 Topics/ 하위로 이동

최상위 10_Wiki/Topic_*였던 4개 카테고리 폴더를 10_Wiki/Topics/Topic_* 로 재배치.
콘텐츠 변경 없음(순수 폴더 이동) — Topics/ 하위 나머지 폴더는 이미 지난 커밋에서
전부 정리된 상태(잔존 항목은 에이전트 운영 상태 및 사용자가 보존을 요청한
업데이트0615/무제 3.canvas 뿐).
This commit is contained in:
Antigravity Agent
2026-07-05 00:44:01 +09:00
parent e9cbf23ab5
commit 9a135bd19d
6127 changed files with 0 additions and 0 deletions
@@ -0,0 +1,171 @@
---
id: wiki-2026-0508-instancedmesh-사용-시-드로우-콜-최적화의-한계
title: InstancedMesh 사용 시 드로우 콜 최적화의 한계점 사례 연구
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [InstancedMesh Limits, Instancing Limits]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [graphics, three-js, performance, instancing]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: JavaScript/GLSL
framework: Three.js r170+/WebGL2/WebGPU
---
# InstancedMesh 사용 시 드로우 콜 최적화의 한계점 사례 연구
## 매 한 줄
> **"매 InstancedMesh 매 1 draw call로 N copies — but 매 frustum culling, material variation, animation, picking 의 cost가 instance 수에 따라 explode."**. 매 naive 사용 시 draw call 매 줄어들어도 GPU vertex/fragment 매 burden, CPU matrix update 매 bottleneck. 매 production 매 LOD + spatial partition + GPU culling 매 결합.
## 매 핵심
### 매 한계 list
- **No per-instance frustum culling**: 매 single bounding sphere → 매 모든 instance가 frustum 안에 있다고 GPU가 가정.
- **No per-instance material**: 매 same material → color/texture variation 매 instanceColor / instance attribute 의 manual.
- **Animation cost**: 매 instance마다 matrix update → CPU bound at 10k+.
- **Picking 어려움**: raycaster 매 instance index 매 별도 처리.
- **Memory**: 16 floats × N instances = 매 1M instances → 64MB matrix buffer.
- **Shadow map**: 매 light 마다 또 한 번 instanced draw — culling 없으면 shadow waste.
### 매 case: 100k cubes
- Naive InstancedMesh: 매 1 draw call, GPU 60fps but matrix update 60ms/frame on CPU.
- Static (`setMatrixAt` once): 매 GPU bound, fillrate 매 issue → LOD 필요.
- Dynamic: 매 매 frame matrix update → useDynamicDrawUsage + partial updates.
### 매 응용 (해결 전략)
1. **GPU instancing + GPU culling**: compute shader 매 frustum check, 매 indirect draw.
2. **Spatial partitioning**: octree / BVH로 매 chunk 단위 InstancedMesh.
3. **LOD groups**: distance 별 다른 InstancedMesh (high/med/low/billboard).
4. **BatchedMesh (Three.js r170+)**: 매 different geometries를 single draw call.
5. **Hierarchical LOD + impostor**: 매 far away는 single quad billboard.
## 💻 패턴
### Frustum culling 수동 (Three.js)
```javascript
const frustum = new THREE.Frustum();
const m = new THREE.Matrix4();
m.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
frustum.setFromProjectionMatrix(m);
const dummy = new THREE.Object3D();
const sphere = new THREE.Sphere(new THREE.Vector3(), boundingRadius);
let visibleCount = 0;
for (let i = 0; i < totalInstances; i++) {
sphere.center.copy(positions[i]);
if (frustum.intersectsSphere(sphere)) {
dummy.position.copy(positions[i]);
dummy.updateMatrix();
instancedMesh.setMatrixAt(visibleCount++, dummy.matrix);
}
}
instancedMesh.count = visibleCount;
instancedMesh.instanceMatrix.needsUpdate = true;
```
### Per-instance color
```javascript
const mesh = new THREE.InstancedMesh(geo, mat, N);
const color = new THREE.Color();
for (let i = 0; i < N; i++) {
color.setHSL(i / N, 0.7, 0.5);
mesh.setColorAt(i, color);
}
mesh.instanceColor.needsUpdate = true;
// shader auto: gl_InstanceID → vInstanceColor
```
### Dynamic draw usage (partial updates)
```javascript
mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
// only update changed instances
mesh.setMatrixAt(idx, newMatrix);
mesh.instanceMatrix.updateRange = { offset: idx * 16, count: 16 };
mesh.instanceMatrix.needsUpdate = true;
```
### Chunked InstancedMesh (spatial bucket)
```javascript
class ChunkedInstances {
constructor(geo, mat, chunkSize = 64) {
this.chunks = new Map(); // "x,y,z" → InstancedMesh
this.chunkSize = chunkSize;
}
add(pos) {
const key = this.chunkKey(pos);
if (!this.chunks.has(key)) {
this.chunks.set(key, new THREE.InstancedMesh(geo, mat, 1024));
}
// ...
}
cullChunks(frustum) {
for (const [key, mesh] of this.chunks) {
mesh.visible = frustum.intersectsBox(this.chunkBox(key));
}
}
}
```
### BatchedMesh (Three.js r170+)
```javascript
const batched = new THREE.BatchedMesh(maxGeoms, maxVerts, maxIdx);
const geoIdA = batched.addGeometry(geoA);
const geoIdB = batched.addGeometry(geoB);
const instA = batched.addInstance(geoIdA);
batched.setMatrixAt(instA, matrixA);
// 매 different geometries 매 single draw call
```
### GPU compute culling (WebGPU)
```javascript
// compute shader: input matrices + frustum planes → atomic counter + visible matrix buffer
const cullPipeline = device.createComputePipeline({...});
pass.setPipeline(cullPipeline);
pass.dispatchWorkgroups(Math.ceil(N / 64));
// then drawIndexedIndirect from visible buffer
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| < 1k static instances | Plain InstancedMesh |
| 1k100k mostly static | InstancedMesh + manual frustum culling |
| 100k+ static | Chunked InstancedMesh (spatial) + LOD |
| Dynamic per-frame (particles) | Points / GPU particle system |
| Different geometries | BatchedMesh (r170+) |
| Massive (1M+) | WebGPU compute culling + indirect draw |
| Picking 필요 | InstancedMesh + raycaster.firstHitOnly = true |
**기본값**: < 10k는 plain InstancedMesh, 그 이상 매 chunked + LOD.
## 🔗 Graph
- 부모: [[GPU Instancing]] · [[Three.js]]
- 변형: [[BatchedMesh]]
- Adjacent: [[Frustum Culling]] · [[LOD]] · [[Indirect Draw]] · [[WebGPU]]
## 🤖 LLM 활용
**언제**: 매 같은 geometry+material의 N copies, 매 N > 50, 매 draw call 매 hot path bottleneck.
**언제 X**: 매 highly varying geometry (use BatchedMesh), 매 < 50 copies (overhead > benefit), 매 fully dynamic mesh (skinning per instance은 expensive).
## ❌ 안티패턴
- **No bounding 갱신**: 매 instance 매 spread out 매 single boundingSphere가 too large → frustum culling 작동 안 함.
- **매 frame full matrix rebuild**: 매 instance 매 100% update assumption 매 wrong → updateRange 활용.
- **Different materials → multiple InstancedMesh**: 매 점 defeats the purpose. Use texture atlas + instance attribute.
- **Skip LOD**: 매 far instance 매 close instance와 same vertex count → fillrate explosion.
- **InstancedMesh on top of skinned mesh**: 매 shader 매 manual instancing 필요 — Three.js native skinning 매 instance와 conflict.
## 🧪 검증 / 중복
- Verified (Three.js docs r170+, mrdoob InstancedMesh PR, WebGPU spec).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — InstancedMesh 한계 / 해결 패턴 / BatchedMesh + WebGPU compute culling |