The standard Shader language in Unity is HLSL, and general HLSL data types are supported. However, Unity handles some data types differently from HLSL, particularly to provide better support on mobile platforms.
Shaders carry out the majority of calculations using floating point numbers (which are float
in regular programming languages like C#). In Unity’s implementation of HLSL, the scalar floating point data types are float
, half
, and fixed
. These data types differ in precision and, consequently, performance or power usage. There are also several related data types for vectors and matrices such as half3
and float4x4
.
float
이는 정밀도가 가장 높은 부동 소수점 데이터 타입입니다.대부분의 플랫폼에서 float
값은 일반 프로그래밍 언어에서와 같이 32비트입니다.
Full float
precision is generally useful for world space positions, texture coordinates, or scalar calculations that involve complex functions such as trigonometry or power/exponentiation. If you use lower precision floating point data types for these purposes, it can cause precision-related artifacts. For example with texture coordinates, a half
doesn’t have enough precision to accurately represent 1-texel offsets of larger textures.
half
This is a medium precision floating point data type. On platforms that support half
values, they are generally 16 bits. On other platforms, this becomes float
.
half
값은 float
값보다 범위가 더 작고 정밀도가 더 낮습니다.
반정밀도는 짧은 벡터, 방향, 오브젝트 공간 포지션, 높은 동적 범위 컬러와 같이 높은 정밀도가 필요하지 않은 값의 셰이더 성능을 향상시키는 데 유용합니다.
fixed
이는 OpenGL ES 2.0 Graphics API에서만 지원됩니다.다른 API에서는 지원되는 정밀도가 가장 낮아집니다(half
또는 float
).
정밀도가 가장 낮은 고정 포인트 값이며 일반적으로 11비트입니다.fixed
값의 범위는 –2.0에서 +2.0이며 정밀도는 1/256입니다.
고정 정밀도는(일반 텍스처에 일반적으로 저장된) 일반 컬러와 간단한 컬러 작업 수행에 유용합니다.
Unity의 셰이더 컴파일러는 HLSL의 부동 소수점 숫자 접미사를 무시합니다.따라서 접미사가 있는 부동 소수점 숫자는 모두 float
가 됩니다.
다음 코드는 Unity에서 접미사 h
가 있는 숫자가 부정적인 영향을 미칠 수 있음을 보여줍니다.
half3 packedNormal = ...;
half3 normal = packedNormal * 2.0h - 1.0h;
접미사 h
가 무시되기 때문에 셰이더 컴파일러는 다음 단계를 실행하는 코드를 생성합니다.
1. 중간 normal
값을 고정밀도로 계산합니다(float3
).
2. 중간 값을 half3
로 전환합니다.
이렇게 하면 셰이더의 성능이 감소합니다.
다음 코드는 계산에 half
값만 사용하기 때문에 더욱 효율적입니다.
half3 packedNormal = ...;
half3 normal = packedNormal * half(2.0) - half(1.0);
정수(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;
모바일 플랫폼의 경우 “저정밀도 샘플러”로 변환됩니다. 즉, 텍스처에는 저정밀도 데이터가 있어야 합니다. Shader precision model 드롭다운을 사용하여 Player Settings에서 Unity 프로젝트 전체의 기본 샘플러 정밀도를 변경할 수 있습니다. 텍스처에 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의 성능 및 기능에 대한 심층적인 가이드를 제공합니다. 자세한 내용은 다음을 참조하십시오.