CPU Sorting Transparency
- DirectX 11의 Blend State를 이용해 Output Merge에 바인딩을 하여 Blending을 일반적인 Alpha Blending 할 경우를
생각해보면 가려지는 부분은 그릴 필요가 없기 때문에 Pixel에 그리기 전 깊이에 따른 정렬을 해주어야 한다.
Order Independent Transparency
- 오브젝트 단위로 투명도 렌더링을 할 경우 정확한 투명도의 선후관계를 처리하기 힘들다.
- 결국 정확한 선후관계를 판별하기엔 픽셀 단위로 해야하는데 위의 문제를 보안하기 위해 쉐이더 내부에서 처리하는
OIT 기술을 적용하게 되었다.
- 반투명 오브젝트는 렌더링 하기전 미리 분류한 후 다른 방식의 렌더링 방식으로 처리한다.
- 오브젝트를 해당 RenderTarget에 그리는 것이 아닌 RWStructBuffer와 RWByteAddressBuffer을 통해 저장해둔 후 마지막
불투명 오브젝트를 그린 RenderTarget과 Blending 하는 방식이다.
- 반투명 오브젝트 데이터
1) RWStructBuffer (Piece / Link Buffer )
: 화면 크기의 레이어와 정렬과 혼합을 위해 필요한 Color, Depth, Next Index에 대한 Data를 담을 구조적 버퍼를 이용하여
저장해 둡니다.
2) RWByteAddressBuffer ( First Node Offset Buffer )
: Link Buffer 대상 픽셀에 해당하는 정적 링커에 해당하는 첫 번째 노드 오프셋입니다.
struct FragmentData
{
uint Color;
float Depth;
};
struct FLStaticNode
{
FragmentData Data;
uint Next;
};
[earlydepthstencil]
void OIT_Particle_PS(VertexIn pIn)
{
...
uint pixelCount = gPieceLinkBuffer.IncrementCounter();
uint2 vPos = (uint2) pIn.PosH.xy;
uint startOffsetAddress = 4 * (gFrameWidth * vPos.y + vPos.x);
uint oldStartOffset;
gFirstOffsetBuffer.InterlockedExchange(
startOffsetAddress, pixelCount, oldStartOffset);
FLStaticNode node;
node.Data.Color = PackColorFromFloat4(texColor);
node.Data.Depth = pIn.PosH.z;
node.Next = oldStartOffset;
gPieceLinkBuffer[pixelCount] = node;
}
- 위의 Shader Code는 반투명 오브젝트를 해당 Link Buffer에 Color, Depth, Next Index Data를 삽입하는 과정이다.
- 이전에 불투명 오브젝트를 그린 DepthStencilView를 기반으로 Depth 체크를하여 Data를 삽입한다.
- 원래 Pixel Shader 이후에 깊이 테스트를 하지만 [earlydepthstencil] 속성을 사용함으로써 강제로 깊이 테스트를 먼저
실행하여 성능 오버헤드를 줄어들게 할 수 있다.
void SortPixelInPlace(int numPixels)
{
FragmentData temp;
for (int i = 1; i < numPixels; ++i)
{
for (int j = i - 1; j >= 0; --j)
{
if (gSortedPixels[j].Depth < gSortedPixels[j + 1].Depth)
{
temp = gSortedPixels[j];
gSortedPixels[j] = gSortedPixels[j + 1];
gSortedPixels[j + 1] = temp;
}
else
{
break;
}
}
}
}
float4 OIT_PS(float4 posH : SV_Position) : SV_Target
{
uint2 vPos = (uint2) posH.xy;
int startOffsetAddress = 4 * (gFrameWidth * vPos.y + vPos.x);
int numPixels = 0;
uint offset = gFirstOffsetBuffer.Load(startOffsetAddress);
FLStaticNode element;
while (offset != 0xFFFFFFFF)
{
element = gPieceLinkBuffer[offset];
gSortedPixels[numPixels++] = element.Data;
offset = (numPixels >= MAX_SORTED_PIXELS) ?
0xFFFFFFFF : element.Next;
}
SortPixelInPlace(numPixels);
float4 currColor = gBackGround.Load(int3(posH.xy, 0));
for (int i = 0; i < numPixels; ++i)
{
float4 pixelColor = UnpackColorFromUInt(gSortedPixels[i].Color);
currColor.xyz = lerp(currColor.xyz, pixelColor.xyz, pixelColor.w);
}
return currColor;
}
- 위의 Shader Code는 불투명 오브젝트를 그리고 반투명 오브젝트의 Layer Data를 쌓아둔 후 최종 혼합을 하는 과정이다.
- 미리 쌓아둔 Pixel별 Layer Data를 기반으로 Sorting과 Blending을 한번에 하여 최종 Pixel Color을 출력한다.
Order Independent Transparency 장점
1) Pixel별 Layer Data를 이용하여 정밀한 Blending이 가능하다.
2) 그리기전 오브젝트별 Sorting 작업을 할 필요가 없어진다.
Order Independent Transparency 단점
1) Pixel별 Layer Data는 GPU 메모리에 올라가기에 미리 정해두고 한정적으로 사용해야 한다.
2) 속도 측면에서 매 Pixel마다 Sorting이 요구되므로 속도면에서 차이가 있다.
- 위의 단점들을 보안할 방법은 추후 개선하도록 해야겠다.
적용 영상
'DirectX 11' 카테고리의 다른 글
[DirectX 11] PBR (Physically Based Rendering) (0) | 2022.01.21 |
---|---|
[DirectX 11] Deferred Rendering FXAA (0) | 2022.01.16 |
[DirectX 11] Particle System (0) | 2021.12.26 |
[DirectX 11] Terrain Mesh Blending (0) | 2021.12.20 |
[DirectX 11] Map / UnMap vs UpdataSubresource (0) | 2021.12.19 |