HLSL 셰이더 프로그램을 작성할 때 입력 및 출력 변수는 semantics를 통해 각각의 “의도”를 명시해야 합니다. 이는 HLSL 셰이더 언어의 표준 개념이며 자세한 내용은 MSDN의 시맨틱 문서를 참조하십시오.
메인 버텍스 셰이더 함수(#pragma vertex
지시자로 명시한 것)는
모든 입력 파라미터에 시맨틱이 있어야 합니다.
이는 버텍스 포지션, 노멀 메시, 텍스처 좌표 같은 개별 메시 데이터 요소에 해당합니다.
자세한 내용은 버텍스 프로그램 입력을 참조하십시오.
다음은 버텍스 포지션 및 텍스처 좌표를 입력으로 받는 단순한 버텍스 셰이더의 예제입니다. 이 픽셀 셰이더는 텍스처 좌표를 컬러로 시각화합니다.
Shader "Unlit/Show UVs"
{
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct v2f {
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
v2f vert (
float4 vertex : POSITION, // vertex position input
float2 uv : TEXCOORD0 // first texture coordinate input
)
{
v2f o;
o.pos = UnityObjectToClipPos(vertex);
o.uv = uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return fixed4(i.uv, 0, 0);
}
ENDCG
}
}
}
모든 개별 입력 하나씩 시맨틱을 명시하는 대신 이 입력을 구조로 선언하고 구조의 각 개별 멤버 변수에 시맨틱을 명시할 수도 있습니다.
프래그먼트(픽셀) 셰이더는 SV_Target
시맨틱을 가진
컬러를 출력하는 경우가 많습니다. 바로 위의 예제가
그런 경우입니다.
fixed4 frag (v2f i) : SV_Target
frag
함수는 fixed4
타입(낮은 정밀도 RGBA 컬러)을 반환합니다.
함수는 하나의 값만을 반환하므로 시맨틱을
: SV_Target
로 함수 자체에 명시하였습니다.
출력에 구조를 함께 반환하는 것도 가능합니다. 위의 프래그먼트 셰이더는 다음 방식으로 재작성할 수도 있으며 동작은 동일합니다.
struct fragOutput {
fixed4 color : SV_Target;
};
fragOutput frag (v2f i)
{
fragOutput o;
o.color = fixed4(i.uv, 0, 0);
return o;
}
프래그먼트 셰이더에서 구조를 반환하는 것은 단일 컬러만을 반환하지 않는 셰이더의 경우에 특히 유용합니다. 프래그먼트 셰이더가 지원하는 추가 시맨틱은 다음과 같습니다.
SV_Target1
, SV_Target2
등은 셰이더가 작성한 추가 컬러입니다. 한 번에 하나 이상의 렌더 타겟에 렌더링할 때 사용되며 이를 멀티플 렌더 타겟 렌더링 기법 또는 MRT라고 합니다. SV_Target0
은 SV_Target
과 동일합니다.
일반적으로 프래그먼트 셰이더는 Z 버퍼 값을 오버라이드하지 않으며, 기본값은 일반 삼각 래스터화에서 사용됩니다.그러나 일부 효과의 경우 픽셀당 커스텀 Z 버퍼 뎁스 값을 출력하는 것이 유용합니다.
이러면 많은 GPU에서는 일부 뎁스 버퍼 최적화를 끄게 되므로 타당한 이유가 없다면 Z 버퍼 값을 오버라이드하지 말아야 합니다.SV_Depth
로 인한 비용은 GPU 아키텍처에 따라 다양하지만, 전반적으로 HLSL에서 빌트인 clip()
함수를 사용한 알파 테스트와 비용이 비슷합니다. 뎁스를 수정하는 렌더 셰이더는 모두 일반 불투명 셰이더입니다(예: AlphaTest
렌더링 대기열을 사용).
뎁스 출력값은 단일 float
이어야 합니다.
버텍스 셰이더는 버텍스의 마지막 클립 공간 포지션을 출력해 GPU에 화면의 어느 부분을 어느 뎁스로 래스터화할지 알려줍니다. 이 출력은 SV_POSITION
시맨틱을 가진 float4
타입이어야 합니다.
버텍스 셰이더로 생성된 다른 출력(“interpolators” 또는 “varyings”)은 특정 셰이더에 필요합니다. 버텍스 셰이더에서 출력된 이 값은 여러 렌더링된 삼각형의 표면에 보간되며 각 픽셀의 값은 프래그먼트 셰이더에 입력으로 전달됩니다.
많은 최신 GPU는 변수의 시맨틱에는 관여하지 않지만 일부 구형 시스템(대표적으로 셰이더 모델 2 GPU)에는 시맨틱에 관한 특수 규칙이 있습니다.
TEXCOORD0
, TEXCOORD1
등은 텍스처 좌표 및 포지션과 같은 임의의 고정밀도 데이터를 나타낼 때 사용합니다.COLOR0
, COLOR1
시맨틱은 단순한 컬러 값과 같은 정밀도가 낮은 0–1 범위의 데이터입니다.최상의 크로스 플랫폼 지원을 위해서는 버텍스 출력과
프래그먼트 입력을 TEXCOORDn
시맨틱으로 레이블해야 합니다.
버텍스에서 프래그먼트 셰이더로 정보를 넘기는 데 사용할 수 있는 전체 인터폴레이터 변수 개수에는 제한이 있습니다. 이 제한은 플랫폼 및 GPU에 따라 달라지며 일반적인 가이드라인은 다음과 같습니다.
float4
변수 하나로 패스할 수 있습니다(좌표 1개인 경우 .xy, 두 번째 좌표의 경우 .zw).#pragma target 3.0
).#pragma target 4.0
)입니다.특정 타겟 하드웨어에 상관 없이 일반적으로 성능상의 이유로 인터폴레이터를 최소한으로 사용하는 것이 좋습니다.
프래그먼트 셰이더는 렌더링되고 있는 픽셀의 포지션을 특수 VPOS
시맨틱을 통해 받을 수 있습니다.
이 기능은 셰이더 모델 3.0 이후로만 지원되므로 셰이더에 #pragma target 3.0
컴파일 지시자가 있어야 합니다.
플랫폼에 따라 스크린 공간 포지션 입력의 기본 타입이 달라지므로 이식성을 최대한 높이려면 UNITY_VPOS_TYPE
타입을 사용해야 합니다(대부분의 플랫폼에서는 float4
).
또한 픽셀 포지션 시맨틱을 사용하면 버텍스를 프래그먼트로 넘기는 동일 구조에서 클립 공간 포지션(SV_POSITION) 및 VPOS를 가지는 것이 어려워집니다.따라서 버텍스 셰이더는 클립 공간 포지션을 별도의 “out” 변수로 출력해야 합니다.아래의 예시 세이더를 참조하십시오.
Shader "Unlit/Screen Position"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
// note: no SV_POSITION in this struct
struct v2f {
float2 uv : TEXCOORD0;
};
v2f vert (
float4 vertex : POSITION, // vertex position input
float2 uv : TEXCOORD0, // texture coordinate input
out float4 outpos : SV_POSITION // clip space position output
)
{
v2f o;
o.uv = uv;
outpos = UnityObjectToClipPos(vertex);
return o;
}
sampler2D _MainTex;
fixed4 frag (v2f i, UNITY_VPOS_TYPE screenPos : VPOS) : SV_Target
{
// screenPos.xy will contain pixel integer coordinates.
// use them to implement a checkerboard pattern that skips rendering
// 4x4 blocks of pixels
// checker value will be negative for 4x4 blocks of pixels
// in a checkerboard pattern
screenPos.xy = floor(screenPos.xy * 0.25) * 0.5;
float checker = -frac(screenPos.r + screenPos.g);
// clip HLSL instruction stops rendering a pixel if value is negative
clip(checker);
// for pixels that were kept, read the texture and output it
fixed4 c = tex2D (_MainTex, i.uv);
return c;
}
ENDCG
}
}
}
프래그먼트 셰이더는 렌더링된 표면이 카메라를 향하는지, 카메라를 등지고 있는지를 나타내는 변수를 받을 수 있습니다. 이 변수는 나뭇잎이나 얇은 오브젝트 같이 양면에서 볼 수 있어야 하는 지오메트리를 렌더링할 때 유용합니다. VFACE
시맨틱 입력 변수는 전면을 향하는 삼각형에 대해서는 양의 값, 후면을 향하는 삼각형에는 음의 값이 됩니다.
이 기능은 셰이더 모델 3.0 이후로만 지원되므로 셰이더에 #pragma target 3.0
컴파일 지시자가 있어야 합니다.
Shader "Unlit/Face Orientation"
{
Properties
{
_ColorFront ("Front Color", Color) = (1,0.7,0.7,1)
_ColorBack ("Back Color", Color) = (0.7,1,0.7,1)
}
SubShader
{
Pass
{
Cull Off // turn off backface culling
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
float4 vert (float4 vertex : POSITION) : SV_POSITION
{
return UnityObjectToClipPos(vertex);
}
fixed4 _ColorFront;
fixed4 _ColorBack;
fixed4 frag (fixed facing : VFACE) : SV_Target
{
// VFACE input positive for frontbaces,
// negative for backfaces. Output one
// of the two colors depending on that.
return facing > 0 ? _ColorFront : _ColorBack;
}
ENDCG
}
}
}
위 예시의 셰이더는 컬 상태를 사용하여 후면 컬링을 비활성화합니다(기본적으로 후면을 향하는 삼각형은 전혀 렌더링되지 않음).여기에서는 다른 방향으로 회전하는 여러 사각형 메시에 셰이더를 적용했습니다.
버텍스 셰이더는 “버텍스 수”를 서명되지 않은 정수로 가지는 변수를 받을 수 있습니다. 대부분 버텍스당 데이터를 텍스처 또는 컴퓨트 버퍼에서 추가로 가져오고자 할 때 유용합니다.
이 기능은 DX10(셰이더 모델 4.0) 및 GLCore / OpenGL ES 3 이후로만 지원되므로, 셰이더에 #pragma target 3.5
컴파일 지시자가 있어야 합니다.
Shader "Unlit/VertexID"
{
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.5
struct v2f {
fixed4 color : TEXCOORD0;
float4 pos : SV_POSITION;
};
v2f vert (
float4 vertex : POSITION, // vertex position input
uint vid : SV_VertexID // vertex ID, needs to be uint
)
{
v2f o;
o.pos = UnityObjectToClipPos(vertex);
// output funky colors based on vertex ID
float f = (float)vid;
o.color = half4(sin(f/10),sin(f/100),sin(f/1000),0) * 0.5 + 0.5;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return i.color;
}
ENDCG
}
}
}