프로그래밍/DirectX

정점 셰이더

이재만박사 2015. 8. 7. 16:52

다음은 간단한 정점 셰이더의 구현 코드이다


cbuffer cbPerObject

{

float4x4 gWorldViewProj;

};


void VS(float3 iPosL : POSITION,

  float4 iColor : COLOR,

  out float4 oPosH : SV_POSITION,

  out float4 oColor : COLOR)

{

// 동차 절단 공간으로 변환한다

oPosH = mul(float4(iPosL, 1.0f), gWorldViewProj);


// 정점 색상을 그대로 픽셀 셰이더에 전달한다

oColor = iColor;

}


하나의 정점 셰이더는 본질적으로 하나의 함수이다.

지금 예의 정점 셰이더는 매개변수가 4개인데, 처음 둘은 입력 매개변수이고 나머지 둘은 out 키워드가 붙어있으므로 출력 매개변수이다.

HLSL에는 참조나 포인터가 없으므로, 함수가 여러 개의 값들을 돌려주려면 구조체를 사용하거나 이처럼 out이 지정된 출력 매개변수를 사용해야 한다.

정점 셰이더의 처음 두 입력 매개변수는 정점 셰이더의 입력 서명을 형성하며, 커스텀 정점 구조체의 자료 멤버들에 대응된다. 매개변수 의미소: POSITION과 :COLOR는 정점 구조체의 멤버들을 정점 셰이더 입력 매개변수들에 대응시키는 역할을 한다.

출력 매개변수에도 의미소가 부여되어 있다. 이들은 정점 셰이더의 출력을 파이프라인의 다음단계(기하 셰이더, 픽셀 셰이더)의 해당 입력에 대응시키는 역할을 한다. SV_POSITION 의미소는 특별한 의미소임을 주목할 것. SV는 이것이 system value(시스템 값) 의미소입을 뜻한다.


행렬 변수 gWorldViewProj는 상수 버퍼에 있는 것인데, 상수 버퍼에 대해서는 다음 절에서 이야기하겠다.

mul은 HLSL의 내장함수로, 벡터, 행렬의 곱셈을 수행한다. 


다음은 이 정점 셰이더와 정확히 같은 일을 하는 정점 셰이더로, 다른 점은 반환 형식과 입력 서명에 구조체들을 사용한다는 것


cbuffer cbPerObject

{

float4x4 gWorldViewProj;

};


struct VertexIn

{

float3 PosL : POSITION;

float4 Color : COLOR;

};


struct VertexOut

{

float4 PosH : SV_POSITION;

float4 Color : COLOR;

};


VertexOut VS(VertexIn vin)

{

VertexOut vout;


// 동차 절단 공간으로 변환

vout.PosH = mul(float(vin.PosL, 1.0f), gWorldViewProj);


// 정점 색상을 그대로 픽셀 셰이더에 전달

vout.Color = vin.Color;


return vout;

}


* 참고

- 기하 셰이더를 사용하지 않는다면 정점 셰이더에서 투영 변환을 반드시 수행해야 한다. 기하 셰이더가 쓰이지 않는 경우 하드웨어는 정점 셰이더를 떠난 정점이 동차 절단 공간에 있다고 가정하기 때문이다. 기하 셰이더를 사용하는 경우에는 투영 변환을 기하 셰이더에게 미룰 수 있다.


* 참고

- 정점 셰이더(또는 기하 셰이더)가 원근 나누기까지 수행하지는 말아야 한다. 투영 행렬을 곱하는 부분만 책임지면 된다. 원근 나누기는 나중에 하드웨어가 수행한다.