§

Appendix A Reference Build 2025.31550

용어 대조표

“TouchDesigner POP · OpenGL / Vulkan · Unity · Houdini · WebGPU 5-환경 33행 매핑.”

기준 build: TouchDesigner 2025.31550 목적: TouchDesigner POP에서 익힌 개념이 OpenGL/Vulkan, Unity, Houdini, WebGPU/WGSL에서 어떤 이름으로 다시 등장하는지의 1:1 사전. 읽는 법: 각 행은 한 CG 개념. 셀이 비어 있으면 (없음) 으로 표시하고 그 이유를 한 줄로 적었다. 본문(17장)과 일부 중복되지만 본 부록은 reference table 전용판이다.

본 부록은 핸드북 본문 18 챕터의 보조 자료이며, 학습자가 한 환경에서 다른 환경으로 옮길 때 가장 먼저 펼쳐 보는 페이지로 설계되었다. 본문 17장 "다른 환경으로 가져가기"가 같은 매핑을 산문 형태로 다룬다면, 본 부록은 reference table 형태로 압축한 판이다. 한 환경에서 익숙한 단어를 다른 환경의 동의어로 즉시 치환하는 것이 본 부록의 단일 목적이다.

본 부록은 세 부분으로 구성한다.

  1. 33개 핵심 개념의 5-환경 매핑 표. attribute·buffer·dispatch·workgroup·instancing 등 GPU 그래픽스 파이프라인의 추상화 33개를 다섯 환경의 이름으로 동시에 적는다.
  2. Terminology Collisions. 같은 단어가 환경마다 다른 것을 가리키는 경우. POP, vertex, attribute, buffer, particle system 등이 대표 사례다.
  3. TouchDesigner GLSL POP / GLSL Advanced POP / GLSL MAT 헬퍼 함수 cheat-sheet. TDIndex(), TDNumElements(), TDIn_AttribName(), oTDPoint_AttribName[] 등 TD 고유 함수의 verbatim 시그니처 목록.

본문에서 환경 약칭을 다음과 같이 쓴다.

본 부록의 사용법은 다음과 같다. 첫째, 매핑 표 (§1)를 한 번 통독해 환경별 어휘의 전체 형상을 파악한다. 둘째, Terminology Collisions (§2)를 통해 자주 발생하는 검색 함정을 피한다. 셋째, GLSL POP 셰이더를 직접 작성할 때 §3 cheat-sheet를 옆에 두고 함수 시그니처를 verbatim으로 복사해 사용한다. 모든 GLSL 코드 블록은 본 cheat-sheet의 함수만으로 구성되어 TouchDesigner에 그대로 붙여넣어 실행 가능하다.


1. 5-환경 핵심 개념 매핑

# 개념 TD POP OpenGL / Vulkan Unity (Compute / DOTS / HLSL) Houdini (VEX / SOP) WebGPU / WGSL
1 Point attribute Point class attribute (e.g. P, N, Cd). Attribute POP의 Point. GLSL POP attrclass = point. Per-vertex in 입력 (OpenGL의 "vertex"가 POP의 "point"에 해당). VBO + glVertexAttribPointer. ComputeBuffer<T> 한 요소. DOTS에서는 IComponentData 한 필드. HLSL StructuredBuffer<T>. point attribute. VEX @P, @N. attribpromote SOP의 point class. array<T> in var<storage> buffer. @builtin(vertex_index) 로 인덱스.
2 Vertex attribute (per-corner) Vertex class attribute. Normal POP Type=Vertex가 만드는 per-corner normal이 대표. GLSL POP attrclass = vertex. Per-vertex 입력의 corner-별 사본. 별도 buffer는 드물고 EBO + 동일 VBO를 공유하는 게 일반적. 명시적 표준 없음. Mesh.SetVertexBufferData로 per-corner 채널을 흉내. vertex attribute. VEX i@vtxnum, vertex() 함수. per-corner attribute는 보통 별도 storage buffer로 packed. @location(n)은 vertex stage in만 정의.
3 Primitive attribute Primitive class attribute. Attribute POP Class=Primitive. GLSL POP attrclass = primitive. 공식 표준 없음. flat qualifier로 첫 provoking vertex 값을 per-prim처럼 쓰거나 SSBO를 primitive id로 인덱스. 별도 ComputeBuffer 또는 MaterialPropertyBlock 활용 (per-instance). primitive attribute (prim class). VEX prim(), primintrinsic(). Storage buffer를 primitive id로 인덱스. WGSL에는 per-prim 표준 입력 없음.
4 Detail / global attribute (없음) — TD POP wiki에는 detail/global class 개념이 명시되지 않는다. Houdini의 detail attribute를 흉내내려면 1-element Point POP 또는 Temp Buffer를 uniform처럼 사용. UBO (uniform) 또는 push constant. C# 스크립트의 변수 / cs.SetFloat(...). detail attribute (Houdini 고유). VEX f@_detailattr (단일 element). uniform buffer (var<uniform>).
5 Custom per-element attribute (user-defined) Attribute POP New Attribute 블록 / GLSL POP Create Attribs 페이지에서 이름·타입·기본값 선언. layout(location=N) in T name (vertex stage) 또는 SSBO struct field. ComputeBuffer.SetData<T>(...), HLSL RWStructuredBuffer<T>. VEX type prefix 자동 선언: f@speed, v@vel, i@id, p@orient. @group(0) @binding(N) var<storage, read_write> name: array<T>.
6 Buffer (vertex / index / SSBO 일반) 내부적으로는 모든 attribute가 SSBO. 사용자에게는 attribute로 추상화. Wiki verbatim: "Each attribute is a Shader Storage Buffer Object (SSBO)." VBO (vertex), EBO/IBO (index), SSBO (storage), UBO (uniform). Vulkan은 모두 VkBuffer 단일 타입. ComputeBuffer, GraphicsBuffer. Mesh 내부에 vertex/index buffer. (직접 노출되지 않음) attribute → 내부 buffer. OpenCL Wrangle에서는 __global buffer 직접 다룸. GPUBuffer (단일 타입), usage flag로 vertex/index/storage/uniform 구분.
7 Read-write storage buffer GLSL POP Output Access = readwrite (atomic 연산에 필수). 출력 어트리뷰트가 read-write SSBO가 됨. layout(std430, binding=N) buffer (qualifier 없음 = read-write); readonly / writeonly 한정자. HLSL RWStructuredBuffer<T>. OpenCL Wrangle: __global float*. VEX 자체는 attribute write 추상화. var<storage, read_write> name: array<T> + GPUBufferBindingType.storage.
8 Uniform / constant GLSL POP의 Colors / Vectors / Matrices 페이지에서 선언한 uniform. Constants 페이지의 entry는 specialization constant. uniform T name; (UBO std140) 또는 push constant (Vulkan). HLSL cbuffer 또는 cs.SetFloat/SetVector/.... VEX 자체 chf(), chv()로 채널 참조 (CHOP 유사). var<uniform> name: T; (@binding으로 UBO 슬롯 지정).
9 Texture sampler (2D) GLSL POP Samplers 페이지: sampler0name + 소스 TOP + Extend U/V/W + Filter. 셰이더 측은 uniform sampler2D 자동 선언. uniform sampler2D tex; texture(tex, uv). Vulkan: VkSampler + VkImageView 분리. HLSL Texture2D tex; SamplerState s; tex.Sample(s, uv). VEX texture("op:/path", u, v). var t: texture_2d<f32>; var s: sampler; textureSample(t, s, uv).
10 Texture buffer (samplerBuffer) GLSL POP Arrays 페이지에서 array0arraytype = texturebuffer 선택. CHOP 한 채널이 packed 1D texture로 노출. GLSL samplerBuffer / uniform samplerBuffer name; texelFetch(name, i). Vulkan: VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER. HLSL Buffer<T> (typed buffer view). (직접 없음) — VEX의 1D 채널 참조는 CHOP API로 우회. WGSL texture_storage_1d 또는 typed array<T> storage buffer로 대체.
11 Compute shader program GLSL POP / GLSL Advanced POP의 compute DAT (computedat). GLSL #version 460 \n layout(local_size_x=...) in; + glCreateProgram. .compute 파일 + #pragma kernel CSMain (HLSL). (없음) — VEX는 CPU/SIMD 컴파일러. GPU 컴퓨트는 OpenCL Wrangle SOP만 제한적으로 제공. WGSL @compute entry function + device.createComputePipeline.
12 Compute dispatch (launch) GLSL POP의 Dispatch Size 파라미터 + Number of Threads 모드. 자동으로 launch. glDispatchCompute(x,y,z) / vkCmdDispatch. ComputeShader.Dispatch(kernel, x, y, z). (없음) — VEX는 element loop가 자동. OpenCL Wrangle은 1D auto-dispatch. passEncoder.dispatchWorkgroups(x, y, z).
13 Workgroup GLSL POP의 1 workgroup = 1 thread group. Default 크기는 NVIDIA 32, AMD 64 (wiki verbatim). layout(local_size_x=...) in; 가 정의하는 thread group. Vulkan에서도 동일. HLSL [numthreads(x,y,z)]. SV: SV_GroupID. (없음) — OpenCL Wrangle만 work-group 개념 노출. WGSL @workgroup_size(x,y,z).
14 Workgroup size GLSL POP Work Group Size (x,y,z) 파라미터. Manual 모드에서만 사용자 지정. layout(local_size_x=X, local_size_y=Y, local_size_z=Z). [numthreads(X,Y,Z)]. (없음) @workgroup_size(X, Y, Z).
15 Local invocation index wiki 미확정 — TD wiki는 gl_LocalInvocationID / gl_LocalInvocationIndex 노출 여부를 명시하지 않는다. TDIndex()만 표준 인터페이스. gl_LocalInvocationID.xyz / gl_LocalInvocationIndex (uint). HLSL SV_GroupThreadID, SV_GroupIndex. (없음) WGSL @builtin(local_invocation_id), @builtin(local_invocation_index).
16 Global invocation index TDIndex() (uint, 1D). manual dispatch 모드에서는 undefined → 사용자가 직접 계산해야 함. gl_GlobalInvocationID.xyz. HLSL SV_DispatchThreadID (uint3). VEX @elemnum / @ptnum / @primnum / @vtxnum. WGSL @builtin(global_invocation_id) (vec3).
17 Element index (1D thread index) TDIndex(). TDNumElements()로 총 개수. workgroup-rounded 초과 인덱스는 사용자가 bounds-check. 보통 gl_GlobalInvocationID.x. id.x (SV_DispatchThreadID의 첫 컴포넌트). VEX @elemnum (Run Over 모드에 따른 통합 인덱스). gid.x (global_invocation_id.x).
18 Atomic operation GLSL POP Output Access = readwrite 필수. GLSL 표준 atomic 함수 (atomicAdd 등) 사용 가능. GLSL atomicAdd(buf[i], v), atomicMin, atomicCounterIncrement (atomic counter 별도). HLSL InterlockedAdd(buf[i], v), InterlockedMin/Max/Or/And/Xor/Exchange/CompareExchange. (없음) — VEX는 element-parallel 모델이라 atomic 미지원. OpenCL Wrangle만 atomic_add 등 가능. WGSL atomicAdd(&buf[i], v) 등. atomic 타입 변수만 가능 (atomic<u32>).
19 Shared / group-shared memory wiki 미확정 — TD GLSL POP wiki에 shared qualifier 사용 가능 여부 명시 없음. GLSL 4.30+ 컴퓨트라면 원칙적으로 가능. 실험으로 확인 필요. GLSL shared T name[N]; + barrier(). Vulkan workgroup memory 동일. HLSL groupshared T name[N]; + GroupMemoryBarrierWithGroupSync(). (없음) — VEX는 element-isolated. WGSL var<workgroup> name: array<T, N>; + workgroupBarrier().
20 Specialization constant GLSL POP Constants 페이지 (const0name, const0value). 셰이더 컴파일 시점에 baked. GLSL layout(constant_id=N) const T name = default; (Vulkan SPIR-V). (직접 등가물 없음) — cs.SetInt 등 uniform 또는 multi_compile keyword variants. (없음) WGSL override name: T = default;.
21 Multi-pass (same shader N times) GLSL POP Passes (npasses) 파라미터. Advanced POP도 노출 (wiki에 충돌; 새 파라미터 페이지 우선). C++ 측에서 glDispatchCompute를 N회 + glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT). C# 측에서 cs.Dispatch를 N회. 사이에 GraphicsFence 가능. SOP Solver / For-loop SOP / Iterate Wrangle. 같은 encoder에서 dispatchWorkgroups를 N회. pass 분리 또는 barrier().
22 Ping-pong feedback Feedback POP (이전 프레임 출력 참조) + Cache POP. GLSL POP Copy Previous Pass Output to Input (prevpassoutput) 토글. 두 SSBO (또는 두 텍스처) 바인딩을 매 프레임 swap. ComputeBuffer 두 개, A→B, 다음 프레임 B→A. Solver SOP — 이전 프레임 출력이 자동으로 다음 입력. 두 storage buffer 핑퐁; 매 프레임 bind group swap.
23 Instancing (per-instance attribute) Geometry COMP에 POP을 instance 소스로 공급. POP의 point attribute가 per-instance 값. (15장 참조) glVertexAttribDivisor(loc, 1) + glDrawArraysInstanced(...). Graphics.RenderMeshInstanced / DrawMeshInstancedProcedural / MaterialPropertyBlock. Copy to Points SOP (per-point instance), i@instance attribute. passEncoder.draw(vertexCount, instanceCount) + @builtin(instance_index).
24 Instance ID GLSL MAT 측 TDInstanceID() (wiki: Write_a_GLSL_Material). 셰이더에서 instance 색·매트릭스를 얻을 때 사용. gl_InstanceID (정수). Vulkan gl_InstanceIndex. HLSL SV_InstanceID. (per-point instancing이라 명시적 ID 없음; ptnum이 대신). WGSL @builtin(instance_index) : u32.
25 Indirect dispatch GLSL POP Number of Threads = Number of Elements from Attribute 모드에서 자동 활성화. Wiki verbatim: "an indirect command buffer is filled, and the compute shader is launched with an indirect dispatch." glDispatchComputeIndirect(GLintptr) / vkCmdDispatchIndirect. ComputeShader.DispatchIndirect(kernel, argsBuffer, argsOffset). (없음) — VEX 외부에서 처리. WGSL/WebGPU passEncoder.dispatchWorkgroupsIndirect(buffer, offset).
26 Spatial neighborhood query Neighbor POP (k-NN), Proximity POP (radius). 또는 GLSL POP에서 uniform grid SSBO 직접 구현. (스펙 표준 아님) 사용자 SSBO 기반 grid / BVH. 하드웨어 ray-tracing API 활용 가능. DOTS KDTree, Compute Shader 기반 grid. VEX nearpoints(), pcfind(), xyzdist(), PointCloud 함수 제공 — 가장 풍부. (스펙 표준 아님) 사용자 storage buffer 기반 grid.
27 Sort primitive Sort POP (P 또는 임의 attribute 기준; vector / proximity / Geo-COMP-axis 모드). (없음 — 사용자 구현) bitonic / radix sort on SSBO. (없음 — 사용자 구현) compute shader 기반 sort. Sort SOP. VEX sort() array 함수. (없음 — 사용자 구현).
28 Reduction (sum / min / max / scan) Analyze POP (avg / min / max를 1-point 출력). prefix sum은 사용자 구현 (Advanced POP + atomic 또는 multi-pass). 컴퓨트 셰이더 사용자 구현. GPU Gems 3 Ch.39 (Harris scan). ComputeBuffer + 사용자 컴퓨트. Burst에는 IJobParallelForReduce 등. VEX attrib promote (detail로 promote = reduce). 컴퓨트 사용자 구현.
29 Material / shader-graph TD MAT family (Phong MAT / Constant MAT / GLSL MAT). GLSL MAT은 셰이더 직접 작성, 일반 MAT은 visual graph. (없음 — API에 visual graph 개념 없음) Unity Shader Graph (URP/HRP), HLSL .shader 파일. Material SOP (rendering 패스). (없음 — API에 visual graph 개념 없음)
30 Vertex shader stage input GLSL MAT vertex shader에서 TDPos(), TDNormal(), TDTexCoord(uint), TDPointColor(), custom은 TDAttrib_<name>(). layout(location=N) in T name;. HLSL vertex shader의 appdata struct semantic (POSITION, NORMAL, TEXCOORD0, …). (벡스는 rendering이 아님 — Karma/Mantra 측 별도) WGSL @vertex fn main(@location(N) name: T) -> ....
31 Fragment shader stage input GLSL MAT pixel shader의 in block — vertex shader out이 rasterizer 보간 후 들어옴. layout(location=N) in T name; + (선택) flat / noperspective qualifier. HLSL fragment shader v2f struct. (외부 렌더러) WGSL @fragment fn main(@location(N) name: T) -> ....
32 Render target / framebuffer Render TOP의 출력 텍스처. Render TOP 자체가 framebuffer 추상화. FBO (glGenFramebuffers + glFramebufferTexture2D). Vulkan VkFramebuffer. RenderTexture, CommandBuffer.SetRenderTarget. (외부 렌더러) GPURenderPassEncoder의 color attachments.
33 Render pass Render TOP cook 1회 = 1 render pass. Multiple pass는 multiple Render TOP. (OpenGL은 명시적 render pass 없음; Vulkan은 VkRenderPass로 명시). CommandBuffer + BeginRenderPass 패턴. (외부) commandEncoder.beginRenderPass({...}) ~ pass.end().

매핑 표에 대한 일반 주석

표의 각 행은 1:1 동치를 주장하지 않는다. 같은 슬롯에 들어가는 가장 가까운 개념의 환경별 이름이라는 의미다. 본 주석은 표를 읽을 때 자주 발생하는 오해를 사전에 차단한다.

TD POP 셀의 함수 이름 출처. TD POP 열에 적힌 모든 함수 이름은 §3 cheat-sheet의 verbatim 시그니처를 기준으로 한다. 즉 TDIndex(), TDNumElements(), TDIn_AttribName(), oTDPoint_AttribName[] 등은 TD wiki의 Write_a_GLSL_POP 페이지 문구 그대로다. 일반 GLSL의 gl_GlobalInvocationIDgl_LocalInvocationID는 TD wiki에 노출 여부가 명시되지 않았으므로 본 표에서 TD POP 셀에는 적지 않았다. 노출 여부가 궁금하다면 manual dispatch 모드에서 실험으로 확인해야 한다.

Houdini VEX 셀이 자주 "(없음)"인 이유. VEX는 GPU 컴퓨트 셰이더가 아니라 CPU/SIMD 컴파일러다. workgroup, dispatch, atomic, shared memory, indirect dispatch 같은 GPU-native 개념은 VEX 어휘에 존재하지 않는다. Houdini에서 같은 개념을 다루려면 OpenCL Wrangle SOP를 사용해야 하며, 그 안에서는 GL/Vulkan과 동일한 워크그룹·atomic 어휘가 다시 등장한다. 반대로 attribute 모델·neighborhood query·attribute promotion 등 데이터 모델 차원의 개념은 Houdini가 가장 풍부한 어휘를 제공하므로 그 행에서는 Houdini 셀이 가장 두껍다.

Unity 셀에 DOTS를 함께 적은 이유. Unity는 같은 attribute 모델을 두 경로로 노출한다. GPU 경로는 Compute Shader(HLSL RWStructuredBuffer<T>)이고, CPU 경로는 DOTS(IComponentData + Burst-compiled IJobEntity)다. 두 경로의 데이터 레이아웃은 거의 같다. 본 표에서 Unity 셀이 GPU 경로 위주로 쓰여 있지만, CPU 측 등가물은 DOTS에서 찾을 수 있음을 명시적으로 적어둔다. POP에서 익힌 dispatch 직관이 DOTS의 IJobParallelFor로 직접 옮겨간다.

WebGPU 셀이 "(없음)"인 항목들. WebGPU는 비교적 새 API이고, render pass·compute pipeline·storage buffer 같은 기본 추상화는 모두 명시적이지만, sort·reduce·neighborhood query 같은 상위 알고리즘은 표준 라이브러리가 아직 없다. 따라서 WebGPU 셀이 "(없음 — 사용자 구현)"인 행은 "이 환경에서는 직접 짜야 한다"는 의미다. WebGPU Fundamentals 같은 학습 사이트들이 그 빈자리를 메우고 있다.

"wiki 미확정" 표시. TouchDesigner wiki가 해당 기능의 노출 여부 또는 정확한 시그니처를 명시하지 않은 경우다. Local invocation index, shared memory, Advanced POP의 Collisions 페이지 등이 여기 해당한다. 본 부록의 §3 cheat-sheet에도 같은 표시가 일부 항목에 붙어 있다. 출판 직전 build 2025.31550 또는 이후 build에서 실험으로 재확인해야 한다.

OpenGL과 Vulkan을 한 셀에 합친 이유. 셰이더 단의 어휘는 GLSL 4.60 (OpenGL) 와 SPIR-V (Vulkan) 사이에서 거의 동일하다. API 단의 dispatch·buffer 바인딩·render pass 추상화에서만 차이가 크게 난다. 본 표는 셰이더 어휘 기준이므로 두 API를 한 셀에 합쳤다. API 단의 정밀한 차이는 Khronos 문서를 보아야 한다.

환경 간 "같은 개념, 다른 단어" 의 일반 규칙. 같은 컴퓨트 모델을 다섯 환경이 다섯 단어로 부른다는 사실이 본 부록의 출발점이다. 한 환경에서 익힌 직관을 다른 환경으로 옮길 때, 가장 먼저 해야 할 일은 "내가 익숙한 단어가 새 환경에서 어떤 단어로 바뀌는가"를 표에서 확인하는 것이다. 그 뒤에야 새 환경의 API quirk를 다룬다. 단어 매핑을 먼저 잡아 두지 않으면 같은 개념을 두 번 배우는 비효율이 생긴다.


2. Terminology Collisions — 같은 단어가 환경마다 다른 것

본 절은 research/03_theory_mapping.md의 Terminology Collisions 섹션을 verbatim 인용하고, 본 부록 분량에 맞춰 확장한다. 검색 시점에 가장 자주 헷갈리는 충돌만 다룬다.

용어 충돌은 단순히 학습자의 혼란이 아니라 검색 행동의 함정이다. 한 환경에서 익힌 단어를 다른 환경의 문서에 그대로 검색하면, 같은 글자가 가리키는 전혀 다른 시스템의 문서가 나온다. 이 절은 그런 검색 함정을 사전에 차단하는 용도로 쓴다. 본 핸드북의 각 챕터는 충돌이 처음 등장하는 자리에서 한 번 언급하지만, 본 부록은 reference 용도로 한자리에 모아둔다.

2.1 POP

본 핸드북에서 "POP"은 항상 TouchDesigner Point Operator를 가리킨다. SideFX 문서를 참조할 일이 있다면 "POP"이라는 단어 자체가 다른 시스템을 가리킨다는 사실을 먼저 인지하고 들어가야 한다. 특히 Houdini의 입자 시스템 자료를 찾는다면 검색어는 "POP"이 아니라 "DOP particles" 또는 "Particle DOP"가 정답이다. 본 핸드북의 10장 (입자 시뮬레이션)이 다루는 POP-based 입자 시스템과 Houdini 입자 시스템은 데이터 모델 차원에서는 비슷하지만 (둘 다 point에 velocity·age·mass attribute를 두는 attribute-update 루프), 구현 환경과 노드 이름은 전혀 다르다.

2.2 Compute shader / kernel / shader graph node

이 셋을 같은 평면에 두지 말 것. graph는 source, kernel/compute shader는 product. 즉 graph 노드를 편집하면 컴파일 결과로 셰이더가 만들어진다. 셰이더는 GPU에서 실행되는 코드 그 자체이지만, graph는 그 코드를 생성하는 도구다. 본 핸드북의 GLSL POP은 graph가 아니라 셰이더를 직접 작성하는 환경이며, TouchDesigner의 일반 MAT 노드들 (Phong MAT, Constant MAT) 은 그래프 측에 해당한다. 14장에서 다루듯, Phong MAT은 GLSL MAT을 TD가 자동 생성한 결과로 볼 수 있다.

2.3 Vertex

같은 단어가 세 가지 메모리 위치를 가리킨다. 본 핸드북은 vertex를 항상 TD POP 의미 (per-corner record) 로만 쓴다. Ch.2의 attribute model이 이 분리를 명시적으로 다루며, Normal POP의 Type = Vertex 옵션이 per-corner normal을 만드는 경로다. OpenGL/LearnOpenGL/RTR4 자료를 참조할 때는 "vertex"가 POP의 "point"를 의미한다는 점을 항상 머릿속에서 치환해 읽어야 한다.

2.4 Attribute

둘은 겹치지만 같지 않다. POP attribute는 셰이더 stage에 들어가기 직전까지 SSBO다. raster pipeline에 진입할 때 GLSL MAT의 vertex shader가 TDPos() / TDNormal() 등의 헬퍼를 통해 그 SSBO를 읽고 vertex stage in 변수로 옮긴다. 즉 두 의미는 "셰이더에 들어가기 전" 의 attribute와 "셰이더 안에서의 입력 변수" 의 attribute다. 같은 데이터가 두 위치를 차례로 거치므로 같은 단어가 쓰이지만, 추상화 계층은 다르다. Ch.14가 이 흐름을 다이어그램으로 보여준다.

2.5 Buffer

Ch.4의 "텍스처와 vertex buffer는 같은 GPU 메모리다"라는 명제는 이 구분을 분리하지 않으면 성립하지 않는다. TouchDesigner 일상 어휘의 "buffer"가 GL 어휘의 "framebuffer"와 같고, GL 어휘의 "buffer"는 TD에서 attribute SSBO·texture·constant buffer 모두에 해당한다. 본 핸드북은 "buffer"라는 단어가 등장할 때마다 어느 의미인지 문맥으로 표시한다 — GLSL POP 출력 SSBO를 "buffer"라 부르는 경우와 Render TOP 출력을 "buffer"라 부르는 경우가 같은 단락에서 등장한다면 명시적으로 풀어 쓴다.

2.6 Particle system

TouchDesigner 안에서도 "particle"이 세 구현 (Particle SOP / Particle GPU TOP / POP-based) 을 동시에 가리킬 수 있다는 점이 특히 까다롭다. 같은 프로젝트에서 세 구현 중 둘을 함께 쓰는 일도 가능하다 — Particle GPU TOP으로 만든 입자 위치를 TOP→POP을 거쳐 GLSL POP에서 후속 처리하는 식이다. 본 핸드북의 10장이 POP-based 경로를 가르치는 이유는 그것이 GPU compute의 가장 자연스러운 표현이고 attribute 모델과 일관되기 때문이다. 다른 두 구현이 잘못된 것은 아니다 — 각각 다른 시점에 설계된 서로 다른 추상화일 뿐이다.

2.7 부수 충돌 (참고)


3. TouchDesigner GLSL 헬퍼 함수 cheat-sheet

본 절은 research/02_chapter_briefs/glsl_pop_deep.md의 verbatim 인용을 그대로 옮긴다. 핸드북 본문 각 챕터에서 이 cheat-sheet를 가리킨다. 일반 GLSL의 gl_GlobalInvocationID는 TD wiki가 명시하지 않으므로 사용하지 않는다 — TDIndex()를 쓴다.

TouchDesigner는 GLSL 컴퓨트 셰이더의 raw 인덱싱 API를 자체 헬퍼 함수로 한 번 감싼다. 이 감싸기의 두 가지 의도가 있다. 첫째, dispatch 모드를 사용자 파라미터로 자동 선택하면서 셰이더 코드는 바뀌지 않게 한다 — Auto / Manual / Indirect 등 어느 모드든 TDIndex() 한 줄이면 된다. 둘째, attribute 단의 SSBO 바인딩을 셰이더 코드 안에 직접 적지 않게 한다 — TDIn_P() 한 줄로 input 0의 P를 읽고, P[id] = ... 한 줄로 출력 SSBO에 쓴다. 결과적으로 TD-flavored compute shader는 일반 GLSL 컴퓨트보다 훨씬 짧지만, 그 짧음의 대가로 명시적 인터페이스 일부가 감춰진다. 본 절은 그 인터페이스의 verbatim 시그니처를 한자리에 모아둔다.

본 절을 읽는 순서는 indexing → element count → input read → output write → 부수 함수다. 모든 컴퓨트 셰이더는 indexing + bounds-check + input read + output write 네 단계를 거치며, 이 순서가 §3.1부터 §3.7까지의 배열과 일치한다. §3.8 이후는 특수 용도 (cache, array attribute, noise, extra output, GLSL MAT 등) 의 헬퍼다.

3.1 Indexing — 모든 GLSL POP의 공통 진입점

uint TDIndex();
// 1d index for current thread.
// undefined when number of threads is manual.

uint TDNumElements();
// number of requested threads based on dispatch mode and number of threads mode.
// actual number of threads is ceil to workgroup size (32 on NVIDIA, 64 on AMD).
// undefined when number of threads is manual.

필수 관용구 (모든 컴퓨트 셰이더의 본문 첫 두 줄):

const uint id = TDIndex();
if (id >= TDNumElements()) return;

wiki verbatim: "The if condition prevents the shader to write outside of the bounds of the allocated SSBO, which can lead to unpredictible results and crashes."

3.2 입력 요소 개수 (Input element counts)

GLSL POP / Advanced POP 공통:

uint TDInputNumPoints(uint inputIndex); // number of points in inputIndex input
uint TDInputNumPrims (uint inputIndex); // number of prims  in inputIndex input
uint TDInputNumVerts (uint inputIndex); // number of verts  in inputIndex input
// returns 0 if input doesn't exist

// 인자 생략 시 input 0:
TDInputNumPoints() = TDInputNumPoints(0);
TDInputNumPrims()  = TDInputNumPrims(0);
TDInputNumVerts()  = TDInputNumVerts(0);

GLSL POP 전용 (선택된 attribute class에 따라 자동 분기):

uint TDInputNumElements();
// wrapper for TDInputNumPoints() / TDInputNumPrims() / TDInputNumVerts()
// depending on attribute class.

3.3 Attribute 읽기 — GLSL POP

선택된 class와 같은 class의 attribute:

attribType TDIn_AttribName(uint inputIndex, uint elementId, uint arrayIndex);
// 인자 생략 시: TDIn_AttribName() = TDIn_AttribName(0, TDIndex(), 0);
// arrayIndex 생략 시: TDIn_AttribName(inputIndex, elementId) = TDIn_AttribName(inputIndex, elementId, 0);
// bounds-checked — out-of-range는 마지막 element/arrayIndex 반환.

선택된 class와 다른 class의 attribute (POP만; Advanced POP은 모든 class에 prefix를 강제):

attribType TDInPoint_AttribName(uint inputIndex, uint pointId, uint arrayIndex);
attribType TDInVert_AttribName (uint inputIndex, uint vertId,  uint arrayIndex);
attribType TDInPrim_AttribName (uint inputIndex, uint primId,  uint arrayIndex);

3.4 Attribute 읽기 — GLSL Advanced POP

모든 class에 prefix 강제:

attribType TDInPoint_AttribName(uint inputIndex, uint pointId, uint arrayIndex);
attribType TDInVert_AttribName (uint inputIndex, uint vertId,  uint arrayIndex);
attribType TDInPrim_AttribName (uint inputIndex, uint primId,  uint arrayIndex);

3.5 Cache POP 읽기 (시간축 보관)

GLSL POP:

attribType TDInCache_AttribName(uint inputIndex, uint cacheIndex, uint elemId, uint arrayIndex);

GLSL Advanced POP (class prefix 포함):

attribType TDInCachePoint_AttribName(uint inputIndex, uint cacheIndex, uint elemId, uint arrayIndex);
attribType TDInCacheVert_AttribName (uint inputIndex, uint cacheIndex, uint elemId, uint arrayIndex);
attribType TDInCachePrim_AttribName (uint inputIndex, uint cacheIndex, uint elemId, uint arrayIndex);

3.6 출력 쓰기 — GLSL POP

GLSL POP의 출력은 함수가 아니라 배열 변수다. 이 설계의 이유는 atomic 연산 호환성이다. GLSL의 atomicAdd(mem, data) 같은 함수는 첫 인자로 메모리 위치 참조를 받는데, 함수 호출 결과는 rvalue라서 atomic의 lvalue 인자로 쓸 수 없다. TouchDesigner는 이 한계 때문에 출력을 AttribName[id] = ... 형태의 배열 변수로 노출한다.

attribType AttribName[];
// 함수가 아니라 배열 변수 — atomicAdd 등 atomic 함수에 직접 넘길 수 있다.

대표 사용:

void main() {
    const uint id = TDIndex();
    if (id >= TDNumElements()) return;
    P[id] = TDIn_P();
}

wiki note: "For P[id] = TDIn_P(); to compile without error, P needs to be present in the input, and selected for writing in 'Output Attributes'."

3.7 출력 쓰기 — GLSL Advanced POP

class prefix 강제:

attribType oTDPoint_AttribName[];
attribType oTDVert_AttribName [];
attribType oTDPrim_AttribName [];

대표 사용:

void main() {
    const uint id = TDIndex();
    if (id >= TDNumElements()) return;
    oTDPoint_P[id] = TDInPoint_P();
}

3.8 Index buffer

읽기 (POP 공통):

uint TDInputPointIndex(uint inputIndex, uint vertIndex);
uint TDInputPointIndex(uint vertIndex) = TDInputPointIndex(0, vertIndex);
// bounds-checked.

쓰기 (Advanced POP 전용 — Max Primitives 파라미터를 custom으로 설정한 경우만 활성):

uint I[];

3.9 Array attribute 크기 상수

GLSL POP:

const uint cTDArraySize_AttribName;

GLSL Advanced POP (class별 분리):

const uint cTDArraySizePoint_AttribName;
const uint cTDArraySizeVert_AttribName;
const uint cTDArraySizePrim_AttribName;

3.10 Built-in noise

float TDSimplexNoise(vec3 p);
// GLSL POP의 TDSimplexNoise() 파라미터 메뉴로
// performance vs quality 모드 선택 가능.

3.11 Extra Output (Advanced POP 전용)

GLSL Select POP이 picks하는 추가 출력 통로. 각 extra-output 블록의 사용자 지정 이름을 OutputName이라 할 때:

// 입력 element 개수:
uint TDInputNumPoints_OutputName();
uint TDInputNumPrims_OutputName();
uint TDInputNumVerts_OutputName();

// 입력 attribute 읽기 (inputIndex 인자 없음 — extra output당 source POP 하나):
attribType TDInPoint_OutputName_AttribName(uint pointId, uint arrayIndex);
attribType TDInVert_OutputName_AttribName (uint vertId,  uint arrayIndex);
attribType TDInPrim_OutputName_AttribName (uint primId,  uint arrayIndex);

// 출력 쓰기:
attribType oTDPoint_OutputName_AttribName[];
attribType oTDVert_OutputName_AttribName [];
attribType oTDPrim_OutputName_AttribName [];

// Array size 상수:
const uint cTDArraySizePoint_OutputName_AttribName;
const uint cTDArraySizeVert_OutputName_AttribName;
const uint cTDArraySizePrim_OutputName_AttribName;

// Index buffer 접근:
uint TDInputPointIndex_OutputName(uint vertIndex);
// wiki에 "TDInputPointIndex_OuputName" 오탈자 그대로 — 실제 함수명은 정정될 수 있다 (실험 필요).

Dimension 헬퍼 (extra output 단위):

const uint cTDDimSize_OutputName;
uint[cTDDimSize_OutputName] TDDimension_OutputName();
uint[cTDDimSize_OutputName] TDDimCoords_OutputName(uint pointIndex);
uint TDDimPointIndex_OutputName(uint[cTDDimSize_OutputName] coords);

3.12 GLSL MAT 측 (14장 참조)

POP attribute를 vertex shader에서 받기 위한 헬퍼. 14장 hands-on에서 verified.

// 위치·법선·UV·점 색 (built-in attribute 접근자)
vec4 TDPos();           // POP P를 vec4(P.xyz, 1.0)로
vec3 TDNormal();        // POP N
vec3 TDTexCoord(uint i);// POP Tex (i번째 UV set)
vec4 TDPointColor();    // POP Cd

// 사용자 정의 attribute (GLSL MAT의 Attributes 페이지에 이름+타입 선언 후)
T TDAttrib_AttribName();
// 예: TDAttrib_vel() — Type vec3로 선언된 vel attribute를 vertex shader에서 읽음.

// POP element-단위 직접 접근 (vertex stage가 아닌 임의 인덱스로 buffer를 읽고 싶을 때)
T TDBuffer_AttribName(uint elementIndex, uint arrayIndex);
// wiki: Write_a_GLSL_Material — "POP attribute access".

// Instancing
uint TDInstanceID();             // 현재 instance index.
mat4 TDInstanceMat();            // per-instance 변환 매트릭스.
vec4 TDInstanceColor(vec4 def);  // per-instance 색 (없으면 default).
T    TDInstanceCustomAttrib0();  // Geometry COMP의 Instancing 페이지 Custom Attrib 0..3.
T    TDInstanceCustomAttrib1();
T    TDInstanceCustomAttrib2();
T    TDInstanceCustomAttrib3();

// 변환 헬퍼
vec4 TDDeform(vec4 pos);            // SOP/POP-space → world-space (instancing/skin 포함).
vec3 TDDeformNorm(vec3 n);          // 법선의 world 변환.
vec4 TDWorldToProj(vec4 worldPos);  // world → clip-space.

// Fragment 출력 swizzle
vec4 TDOutputSwizzle(vec4 col);     // 출력 텍스처 채널 순서 보정.

// Camera matrix uniform
uniform TDMatrix uTDMats[TD_NUM_CAMERAS];
// stereo / multi-camera 렌더 대응. 일반 단일 카메라는 uTDMats[0] 사용.

주의 (wiki 미확정 — 실험 필요): TDAttrib_<name>() / TDBuffer_<name>() / TDInstanceCustomAttribN() 의 시그니처는 Write_a_GLSL_Material 페이지를 1차 출처로 한다. 본 부록은 verbatim 인용을 보장하지 않는 항목이 있다 (14장 hands-on에서 사용된 형태에 한해 검증됨).

3.13 표 — 어디서 무엇을 쓰는가

컨텍스트 Element index Element count 입력 read 출력 write 인덱스 버퍼 read
GLSL POP TDIndex() TDNumElements() / TDInputNumElements() TDIn_AttribName() (selected class) / TDInPoint_/TDInVert_/TDInPrim_AttribName() (other classes) AttribName[id] TDInputPointIndex(vertIndex)
GLSL Advanced POP TDIndex() TDNumElements() TDInPoint_/TDInVert_/TDInPrim_AttribName() oTDPoint_/oTDVert_/oTDPrim_AttribName[id] TDInputPointIndex(vertIndex)
Advanced POP Extra Output TDIndex() TDInputNumPoints_OutputName() TDInPoint_OutputName_AttribName() oTDPoint_OutputName_AttribName[id] TDInputPointIndex_OutputName(vertIndex)
GLSL MAT vertex shader (per-vertex stage; index는 gl_VertexID) (mesh이 결정) TDPos() / TDNormal() / TDAttrib_<name>() / TDBuffer_<name>(i,a) gl_Position = TDWorldToProj(...); out block n/a (raster pipeline)
GLSL MAT fragment shader n/a (per-fragment) n/a in block (vertex shader out의 보간) fragColor = TDOutputSwizzle(...) n/a

4. 출처 (Sources, 본 부록에 한정)

유지보수 메모: TouchDesigner wiki의 파라미터 페이지는 footer에 wikieditor2025.30000이 적혀 있어 핸드북 reference build 2025.31550보다 약간 뒤처질 수 있다. 새 build에서 신규 helper 함수가 추가될 가능성이 있으므로 출판 직전 §3 cheat-sheet의 시그니처를 재확인해야 한다.

5. 본 부록의 한 줄 명제

같은 GPU 컴퓨트 모델을 다섯 환경이 다섯 단어로 부른다. 한 번 익힌 추상화는 단어만 바꾸면 그대로 다른 환경에서 동작한다. 본 부록은 그 단어 사전이다.

본문 17장 (Ch.17) 의 메타 명제 — "POP에서 손에 익은 dispatch·SSBO·attribute·ping-pong·instancing은 환경이 바뀌어도 이름만 바뀐다" — 의 reference table 판이다. 17장이 산문으로 풀어 쓴 매핑을 본 부록이 표 한 장으로 압축했다. 두 자료를 함께 쓰는 것이 권장된다 — 17장으로 흐름을 잡고, 본 부록으로 정확한 시그니처를 확인한다.

학습자가 본 부록을 가장 자주 펼치는 시점은 새 환경에 처음 들어갈 때다. Unity Compute Shader 문서의 첫 페이지를 읽으면서 [numthreads]가 GLSL POP의 무엇에 해당하는지 즉시 알고 싶을 때, WGSL 스펙의 @workgroup_size가 같은 것임을 즉시 알고 싶을 때, Houdini Attribute Wrangle의 @PTDIn_P()와 같음을 즉시 알고 싶을 때 — 이 모든 시점에 본 부록의 §1 매핑 표가 답을 준다. 새 환경의 API quirk를 깊이 파기 전에 단어 매핑을 먼저 잡아두면 학습 시간이 절약된다.