Files
2nd/10_Wiki/Topics/Programming & Language/InstancedMesh 사용 시 드로우 콜 최적화의 한계점 사례 연구.md
T
2026-05-10 22:08:15 +09:00

6.8 KiB
Raw Blame History

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-instancedmesh-사용-시-드로우-콜-최적화의-한계 InstancedMesh 사용 시 드로우 콜 최적화의 한계점 사례 연구 10_Wiki/Topics verified self
InstancedMesh Limits
Instancing Limits
none A 0.9 applied
graphics
three-js
performance
instancing
2026-05-10 pending
language framework
JavaScript/GLSL 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)

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

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)

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)

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+)

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)

// 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 · GPU Particle
  • 응용: Foliage Rendering · Crowd Rendering
  • 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