--- id: wiki-2026-0508-geometry-merging title: Geometry Merging category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Mesh Merging, Static Batching, Geometry Batching] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [graphics, optimization, rendering, gpu] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: C++/HLSL framework: Unity/Unreal/Three.js --- # Geometry Merging ## 매 한 줄 > **"매 여러 mesh 를 매 단일 vertex/index buffer 로 합쳐 매 draw call 수를 매 줄이는 기법"**. CPU-GPU command overhead 의 매 frame budget 의 매 dominant share 였던 시대의 매 staple optimization. 매 modern era — GPU instancing, indirect draw, mesh shader 가 매 알 수 있게 대체했지만 매 static scene, mobile, low-end 에서 매 still relevant. ## 매 핵심 ### 매 종류 - **Static batching**: build-time 에 같은 material 의 static mesh 합침. - **Dynamic batching**: runtime 에 small mesh 를 transform & merge (CPU cost ↑). - **GPU instancing**: 같은 mesh 여러 transform — merging 의 modern 대체. - **Mesh atlas (texture array)**: material 통합으로 merge 가능 범위 확장. ### 매 trade-off - ↑ Throughput (fewer draw call). - ↓ Culling 정확도 (merged AABB 가 매 커짐). - ↑ Memory (per-vertex data 의 매 duplication). - ↓ Animation flexibility (static 한정). ### 매 응용 1. Mobile 게임 — draw call 의 매 hard limit (~100-200). 2. Architectural visualization — 매 thousands of small props. 3. Tile-based world streaming. 4. UI batching (text glyph atlas). ## 💻 패턴 ### Manual merge (Three.js) ```javascript import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js'; const geos = props.map(p => p.geometry.clone().applyMatrix4(p.matrixWorld)); const merged = mergeGeometries(geos, false); const mesh = new THREE.Mesh(merged, sharedMaterial); scene.add(mesh); // 1000 draw calls → 1 ``` ### Unity static batching ```csharp // Mark objects as static in Inspector → Unity merges at build time. // Or runtime: StaticBatchingUtility.Combine(rootGameObject); // Caveat: combined mesh 64k vertex 한도 (16-bit index). ``` ### GPU instancing (preferred over merge) ```glsl // vertex shader (Unity URP) struct Attributes { float3 positionOS : POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID }; UNITY_INSTANCING_BUFFER_START(Props) UNITY_DEFINE_INSTANCED_PROP(float4, _Color) UNITY_INSTANCING_BUFFER_END(Props) Varyings vert(Attributes IN) { UNITY_SETUP_INSTANCE_ID(IN); // ... } ``` ### Texture atlas (enable merging across materials) ```python # Bake separate textures into one atlas → assign UV remap. import numpy as np atlas = np.zeros((2048, 2048, 4), np.uint8) uv_remap = {} for i, tex in enumerate(textures): x, y = (i % 8) * 256, (i // 8) * 256 atlas[y:y+256, x:x+256] = tex uv_remap[i] = (x/2048, y/2048, 256/2048, 256/2048) # Then rewrite mesh UVs per material id. ``` ### Multi-draw indirect (modern alt) ```cpp // Instead of merging, keep mesh separate but submit via single indirect call. struct DrawCmd { uint32_t indexCount, instanceCount, firstIndex, vertexOffset, firstInstance; }; std::vector cmds; // one per visible mesh glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, cmds.data(), cmds.size(), 0); ``` ### Hierarchical merge (octree) ```python def merge_octree(node): if node.is_leaf and len(node.meshes) > 1: node.merged = merge(node.meshes) else: for c in node.children: merge_octree(c) # Coarse cull on octree node, fine draw merged buffer. ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | 同 mesh 다수 | GPU instancing (best) | | Static, 多 unique mesh | Static merging + atlas | | Modern API (Vk/D3D12) | Indirect draw + bindless | | Mobile / WebGL legacy | Static batching + atlas | | Animated / dynamic transform | Per-object draw + culling | **기본값**: Modern HW → instancing/indirect. Legacy → static merge + atlas. ## 🔗 Graph - 부모: [[Rendering Optimization]] · [[Draw Call]] - 변형: [[GPU Instancing]] · [[Indirect Draw]] - 응용: [[Texture Atlas]] · [[Octree]] · [[BVH]] - Adjacent: [[Frustum Culling]] · [[LOD]] ## 🤖 LLM 활용 **언제**: Mobile / web renderer 최적화, asset pipeline 설계. **언제 X**: Highly dynamic scenes (animation/destruction). ## ❌ 안티패턴 - **Merge everything**: 매 culling 효과 무력화. - **Material 다른 mesh merge**: shader switch 강제 → benefit 없음. - **Skinned mesh static merge**: 매 animation broken. - **64k vertex 한계 모름**: 16-bit index 의 매 silent overflow. - **Modern API 에서 merge 만 사용**: indirect/instancing 무시. ## 🧪 검증 / 중복 - Verified (Unity docs, Three.js BufferGeometryUtils, GPU Pro series). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — merging vs instancing/indirect 의 trade-off |