Shader Pipeline 4 Geometry Shader
“Fragemnt Shader” 에서 Fragment Shader 에 대해 알아보았다. 다음은 Geometry Shader 에 대해서 써보려 한다.
Geometry Shader 는 쉐이더 파이프라인에서 Rasterizer Stage 넘어가기 전의 Geometry Stage 의 마지막 단계로써 이전 쉐이더에서 넘긴 Primitive 데이터(point, line, triangle..)를 프로그래머가 원하는 복수의 Primitive 데이터로 변환할 수 있다. 삼각형을 삼각형의 중심을 나타내는 점으로 변환하는 쉐이더를 보자.
[maxvertexcount(1)]
void geom(vertexOutput input[3], inout PointStream<geometryOutput> pointStream)
{
geometryShaderOutput o;
o.vertex = (input[0].vertex + input[1].vertex + input[2].vertex) / 3;
pointStream.Append(o);
}
매우 간단한 코드다. 간략하게 설명하자면, 맨 윗줄의 maxvertexcount 는 해당 지오메트리 쉐이더에서 Stream 으로 넘길 정점별 데이터의 갯수를 뜻한다. Geometry Shader 한번당 Stream 으로 넘길 maxvertexcount 의 한계는 정해지지 않았지만 크기는 1024 바이트로 정해져 있기 때문에 적절하게 사용해야 겠다. 그 다음줄의 인자들에 대해서 설명하면, 첫번째 vertexOutput input[3] 은 정해진 프리미티브의 값들을 뜻한다. 여기서는 삼각형을 기준으로 만들었기 때문에 정점별 정보가 3개가 있다. _inout PointStream
Stream 은 총 두가지의 역할을 한다. 하나는 Rasterizer 단계로 넘겨서 쉐이더에서 처리를 할 수 있게 하는 통로 역할을 하고, 다른 하나는 드라이버 레벨에서 데이터를 출력해주는 통로 역할을 한다. 두가지의 일을 하기 때문에 Stream 의 개념으로 추상화한 것인가 싶다. 그리고 하나의 Geometry Shader 에서 여러개의 Stream 으로 출력이 가능하긴 하다. 최대 4개의 Stream 을 사용할 수 있다. Stream 을 선택해서 데이터를 받아올 수도 있으며, Rasterizer 로 보낼수도 있다. 자세한 사항은 MSDN : How To: Index Multiple Output Streams 에서 확인하면 되겠다.
활용할 수 있는 다른 기능이 하나 더 있다. instance 기능이다. 아래 코드를 보자.
[instance(3)]
[maxvertexcount(1)]
void geom(vertexOutput input[3], uint InstanceID : SV_GSInstanceID, inout PointStream<geometryOutput> pointStream)
{
geometryShaderOutput o;
o.vertex = input[InstanceID].vertex;
pointStream.Append(o);
}
해당 코드는 삼각형의 세개의 정점 위치를 넘기는 코드다. 달라진 것은 instance(3) 코드가 붙고, uint InstanceID : SV_GSInstanceID 파라미터가 생겨 코드 안에서 이를 활용한다. instance(x) 에 들어가는 x 는 반복하는 횟수를 뜻하고, InstanceID 파라미터는 반복하는 인덱스를 뜻한다. 같은 입력을 여러번 받아서 일정한 수만큼 반복하는 것이다. instance 속성에 들어가는 숫자의 한계는 32까지다.
Geometry Shader 는 Shader Model 4.0 에서 추가되었으며 뒤에 추가적으로 알아본 multiple stream 과 instance 키워드는 Shader Model 5.0 에서 확장된 기능들이다.