Quick Reference
Vertex는 position·normal·UV 같은 attribute 묶음이고, mesh는 vertex와 index로 구성된 geometry이며, primitive topology가 이를 point·line·triangle로 조립합니다. 같은 position이라도 UV seam·normal·tangent·skinning weight가 다르면 별도 vertex가 필요하므로 DCC의 위치 수와 GPU vertex 수는 다를 수 있습니다.
| 입력 | shader가 받는 것 | 설계할 때 확인할 값 |
|---|---|---|
| Vertex buffer | position, normal, UV, color, tangent 등 attribute | format, byte offset, stride, input location |
| Index buffer | vertex를 참조하는 16/32-bit index | index type, topology, bounds |
| Primitive topology | point, line, triangle list/strip 등 조립 규칙 | winding, restart, cull mode |
| Mesh section | 같은 material/range로 그릴 geometry 범위 | draw count, base vertex, material 분할 |
Buffer와 layout
GPU는 보통 정점 버퍼에서 position, normal, UV 같은 attribute를 읽고, index buffer를 통해 삼각형을 조립합니다. 삼각형이 기본 단위인 이유는 항상 평면을 이루고, 보간과 래스터라이제이션 규칙을 안정적으로 적용하기 쉽기 때문입니다. input layout은 CPU struct의 모양을 자동으로 알아내지 못합니다. shader location마다 어느 buffer의 어느 byte offset을 어떤 format으로 읽는지 명시해야 합니다.
vertex buffer:
position, normal, uv
index buffer:
0, 1, 2
2, 3, 0정점 하나는 화면의 픽셀 하나가 아닙니다. 정점은 삼각형의 꼭짓점이고, rasterization 단계에서 삼각형 내부의 fragment 후보가 만들어집니다. interleaved buffer는 한 vertex의 모든 attribute를 붙여 cache-friendly하게 읽기 쉽고, separate stream은 position만 쓰는 depth pass처럼 일부 attribute만 갱신하거나 바인딩할 때 유리할 수 있습니다. 어느 쪽이 항상 빠른 규칙은 아니므로 실제 vertex fetch와 upload 패턴을 봅니다.
보간과 topology
삼각형 내부 fragment의 UV, normal, color는 정점 attribute를 보간해서 얻습니다. 그래서 vertex shader가 넘긴 값은 fragment shader에서 픽셀마다 다른 값으로 들어올 수 있습니다. normal과 tangent는 보간 뒤 길이가 달라질 수 있으므로 fragment shader에서 normalize하고, normal map에는 tangent handedness까지 사용합니다.
triangle winding은 front face와 back face 판정에 쓰입니다. mesh export에서 좌표계나 index 순서가 바뀌면 cull mode와 맞지 않아 표면이 사라질 수 있습니다. triangle strip은 index를 아낄 수 있지만 restart와 winding parity를 관리해야 하며, 현대 renderer에서는 batching/meshlet 구조와 함께 이점이 있는지 판단합니다.
Attribute와 format
| 목적 | 필요한 attribute |
|---|---|
| 위치만 표시 | position |
| 기본 조명 | position, normal |
| 텍스처 매핑 | position, UV |
| normal map | normal, tangent, UV |
| vertex color | color |
| 스키닝 | bone index, weight, instance 또는 palette offset |
attribute가 많아질수록 vertex bandwidth가 늘어납니다. 필요 없는 attribute를 계속 실어 보내면 vertex processing과 메모리 대역폭 비용이 증가합니다. UV를 16-bit normalized로 저장할지, color를 8-bit normalized로 저장할지, index를 16-bit로 유지할 수 있는지 같은 format 선택은 메모리와 precision을 함께 바꿉니다. 형식을 줄이기 전에는 transform 범위, quantization 오차, shader decode를 확인합니다.
| 변경 | 얻는 것 | 확인할 위험 |
|---|---|---|
| 16-bit index | index bandwidth와 memory 감소 | vertex 수가 표현 범위를 넘지 않는지 |
| packed normal/tangent | vertex fetch 감소 | decode와 normalizing, handedness 보존 |
| static/dynamic buffer 분리 | 자주 바뀌는 data만 upload | frame in-flight 중 buffer overwrite |
| instance buffer 사용 | 같은 mesh의 draw 수 감소 | per-instance stride, divisor, culling granularity |
자주 깨지는 입력 계약
index buffer가 항상 빠른 것은 아닙니다. 정점 재사용이 거의 없거나 data가 매우 단순한 경우에는 index read와 vertex cache 효율을 함께 봐야 합니다. 또한 culling은 mesh section 또는 instance bounds 단위로 일어나므로, 한 mesh에 너무 넓은 영역을 묶으면 보이지 않는 triangle까지 계속 보내게 됩니다.
| 증상 | 먼저 확인할 값 |
|---|---|
| mesh가 폭발하거나 줄처럼 보임 | attribute format, stride, offset, shader location |
| 일부 면이 사라짐 | index count, topology, winding, cull mode |
| normal map 조명이 seam에서 꺾임 | UV split, tangent/handedness, normal normalization |
| animation이 frame마다 깨짐 | bone index/weight format, palette offset, dynamic buffer lifetime |
| index가 큰 mesh에서 반복되거나 잘림 | 16/32-bit index type과 base vertex |
참고 링크
1 sources