Unity의 스탠다드 셰이더 언어는 HLSL이고, 일반 HLSL 데이터 타입이 지원됩니다. 하지만 Unity에는 특히 모바일 플랫폼에서 지원을 개선하기 위한 추가 HLSL 타입이 있습니다.
셰이더의 연산은 대부분 플로팅 포인트 숫자(C# 같은 일반 프로그래밍 언어에서는 float
)에 대해 수행됩니다. 플로팅 포인트 타입의 몇 가지 배리언트인 float
, half
및 fixed
등이 있고, half3
및 float4x4
등 이런 배리언트의 벡터/매트릭스 배리언트도 있습니다. 타입마다 정밀도가 다르기 때문에, 성능과 전력 사용량도 다릅니다.
float
최고 정밀도 플로팅 포인트 값으로, 일반 프로그래밍 언어의 float
처럼 일반적으로 32비트입니다.
전체 float
정밀도는 일반적으로 월드 공간 포지션, 텍스처 좌표 또는 삼각법이나 제곱/지수연산 같은 복합 함수를 수반하는 스칼라 계산에 사용됩니다.
half
중정밀도 플로팅 포인트 값으로, 일반적으로 16비트입니다(–60,000 - +60,000 범위, 십진 숫자 약 3개의 정밀도).
반정밀도는 짧은 벡터, 방향, 오브젝트 공간 포지션, 고다이나믹 레인지 컬러에 유용합니다.
fixed
정밀도가 가장 낮은 고정 포인트 값입니다. 일반적으로 11비트고, 범위는 –2.0 - +2.0, 정밀도는 1/256입니다.
고정 정밀도는(일반 텍스처에 일반적으로 저장된) 일반 컬러와 간단한 컬러 작업 수행에 유용합니다.
정수(int
데이터 타입)는 종종 루프 카운터나 배열 인덱스로 사용됩니다. 이 용도로 사용할 경우 일반적으로 다양한 플랫폼에서 문제 없이 사용 가능합니다.
플랫폼에 따라 GPU에서 정수 타입을 지원하지 않을 수 있습니다. 예를 들어, Direct3D 9 및 OpenGL ES 2.0 GPU는 플로팅 포인트 데이터에만 동작하고(비트 또는 논리 연산을 수반하는) 간단해 보이는 정수식을 꽤 복잡한 플로팅 포인트 수학 명령을 사용하여 에뮬레이트할 수 있습니다.
Direct3D 11, OpenGL ES 3, Metal 및 기타 최신 플랫폼은 정수 데이터 타입을 제대로 지원하므로 비트 시프트와 비트 마스킹을 사용하면 올바르게 작동합니다.
HLSL에는 기본 타입을 토대로 만든 빌트인 벡터 및 매트릭스 타입이 있습니다. 예를 들어, float3
은 .x, .y, .z 컴포넌트가 있는 3D 벡터고 half4
는 .x, .y, .z, .w 컴포넌트가 있는 중정밀도 4D 벡터입니다. 또는 컬러 관련 작업을 수행할 때 유용한 .r, .g, .b, .a 컴포넌트를 사용하여 벡터를 인덱스할 수 있습니다.
매트릭스 타입도 유사한 방법으로 빌드됩니다. 예를 들어 float4x4
는 4x4 변환 매트릭스입니다. OpenGL ES 2.0 같은 일부 플랫폼에서는 정사각형 매트릭스만 지원합니다.
일반적으로 텍스처를 HLSL 코드에서 다음과 같이 선언합니다.
sampler2D _MainTex;
samplerCUBE _Cubemap;
모바일 플랫폼의 경우 “저정밀도 샘플러”로 변환됩니다. 즉, 텍스처에는 저정밀도 데이터가 있어야 합니다. 텍스처에 HDR 컬러가 포함되어 있음을 알고 있는 경우 반정밀도 샘플러를 사용할 수 있습니다.
sampler2D_half _MainTex;
samplerCUBE_half _Cubemap;
또는 텍스처에 전체 플로트 정밀도 데이터가 포함된 경우(예: 뎁스 텍스처), 전체 정밀도 샘플러를 사용합니다.
sampler2D_float _MainTex;
samplerCUBE_float _Cubemap;
float
/half
/fixed
데이터 타입을 사용하는 경우에 발생하는 복잡한 문제 중 하나는 PC GPU가 항상 고정밀도라는 점입니다. 즉, 모든 PC(Windows/Mac/Linu) GPU는 셰이더에서 float
, half
또는 fixed
데이터 타입 중 무엇을 작성하든 상관없이 항상 모든 것을 전체 32비트 플로팅 포인트 정밀도로 연산합니다.
half
및 fixed
타입은 모바일 GPU가 타겟인 경우에만 중요합니다. 이 경우 두 타입은 주로 전력(및 때로는 성능) 제약을 위해 존재합니다. 셰이더를 테스트하여 정밀도/숫자 문제가 발생하지 않는지 확인해야 함을 기억해야 합니다.
모바일 GPU의 경우에도 여러 정밀도 지원이 GPU 제품군에 따라 다릅니다. 다음은 각 모바일 GPU 제품군이 각 플로팅 포인트 타입(각 타입에 사용된 비트 수로 나타냄)을 처리하는 방법의 개요입니다.
GPU 제품 | float | half | fixed |
---|---|---|---|
PowerVR Series 6/7 | 32 | 16 | |
PowerVR SGX 5xx | 32 | 16 | 11 |
Qualcomm Adreno 4xx/3xx | 32 | 16 | |
Qualcomm Adreno 2xx | 32버텍스 24프래그먼트 | ||
ARM Mali T6xx/7xx | 32 | 16 | |
ARM Mali 400/450 | 32버텍스 16프래그먼트 | ||
NVIDIA X1 | 32 | 16 | |
NVIDIA K1 | 32 | ||
NVIDIA Tegra 3/4 | 32 | 16 |
대부분의 최신 모바일 GPU는 실제로 32비트 숫자(float
타입에 사용됨) 또는 16비트 숫자(half
및 fixed
타입에 모두 사용됨) 중 하나만 지원합니다. 일부 구형 GPU의 버텍스 셰이더 및 프래그먼트 셰이더 연산 정밀도는 다릅니다.
더 낮은 정밀도를 사용하면 GPU 레지스터 할당 개선으로 인해 또는 특정 저정밀도 수학 연산을 위한 특수 “빠른 경로” 실행 유닛으로 인해 종종 빨라질 수 있습니다. 순수한 성능상의 이점이 없는 경우에도 더 낮은 정밀도를 사용하면 종종 GPU에 전원이 덜 사용되어 배터리 수명이 연장됩니다.
일반적인 경험 법칙에 따르면, 포지션 및 텍스처 좌표를 제외한 모든 것에 대해 반정밀도로 시작해야 합니다. 계산의 일부분에 반정밀도가 충분하지 않은 경우에만 정밀도를 높여야 합니다.
특수 플로팅 포인트 값에 대한 지원은 사용하는 GPU 제품군(대부분 모바일)에 따라 다를 수 있습니다.
Direct3D 10을 지원하는 모든 PC GPU는 매우 정확하게 규정된 IEEE 754 플로팅 포인트 스탠다드를 지원합니다. 즉, 플로트 숫자가 CPU에 일반적인 프로그래밍 언어에서 동작하는 것과 똑같이 동작합니다.
모바일 GPU의 지원 수준은 약간 다를 수 있습니다. 일부 GPU로 0을 0으로 나눈 결과는 NaN(“숫자 아님”)이 될 수 있고, 그 외의 GPU에서는 무한, 0, 또는 기타 지정되지 않은 값이 될 수 있습니다. 타겟 디바이스에서 셰이더를 테스트하여 지원되는지 확인해야 합니다.
GPU 제조사는 자사 GPU의 성능 및 기능에 대한 심층적인 가이드를 제공합니다. 자세한 내용은 다음을 참조하십시오.