컴퓨트 셰이더는 노멀 렌더링 파이프라인과 별도로 GPU에서 실행되는 셰이더 프로그램입니다.
컴퓨트 셰이더는 대량 병렬 GPGPU 알고리즘 또는 게임 렌더링의 일부를 가속시키기 위해 사용할 수 있습니다. 효율적으로 사용하려면 GPU 아키텍처와 병렬 알고리즘에 대한 깊은 지식뿐만 아니라 DirectCompute, OpenGL Compute, CUDA, 또는 OpenCL에 대한 지식도 필요합니다.
Unity의 컴퓨트 셰이더는 DirectX 11 DirectCompute 기술과 거의 일치합니다. 컴퓨트 셰이더가 작동하는 플랫폼은 다음과 같습니다.
DirectX 11 또는 DirectX 12 그래픽스 API와 Shader Model 5.0 GPU가 적용된 Windows 및 Windows 스토어
Metal 그래픽스 API를 사용하는 Mac OS 및 iOS
Vulkan API가 적용된 Android, Linux 및 Windows 플랫폼
최신 OpenGL 플랫폼( Linux 또는 Windows의 경우 OpenGL 4.3, Android의 경우 OpenGL ES 3.1). Mac OS X는 OpenGL 4.3을 지원하지 않습니다.
최신 콘솔
컴퓨트 셰이더 지원은 SystemInfo.supportsComputeShaders를 사용하여 런타임에 쿼리할 수 있습니다.
셰이더 에셋과 유사하게 컴퓨트 셰이더 에셋은 .compute 파일 확장자를 가진 프로젝트의 파일입니다. DirectX 11 스타일 HLSL 언어로 작성되어 있으며, 어떤 기능을 컴퓨트 셰이더 커널로 컴파일할 것인지 나타내는 최소한의 #pragma 컴파일 지시자를 포함합니다.
다음은 출력 텍스처를 빨간색으로 채우는 컴퓨트 셰이더 파일의 기본 예제입니다.
// test.compute
#pragma kernel FillWithRed
RWTexture2D<float4> res;
[numthreads(1,1,1)]
void FillWithRed (uint3 dtid : SV_DispatchThreadID)
{
res[dtid.xy] = float4(1,0,0,1);
}
언어는 추가 #pragma kernel FillWithRed
지시문이 포함된 스탠다드 DX11 HLSL입니다. 하나의 컴퓨트 셰이더 에셋 파일에는 호출 가능한 최소 한 개의 ’컴퓨트 커널(kernel)’이 포함되어 있어야 하며, 해당 함수는 #pragma directive
로 표시되어야 합니다. 파일에는 하나 이상의 커널이 있을 수 있습니다. 여러 #pragma kernel
행을 추가하기만 하면 됩니다.
여러 #pragma kernel
행을 사용하는 경우 #pragma kernel
지시문과 동일한 행에 스타일 // text
주석을 사용할 수 없으므로 컴파일 오류가 발생하면 이를 사용해야 합니다.
#pragma kernel
행에는 선택적으로 해당 커널을 컴파일하는 동안 정의할 수 있는 많은 사전 처리기 매크로가 올 수 있습니다. 예를 들어 다음과 같습니다.
# pragma kernel KernelOne SOME_DEFINE DEFINE_WITH_VALUE=1337
# pragma kernel KernelTwo OTHER_DEFINE
// ...
스크립트에서 ComputeShader 타입의 변수를 정의하고 에셋에 대한 레퍼런스를 할당하면 ComputeShader.Dispatch 함수를 사용하여 불러올 수 있습니다. 자세한 내용은 ComputeShader 클래스의 Unity 문서를 참조하십시오.
컴퓨트 셰이더와 밀접한 관련이 있는 것은 ComputeBuffer 클래스로 임의의 데이터 버퍼(DX11 언어의 “구조화된 버퍼”)를 정의합니다. “랜덤 액세스” 플래그가 설정되었을 경우(DX11의 “정렬되지 않은 액세스 뷰”) Render Textures도 컴퓨트 셰이더에서 쓰기 가능합니다. 자세한 내용은 RenderTexture.enableRandomWrite를 참조하십시오.
텍스처와 샘플러는 Unity에서 별개의 오브젝트가 아니므로, 컴퓨트 셰이더에서 사용하려면 다음과 같은 Unity 관련 규칙 중 하나를 따라야 합니다.
텍스처 이름과 동일한 이름을 사용하고 처음에는 sampler
를 사용해야 합니다(예: Texture2D MyTex
; SamplerState samplerMyTex
). 이 경우, 샘플러는 텍스처의 filter/wrap/aniso 설정으로 초기화됩니다.
미리 정의된 샘플러를 사용해야 합니다. 이를 위해 이름은 Linear
또는 Point
(필터 모드의 경우) 및 Clamp
또는 Repeat
(랩 모드의 경우)가 있어야 합니다. 예를 들어 SamplerState MyLinearClampSampler
는 선형 필터 모드와 클램프 랩 모드가 있는 샘플러를 만듭니다.
자세한 내용은 샘플러 상태에 대한 문서를 참조하십시오.
일반 셰이더와 마찬가지로 Unity는 컴퓨트 셰이더를 HLSL에서 다른 셰이더 언어로 트랜스폼할 수 있습니다. 따라서 가장 쉬운 크로스 플랫폼 빌드를 위해 HLSL에 컴퓨트 셰이더를 작성해야 합니다. 그러나 이를 수행할 때 고려해야 할 몇 가지 요소가 있습니다.
DirectX 11(DX11)은 다른 플랫폼(Metal 또는 OpenGL ES 등)에서는 지원하지 않는 많은 작업을 지원합니다. 따라서 항상 DX11이 아닌 지원이 적은 플랫폼에서 셰이더가 잘 정의된 동작을 수행하도록 해야 합니다. 다음은 고려해야 할 몇 가지 사항입니다.
범위를 벗어난 메모리 액세스가 잘못되었습니다. DX11은 읽을 때 일관되게 0을 반환할 수 있으며 문제없이 일부 쓰기를 읽을 수 있지만 지원이 적은 플랫폼은 GPU를 충돌시킬 수 있습니다. DX11 특정 해킹, 스레드 그룹 크기의 배수와 일치하지 않는 버퍼 크기, 버퍼의 시작 또는 끝에서 이웃하는 데이터 요소를 읽으려는 시도 및 유사한 비호환성을 주의해야 합니다.
리소스를 초기화해야 합니다. 새 버퍼 및 텍스처의 내용은 정의되지 않습니다. 일부 플랫폼은 모두 0을 제공하지만 다른 플랫폼에서는 NaN을 포함할 수 있습니다.
컴퓨트 셰이더가 선언한 모든 리소스를 바인딩해야 합니다. 셰이더가 분기로 인해 현재 상태의 리소스를 사용하지 않는다는 사실을 알고 있어도 리소스가 바인딩되어 있는지 확인해야 합니다.
Metal(iOS 및 tvOS 플랫폼용)은 텍스처의 원자 연산(atomic operation)을 지원하지 않습니다. 또한 Metal은 버퍼에서 GetDimensions
쿼리를 지원하지 않습니다. 필요한 경우 버퍼 크기 정보를 상수로 셰이더에 전달해야 합니다.
OpenGL ES 3.1(Android, iOS, tvOS 플랫폼용)은 한 번에 4개의 컴퓨트 버퍼만 지원합니다. 실제 구현은 보통 더 많은 것을 지원하지만 일반적으로 OpenGL ES용으로 개발하는 경우에는 각 데이터 항목을 자체 버퍼에 두는 대신 관련 데이터를 구조체로 그룹화하는 것을 고려해야 합니다.
일반적으로 컴퓨트 셰이더 파일은 HLSL로 작성되고 필요한 모든 플랫폼으로 자동 컴파일되거나 번역됩니다. 그러나 다른 언어로의 이동(즉, HLSL 플랫폼만 유지)을 방지하거나 GLSL 컴퓨트 코드를 수동으로 작성할 수 있습니다.
다음 정보는 크로스 플랫폼 빌드가 아닌 HLSL 전용 또는 GLSL 전용 컴퓨트 셰이더에만 적용됩니다. 이 정보로 인해 일부 플랫폼에서 컴퓨트 셰이더 소스가 제외될 수 있기 때문입니다.
CGPROGRAM
및 ENDCG
키워드로 둘러싸인 컴퓨트 셰이더 소스는 HLSL이 아닌 플랫폼에서 처리되지 않습니다.
GLSLPROGRAM
및 ENDGLSL
키워드로 둘러싸인 컴퓨트 셰이더 소스는 GLSL 소스로 취급되며 축약됩니다. 이는 OpenGL 또는 GLSL 플랫폼을 타겟으로 할 때만 적용됩니다. 자동으로 변환된 셰이더는 버퍼의 HLSL 데이터 레이아웃을 따르지만 수동으로 작성된 GLSL 셰이더는 GLSL 레이아웃 규칙을 따릅니다.
키워드를 사용하여 그래픽스 셰이더와 마찬가지로 컴퓨트 셰이더의 여러 배리언트를 생성할 수 있습니다.
배리언트에 대한 일반적인 정보는 셰이더 배리언트를 참조하십시오. 컴퓨트 셰이더에서 해당 기능을 구현하는 방법에 대한 자세한 내용은 HLSL에서 셰이더 키워드 선언 및 사용과 ComputeShader API 문서를 참조하십시오.