d8a80f6272
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해 끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은 과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업. 도구: Datacollect/scripts/link_reconcile_apply.mjs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
184 lines
6.5 KiB
Markdown
184 lines
6.5 KiB
Markdown
---
|
|
id: wiki-2026-0508-cad-렌더링-최적화
|
|
title: CAD 렌더링 최적화
|
|
category: 10_Wiki/Topics
|
|
status: verified
|
|
canonical_id: self
|
|
aliases: [CAD Rendering Optimization, CAD Performance, Engineering Visualization]
|
|
duplicate_of: none
|
|
source_trust_level: A
|
|
confidence_score: 0.9
|
|
verification_status: applied
|
|
tags: [cad, rendering, gpu, lod, webgpu]
|
|
raw_sources: []
|
|
last_reinforced: 2026-05-10
|
|
github_commit: pending
|
|
tech_stack:
|
|
language: TypeScript
|
|
framework: WebGPU/Three.js
|
|
---
|
|
|
|
# CAD 렌더링 최적화
|
|
|
|
## 매 한 줄
|
|
> **"매 millions-of-triangles model 의 60fps 표시 = LOD + culling + GPU instancing 의 합."**. 매 CAD assembly 는 mechanical part 가 hundreds-of-thousands 단위로 쌓여 brute-force rendering 시 GPU 가 즉사. 매 2026 모던 stack 은 WebGPU + meshlet (Nanite-style) + indirect draw 를 사용해 browser 에서도 native-like performance 달성.
|
|
|
|
## 매 핵심
|
|
|
|
### 매 bottleneck axis
|
|
- **Geometry**: 매 triangle count — 매 fillet/thread 같은 detail 이 수십 million 까지 폭증.
|
|
- **Draw call**: 매 part 별 separate draw → CPU/GPU sync overhead 가 frame budget 잠식.
|
|
- **Overdraw**: 매 transparent assembly 의 layered fragment shading.
|
|
- **Memory**: 매 32-bit index + per-vertex normal/UV/color → VRAM 빠르게 saturate.
|
|
|
|
### 매 technique stack
|
|
- **Tessellation control**: 매 NURBS → mesh 변환 시 view-dependent chord tolerance.
|
|
- **LOD**: 매 distance / screen-coverage 기반 mesh swap.
|
|
- **Frustum / occlusion culling**: 매 BVH + Hi-Z buffer.
|
|
- **Instancing**: 매 동일 part (bolt/screw) 의 single draw call.
|
|
- **Meshlet (Nanite-like)**: 매 cluster 단위 GPU culling + virtual geometry.
|
|
- **Deferred shading**: 매 overdraw 비용 절감.
|
|
|
|
### 매 응용
|
|
1. **Onshape / Fusion 360 web**: 매 browser 안 assembly editing.
|
|
2. **Plant 3D walkthrough**: 매 oil refinery / factory digital twin.
|
|
3. **AR overlay**: 매 Vision Pro / Quest 3 의 maintenance instruction.
|
|
4. **VR design review**: 매 stakeholder 의 immersive walkthrough.
|
|
|
|
## 💻 패턴
|
|
|
|
### Screen-space LOD selection
|
|
```typescript
|
|
function pickLOD(part: CadPart, camera: Camera): number {
|
|
const screenCoverage = projectedRadius(part.bounds, camera) / camera.viewport.height;
|
|
if (screenCoverage > 0.3) return 0; // full mesh
|
|
if (screenCoverage > 0.1) return 1; // 1/4 triangles
|
|
if (screenCoverage > 0.03) return 2; // 1/16 triangles
|
|
if (screenCoverage > 0.005) return 3; // billboard
|
|
return -1; // cull entirely
|
|
}
|
|
```
|
|
|
|
### GPU instancing for fasteners
|
|
```typescript
|
|
const boltMesh = loadMesh('m6_socket_head.glb');
|
|
const transforms = new Float32Array(boltCount * 16); // packed mat4
|
|
fillTransforms(transforms, boltInstances);
|
|
|
|
device.queue.writeBuffer(instanceBuffer, 0, transforms);
|
|
pass.setPipeline(instancedPipeline);
|
|
pass.setVertexBuffer(0, boltMesh.vertices);
|
|
pass.setVertexBuffer(1, instanceBuffer);
|
|
pass.drawIndexed(boltMesh.indexCount, boltCount); // single call for 50k bolts
|
|
```
|
|
|
|
### BVH-based frustum culling
|
|
```typescript
|
|
class BVHNode {
|
|
bounds: AABB;
|
|
children?: [BVHNode, BVHNode];
|
|
parts?: CadPart[];
|
|
}
|
|
|
|
function cullVisible(node: BVHNode, frustum: Frustum, out: CadPart[]) {
|
|
const test = frustum.testAABB(node.bounds);
|
|
if (test === 'outside') return;
|
|
if (test === 'inside' || !node.children) {
|
|
out.push(...(node.parts ?? collectAll(node)));
|
|
return;
|
|
}
|
|
cullVisible(node.children[0], frustum, out);
|
|
cullVisible(node.children[1], frustum, out);
|
|
}
|
|
```
|
|
|
|
### Meshlet cluster (Nanite-style)
|
|
```wgsl
|
|
// WebGPU compute shader — cluster culling
|
|
@group(0) @binding(0) var<storage, read> meshlets: array<Meshlet>;
|
|
@group(0) @binding(1) var<storage, read_write> visibleList: array<u32>;
|
|
@group(0) @binding(2) var<uniform> camera: Camera;
|
|
|
|
@compute @workgroup_size(64)
|
|
fn cullMeshlets(@builtin(global_invocation_id) gid: vec3u) {
|
|
let idx = gid.x;
|
|
if (idx >= arrayLength(&meshlets)) { return; }
|
|
let m = meshlets[idx];
|
|
if (frustumTest(m.boundingSphere, camera) &&
|
|
coneTest(m.normalCone, camera.position)) {
|
|
let slot = atomicAdd(&visibleList[0], 1u);
|
|
visibleList[slot + 1u] = idx;
|
|
}
|
|
}
|
|
```
|
|
|
|
### Indirect draw aggregation
|
|
```typescript
|
|
// One draw call dispatches all visible meshlets
|
|
const drawArgs = new Uint32Array([
|
|
indexCount, instanceCount, firstIndex, baseVertex, firstInstance
|
|
]);
|
|
device.queue.writeBuffer(indirectBuffer, 0, drawArgs);
|
|
pass.drawIndexedIndirect(indirectBuffer, 0);
|
|
```
|
|
|
|
### Progressive streaming
|
|
```typescript
|
|
async function streamAssembly(modelId: string) {
|
|
const manifest = await fetch(`/cad/${modelId}/manifest.json`).then(r => r.json());
|
|
// load coarse first → user sees something instantly
|
|
for (const lod of [3, 2, 1, 0]) {
|
|
await Promise.all(manifest.parts.map(p =>
|
|
cache.has(`${p.id}_lod${lod}`) ? null : loadPart(p, lod)
|
|
));
|
|
requestRedraw();
|
|
}
|
|
}
|
|
```
|
|
|
|
### Hi-Z occlusion
|
|
```typescript
|
|
// Down-sampled depth pyramid → occluder test before draw
|
|
const hiZ = buildHiZPyramid(depthTexture);
|
|
for (const part of visibleAfterFrustum) {
|
|
if (occludedByHiZ(part.bounds, hiZ, camera)) continue;
|
|
drawList.push(part);
|
|
}
|
|
```
|
|
|
|
## 매 결정 기준
|
|
| 상황 | Approach |
|
|
|---|---|
|
|
| < 100k triangles, single part | brute force, no LOD |
|
|
| 1M-10M triangles, assembly | BVH + frustum culling + LOD |
|
|
| 10M-100M triangles | + GPU instancing + meshlets |
|
|
| > 100M (plant/ship) | virtual geometry + streaming + occlusion |
|
|
| Mobile / VR | aggressive LOD + foveated rendering |
|
|
|
|
**기본값**: BVH culling + 4-tier LOD + instanced fasteners (covers 90% mid-size assemblies).
|
|
|
|
## 🔗 Graph
|
|
- 부모: [[Computer_Graphics]] · [[GPU Architecture]]
|
|
- 응용: [[Digital_Twin]]
|
|
- Adjacent: [[WebGPU]] · [[Three.js]] · [[Level_of_Detail]]
|
|
|
|
## 🤖 LLM 활용
|
|
**언제**: CAD/BIM viewer 설계, performance bottleneck 분석, LOD threshold tuning.
|
|
**언제 X**: photorealistic offline rendering (path tracing 영역).
|
|
|
|
## ❌ 안티패턴
|
|
- **Per-part separate draw call**: 매 50k draws/frame 은 어떤 GPU 도 죽음.
|
|
- **CPU-side culling only**: 매 GPU-driven culling 없이는 modern bandwidth 활용 불가.
|
|
- **Uniform LOD across assembly**: 매 close-up bolt 는 detail 필요, far wall 은 billboard 충분.
|
|
- **No tessellation budget**: 매 NURBS → mesh 변환 시 chord tolerance 가 화면 무관하면 메모리 폭발.
|
|
|
|
## 🧪 검증 / 중복
|
|
- Verified (Onshape engineering blog 2025, Unreal Nanite SIGGRAPH 2021, WebGPU spec 2024).
|
|
- 신뢰도 A.
|
|
|
|
## 🕓 Changelog
|
|
| 날짜 | 변경 |
|
|
|---|---|
|
|
| 2026-05-08 | Phase 1 |
|
|
| 2026-05-10 | Manual cleanup — CAD rendering pipeline, LOD, meshlet, WebGPU patterns |
|