안녕하세요.
정글러 입니다.
Compute Shader에 대해서 알아보겠습니다.

Computer Shader는 vertex와 상관없이 GPU에서 별도로 사용할 수 있습니다.
픽셀 쉐이더는 어떤 픽셀의 색깔값을 선택할 수 없지만, computer shader는 필요한 부분의 색깔과 포지션 값의 수정이 가능합니다.
- 픽셀 쉐이더는 vertex가 갖고 있는 texture좌표를 pixel 단위로 interpolation해 pixel shader에 넣어주는 sampling
- computer shader는 필요한 대로 sampling을 할 수 있음
GPU Render Pipeline
m_context->CSSetConstBuffers(0, 1, m_constsGPU.GetAddressOf());
m_context->SetUnorderedAccessViews(0, 1, m_backUAV.GetAddressOf(), NULL);
Dispatch(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ)
// 픽셀의 구역을 ThreadGroup으로 나눔
ComputeShader 기본
RWTexture2D<float4> gOutput : register(u0) // 읽기와 쓰기가 가능한 텍스쳐2D
cbuffer MyBuffer : register(b0)
{ float3 position;
float scale;
float4 color;
}
[numthreads(256, 1, 1)]란?
하나의 스레드 그룹 안에서 실행되는 스레드의 갯수
Maximum Threads (X*Y*Z) = 1024

void main(uint3 gID : SV_GroupID, uint3 tID : SV_DispatchThreadID)
// 이때 tID는 픽셀의 좌표, 픽셀의 인덱스라고 볼 수 있습니다.
// 여기서 gOutput는 읽고 쓸 수 있기 때문에 픽셀을 바꿀 수 있습니다.
Warp
GPU는 이렇게 블럭 단위로 일을 하기 때문에 warp를 할 수 있습니다.
Warp는 동시에 일을 하는 스레드의 묶음 입니다. (32 parallel threads)

Block단위로 스레드를 제어할 수 있습니다. 하지만 다른 블럭과는 동기화시킬 수 없습니다.
모든 블럭들이 다 끝날 때까지 기다릴 수는 있습니다.
// 컴퓨터 쉐이더가 하던 일을 끝내게 만들고 Resources를 해제한다.
AppBase::ComputeShaderBarrier();
Structured Buffer
texture memory- pixel의 2차원 메모리이다.
structured buffer는? 1차원 배열처럼 사용할 수 있다.
예를들어 position과 color가 있는 particle template 구조체의 배열로 사용할 수 있다.
CPP
[데이터 멤버]
vector<T_ELEMENT> m_cpu; // gpu로 보낼 데이터
ComPtr<ID3D11Buffer> m_gpu;
ComPtr<ID3D11Buffer> m_staging;
ComPtr<ID3D11ShaderResourceView> m_srv;
ComPtr<ID3D11UnorderedAccessView> m_uav;
Initialize (device, UINT(m_cpu.size()), sizeof(T_ELEMENT), m_cpu.data(), m_gpu, m_srv, m_uav);
데이터 초기화
랜덤 넘버 지정
vertex shader
pixel shader
compute shader
update
// 입자들의 위치를 바꿔주는 작업
render
m_context->CSSetConstBuffers(0, 1, m_constsGPU.GetAddressOf());
m_context->SetUnorderedAccessViews(0, 1, m_backUAV.GetAddressOf(), NULL);
Dispatch(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ)
AppBase::ComputeShaderBarrier();
computeshader.hlsl
RWStructureBuffer<particle> outputParticles : register(u0)
[numthreads(256, 1, 1)]
void main(int3 gID : SV_GroupID, int3 gtID : SV_GroupThreadID, uint3 dtID : SV_DispatchThreadID)
//여기서 애니메이션 효과 추가!
Particle p = outputParticles[dtID.x]; //Read
float3 velocity = ...;
p.pos += velocity * dt;
outputParticles[dtID.x].pos = p.pos //Write
속도를 어떻게 계산하는가에 따라 다양한 애니메이션을 만들 수 있습니다.
나중에 언리얼엔진의 나이아가라에서 흐름을 제대로 이해하기 위해서
제가 이해할 수 있는 흐름정도로만 정리가 된 것 같네요;;
compute shader를 통해 정말 다양한 애니메이션을 만들 수 있을 것 같아서 흥미롭습니다.
감사합니다.
'XR > Graphics' 카테고리의 다른 글
[Graphics] RenderDoc 읽기 (0) | 2025.04.24 |
---|---|
[Graphics] Stable Fluids (Navier-Stokes equation) 알아보기 (1) | 2025.04.24 |
[Graphics] Barycentric Coordinate System 알아보기 (0) | 2025.03.10 |
[Graphics] Rasterization과 Ray tracing의 차이 (0) | 2025.02.21 |
[Graphics] Phong Reflection Model(Ambient / Diffuse / Specular) 이해하기 (0) | 2025.02.04 |