이 챕터에서 정복할 CG 개념
- vertex shader는 per-vertex attribute를 읽어 clip-space 좌표를 만든다.
- rasterizer는 per-fragment varying을 보간하고 fragment shader가 픽셀을 결정한다.
- POP attribute는 vertex shader의 입력 SSBO와 같은 메모리이고, GLSL MAT의 attribute 접근자는 그 SSBO를 가리키는 view다.
- node-graph 위의 MAT은 fixed pipeline 셰이더의 thin wrapper이며, GLSL MAT은 같은 자리의 셰이더 코드 그 자체다.
왜 이게 중요한가
지금까지 POP은 GPU 위의 attribute buffer를 만지는 도구였다. 그 buffer가 어디로 가느냐가 14장의 질문이다. POP attribute는 vertex shader의 in 변수, 정확히는 SSBO에서 끌어온 per-vertex 값으로 바인딩된다. fragment shader는 그 값을 varying으로 받아 픽셀 색을 결정한다. 이 흐름이 raster pipeline의 정의이며 OpenGL의 glDrawElements, Unity의 Material, Unreal의 PSO, WebGPU의 render pass에서 같은 모양으로 다시 등장한다. POP → Geometry COMP → Render TOP 경로는 그 파이프라인을 노드 그래프 위에서 직접 만지게 한다.
POP에서의 노출 지점
- Geometry COMP: POP 네트워크 컨테이너. Render Flag가 켜진 POP이 렌더 대상 (wiki: "Each Geometry Component contains a Network containing POPs ... that define its 3D shape.").
- Render TOP: Camera COMP, Geometry COMP, (선택) Light COMP를 받아 2D 이미지를 출력 (wiki: "The Render TOP is used to render all 3D scenes in TouchDesigner.").
- MAT: Geometry COMP에 할당되는 material. Constant/Phong MAT은 fixed pipeline, 셰이더 코드 없이 파라미터로 결정.
- GLSL MAT: vertex/pixel/geometry shader를 DAT 텍스트로 직접 쓰는 material.
- GLSL MAT attribute 접근자:
TDPos(),TDNormal(),TDTexCoord(uint),TDPointColor(), custom은 Attributes 페이지 선언 후TDAttrib_AttribName(). POP element-단위 접근은TDBuffer_AttribName(uint elementIndex, uint arrayIndex)(wiki: Write_a_GLSL_Material).
이론
raster pipeline의 최소 모델
POP SSBO → Vertex Shader (gl_Position) → Primitive Assembly + Clipping → Rasterizer (varying 보간) → Fragment Shader (fragColor) → Blend → Framebuffer (= Render TOP 출력).
vertex shader의 의무는 gl_Position을 clip space에서 채우는 것 하나, 그 외 out은 rasterizer가 fragment의 in으로 보간한다. fragment shader의 의무는 fragColor를 채우는 것 하나다.
TouchDesigner의 GLSL MAT은 이 최소 모델에 두 가지 편의를 얹는다. transform 매트릭스를 TDMatrix uTDMats[TD_NUM_CAMERAS] uniform으로 제공하고, TDDeform(P) · TDWorldToProj(P)가 모델→world→clip 변환을 한 줄로 끝낸다. fragment 측에서는 출력 텍스처 채널 순서를 맞추려 TDOutputSwizzle(curColor)를 거친다.
POP attribute → vertex shader input
POP의 attribute는 GPU 메모리 위의 SSBO다 (4장, 8장 참조). Geometry COMP가 그 SSBO를 vertex buffer로 인식하고 GLSL MAT의 vertex shader가 TDPos() 헬퍼로 현재 vertex의 P를 읽는다. custom attribute를 받으려면 GLSL MAT의 Attributes 페이지에 이름·타입을 등록 (예: vel, vec3)한 뒤 TDAttrib_vel()로 접근한다.
노드 ≡ 셰이더 한 줄
| 노드 | GLSL MAT |
|---|---|
| Phong MAT Diffuse | fragColor = ambient + diffuse*N·L |
| Constant MAT Color | fragColor = vec4(color, 1.0) |
| Geometry COMP Transform | TDDeform(P) |
| Camera COMP View+Projection | TDWorldToProj(world) |
fixed pipeline MAT은 GLSL MAT을 TD가 자동 생성한 결과다.
손작업 (Hands-on)
시작 파일
- Sphere POP1 (Type: Geodesic, Frequency 4)
- Normal POP1 (Type: Vertex)
- Geometry COMP1 (containing Sphere POP1 + Normal POP1, render flag on Normal POP1)
- Camera COMP1
- Light COMP1
- Render TOP1
연결: Sphere POP1 → Normal POP1 (in geo1); Camera COMP1, Light COMP1, Geometry COMP1 → Render TOP1.
단계 1 — 기본 렌더
Render TOP1의 Geometry 파라미터를 geo1로, Camera를 cam1로, Light를 light1로 지정한다. Phong MAT을 만들어 Geometry COMP의 Material 파라미터에 연결한다. 화면: 균일하게 음영이 들어간 구. 보게 될 것: POP이 만든 점·삼각형이 Geometry COMP 안에서 mesh로 해석되고, Phong MAT의 fixed pipeline 셰이더가 그 mesh를 그린다.
단계 2 — GLSL MAT로 같은 결과를 손으로
GLSL MAT1을 만들고 vertex/pixel shader DAT 두 개를 연결한다. Geometry COMP의 Material을 GLSL MAT1로 바꾼다.
vertex shader (vshader1):
// per-vertex: world space 위치 + 법선을 fragment로 보낸다
out Vertex {
vec3 worldPos;
vec3 worldNormal;
} oVert;
void main() {
vec4 worldPos = TDDeform(TDPos()); // SOP/POP → world
vec3 worldN = TDDeformNorm(TDNormal()); // 법선의 world 변환
oVert.worldPos = worldPos.xyz;
oVert.worldNormal = worldN;
gl_Position = TDWorldToProj(worldPos); // world → clip
}
pixel shader (pshader1):
// per-fragment: 단순 Lambert + ambient
in Vertex {
vec3 worldPos;
vec3 worldNormal;
} iVert;
out vec4 fragColor;
void main() {
vec3 N = normalize(iVert.worldNormal);
vec3 L = normalize(vec3(0.3, 1.0, 0.5)); // 임의 방향광
float NdotL = max(dot(N, L), 0.0);
vec3 col = vec3(0.1) + vec3(0.9, 0.7, 0.4) * NdotL;
fragColor = TDOutputSwizzle(vec4(col, 1.0));
}
이 코드가 GPU에서 하는 일: 매 vertex마다 vertex shader가 gl_Position을 채운다. rasterizer가 삼각형을 픽셀로 자르고 iVert를 보간한다. 매 픽셀마다 fragment shader가 N·L 내적으로 명도를 정한다. TDOutputSwizzle은 출력 텍스처 채널 배치를 맞춘다 (wiki: "ensures the channels are in the correct place").
보게 될 것: Phong MAT과 거의 같은 음영의 구. 음영 식이 위 6줄에 다 있다.
단계 3 — custom attribute를 vertex → fragment로 흘려보내기
Sphere POP1과 Normal POP1 사이에 GLSL POP1을 끼우거나 Random POP1을 끼워 Cd (color) point attribute를 만든다. 또는 더 명시적으로, GLSL POP1에서 vel 같은 vec3 attribute를 생성한다 (Create Attribs 페이지에서 vel: vec3 선언, Output Attributes에 vel 추가).
GLSL POP1 셰이더 본문:
// 점마다 P를 입력 삼아 의사-velocity를 만든다
void main() {
const uint id = TDIndex();
if (id >= TDNumElements()) return;
vec3 p = TDIn_P();
vel[id] = vec3(sin(p.x*3.0), cos(p.y*3.0), sin(p.z*3.0));
}
이 코드가 GPU에서 하는 일: 한 thread가 한 점을 맡아 P를 읽고 sin/cos 조합으로 vec3을 만들어 vel SSBO에 쓴다. workgroup-round-up 때문에 마지막 워크그룹이 잉여 thread를 포함할 수 있고 if (id >= TDNumElements()) 가드가 그 쓰기를 막는다.
GLSL MAT1의 Attributes 페이지에 entry 추가: Name vel, Type vec3. 그러면 vertex shader에서 TDAttrib_vel()로 읽힌다. 단계 2의 vertex shader에 vec3 vel을 Vertex 블록에 추가하고 oVert.vel = TDAttrib_vel(); 한 줄을 더한다. pixel shader는 색 계산만 교체:
// pixel shader 본문 (Vertex 블록과 fragColor선언은 단계 2와 동일)
vec3 col = 0.5 + 0.5 * iVert.vel; // -1..1 → 0..1 매핑
fragColor = TDOutputSwizzle(vec4(col, 1.0));
보게 될 것: 구 표면에 부드러운 RGB 그라데이션. 각 픽셀 색은 삼각형 세 vertex vel의 barycentric 보간이다. POP의 attribute가 vertex shader의 in이 되고 out을 거쳐 rasterizer가 fragment의 in으로 보간하는 흐름이 화면에 나타난다.
노드 ↔︎ GLSL 매핑
같은 결과 — Sphere POP을 회색 음영으로 렌더.
노드: Sphere POP → Normal POP → Geometry COMP. Material: Phong MAT (Diffuse RGB 0.6).
GLSL MAT: 단계 2의 vertex+pixel shader, Diffuse 색만 vec3(0.6). Phong MAT은 specular·ambient·rim·emit 항을 자동으로 더하므로 셰이더에서 그 항을 다 쓰면 동일해진다. Phong MAT은 GLSL MAT을 자동 작성한 결과물이다.
확인 질문 (Self-check)
- POP의 point attribute가 vertex shader의 어떤 인터페이스로 들어오는가? GLSL MAT의 어떤 페이지·함수가 그것을 노출하는가?
gl_Position은 어느 좌표계의 값인가?TDWorldToProj는 어떤 변환을 합치는가?- fragment shader의
in은 어떻게 vertex shader의out으로부터 만들어지는가? 어떤 단계가 그 사이에 있는가? - POP에서 만든 custom attribute
vel을 GLSL MAT에서 받으려면 GLSL MAT 측에서 무엇을 선언해야 하는가? TDOutputSwizzle이 없으면 어떤 시각적 증상이 나타날 가능성이 있는가? 왜 그런가?
연결 고리
- LearnOpenGL — "Hello Triangle" (https://learnopengl.com/Getting-started/Hello-Triangle): vertex attribute / VAO / EBO. POP의 Point·Vertex·Primitive와 같은 자리.
- LearnOpenGL — "Shaders" (https://learnopengl.com/Getting-started/Shaders): vertex
out→ fragmentin의 흐름. 위 단계 3의 본질. - LearnOpenGL — "Basic Lighting" (https://learnopengl.com/Lighting/Basic-Lighting): normal attribute를 fragment에서 쓰는 최소 예제. 단계 2의 Lambert 식과 같음.
- Real-Time Rendering 4ed §2 "The Graphics Rendering Pipeline" §5 "Shading Basics": 위 다이어그램의 책 측 어휘.
이 챕터의 한 줄 명제
POP attribute는 vertex shader의 SSBO 입력이고, GLSL MAT은 그 SSBO를 읽어 gl_Position과 fragColor를 채우는 손글씨 셰이더다.