[shaderx6] 3.7 Robust Order-Independent Transparency via Reverse Depth Peeling in DirectX 10

Post on 27-Jun-2015

1.978 views 5 download

Tags:

Transcript of [shaderx6] 3.7 Robust Order-Independent Transparency via Reverse Depth Peeling in DirectX 10

3.7 Robust Order-Independent Transparency via Reverse Depth Peeling in DirectX 10

ohyecloudy http://ohyecloudy.com

shader studyhttp://cafe.naver.com/shader.cafe

2010.06.21

ShaderX6

Introduction

Depth Peeling

Reverse Depth Peeling

Overview

Algorithm

Emulating Second Depth Buffer

Optimal # of Layers

Optimizations

Conclusion

Order-Independent Transparency

반투명 지오메트리를 정렬 없이 편하게 그리자

왜 고생하고 있나?

z-buffer는 fragment마다

entry 하나만 가지도록 설계됐음.

back-to-front order

전통적인 방식 카메라 공간에서 먼 지오메트리부터 가까운 지오메트리 순서로 정렬한다. 정렬하는 비용

공짜는 없다.

보통 CPU에서 bitonic 정렬같은 방법으로 GPU에서 할 수도 있음

back-to-front order 문제점

정렬이 per-object나 per-polygon 단위

per-pixel이 아니라서 visual artfact 존재

정렬한 순서대로 렌더링을 하기 때문에

모아 찍기가 불가능

shader switching이 많다.

per-object sorting

reverse depth peeling

Introduction

Depth Peeling

Reverse Depth Peeling

Overview

Algorithm

Emulating Second Depth Buffer

Optimal # of Layers

Optimizations

Conclusion

깊이depth를 귤 껍질 까듯이 하나하나 벗겨peeling

layer에 그린다.

from google 사전

Layer Layer Layer Layer Layer Layer

반투명 폴리곤 반투명 폴리곤 반투명 폴리곤 반투명 폴리곤 반투명 폴리곤

정렬 안 하고 렌더링

Render Target

back-to-front order blend

사용하는 layer 수 만큼 layer 추출

per-pixel 반투명 평가 가능

visual artifact X

layer가 deferred shading에 있는

G-buffer와 닮았다.

layer는 video memory에 저장

몇 개야! 도대체

압박

Introduction

Depth Peeling

Reverse Depth Peeling

Overview

Algorithm

Emulating Second Depth Buffer

Optimal # of Layers

Optimizations

Conclusion

depth peeling 메모리 사용량을 줄이자

layer 하나만 사용 하나를 계속 업데이트해서 쓴다는 얘기.

layer가 하나란 개념이 아니다.

layer 추출하는 순서를 바꿨다.

depth peeling front-to-back order로 layer를 추출

reverse depth peeling back-to-front order로 layer를 추출

반투명 폴리곤 반투명 폴리곤 반투명 폴리곤 반투명 폴리곤 반투명 폴리곤

정렬 안 하고 렌더링

Layer Render Target

blend

layer 추출

사용하는 layer 수 만큼

layer = 1 (furthermost)

Render Target

layer = 2

Render Target

layer = 3

Render Target

layer = 4 (frontmost)

Render Target

Introduction

Depth Peeling

Reverse Depth Peeling Overview

Algorithm

Emulating Second Depth Buffer

Optimal # of Layers

Optimizations

Conclusion

for (nLayer=0; nLayer<nRequiredLayers; ++nLayer)

{

BindDepthBuffer(0, pDepthBuffer[0], EnableWrites, GREATER);

Clear(pDepthBuffer[0], 0.0);

BindDepthBuffer(1, pDepthBuffer[1], DisableWrites, LESS);

SetRenderTarget(pCurrentTransparentLayer);

SetBlendMode(ONE, ZERO);

DrawTransparentGeometry();

SetTexture(pCurrentTransparentLayer);

SetRenderTarget(pMainRenderTarget);

SetBlendMode(SRCALPHA, INVSRCALPHA);

DrawFullscreenQuad();

SWAP(pDepthBuffer[0], pDepthBuffer[1]);

}

for (nLayer=0; nLayer<nRequiredLayers; ++nLayer)

{

BindDepthBuffer(0, pDepthBuffer[0], EnableWrites, GREATER);

Clear(pDepthBuffer[0], 0.0);

BindDepthBuffer(1, pDepthBuffer[1], DisableWrites, LESS);

SetRenderTarget(pCurrentTransparentLayer);

SetBlendMode(ONE, ZERO);

DrawTransparentGeometry();

SetTexture(pCurrentTransparentLayer);

SetRenderTarget(pMainRenderTarget);

SetBlendMode(SRCALPHA, INVSRCALPHA);

DrawFullscreenQuad();

SWAP(pDepthBuffer[0], pDepthBuffer[1]);

}

가장 멀리 있는 반투명 fragment를 판단하기 위한 depth buffer Z 값을 write. GREATER 비교 GREATER로 비교하기 때문에 0.0으로 전체를 지운다.

for (nLayer=0; nLayer<nRequiredLayers; ++nLayer)

{

BindDepthBuffer(0, pDepthBuffer[0], EnableWrites, GREATER);

Clear(pDepthBuffer[0], 0.0);

BindDepthBuffer(1, pDepthBuffer[1], DisableWrites, LESS);

SetRenderTarget(pCurrentTransparentLayer);

SetBlendMode(ONE, ZERO);

DrawTransparentGeometry();

SetTexture(pCurrentTransparentLayer);

SetRenderTarget(pMainRenderTarget);

SetBlendMode(SRCALPHA, INVSRCALPHA);

DrawFullscreenQuad();

SWAP(pDepthBuffer[0], pDepthBuffer[1]);

}

이전 layer에서 벗겨낸 지오메트리를 또 다시 안 벗겨내기 위해서 back – to – front 순서로 벗겨내고 있는 것을 명심 LESS 비교 제외시키기 위한 용도이므로 z값을 write하지 않는다.

이번에 기록한 가장 먼 depth를 다음 루프에서 LESS 비교 값으로 사용하기 위해

for (nLayer=0; nLayer<nRequiredLayers; ++nLayer)

{

BindDepthBuffer(0, pDepthBuffer[0], EnableWrites, GREATER);

Clear(pDepthBuffer[0], 0.0);

BindDepthBuffer(1, pDepthBuffer[1], DisableWrites, LESS);

SetRenderTarget(pCurrentTransparentLayer);

SetBlendMode(ONE, ZERO);

DrawTransparentGeometry();

SetTexture(pCurrentTransparentLayer);

SetRenderTarget(pMainRenderTarget);

SetBlendMode(SRCALPHA, INVSRCALPHA);

DrawFullscreenQuad();

SWAP(pDepthBuffer[0], pDepthBuffer[1]);

}

Layer에 반투명 지오메트리를 렌더링한다. 렌더 타겟에 blend 하기 위한 임시 렌더링

for (nLayer=0; nLayer<nRequiredLayers; ++nLayer)

{

BindDepthBuffer(0, pDepthBuffer[0], EnableWrites, GREATER);

Clear(pDepthBuffer[0], 0.0);

BindDepthBuffer(1, pDepthBuffer[1], DisableWrites, LESS);

SetRenderTarget(pCurrentTransparentLayer);

SetBlendMode(ONE, ZERO);

DrawTransparentGeometry();

SetTexture(pCurrentTransparentLayer);

SetRenderTarget(pMainRenderTarget);

SetBlendMode(SRCALPHA, INVSRCALPHA);

DrawFullscreenQuad();

SWAP(pDepthBuffer[0], pDepthBuffer[1]);

}

메인 렌더 타겟에 blend한다.

Introduction

Depth Peeling

Reverse Depth Peeling Overview

Algorithm

Emulating Second Depth Buffer

Optimal # of Layers

Optimizations

Conclusion

for (nLayer=0; nLayer<nRequiredLayers; ++nLayer)

{

BindDepthBuffer(0, pDepthBuffer[0], EnableWrites, GREATER);

Clear(pDepthBuffer[0], 0.0);

BindDepthBuffer(1, pDepthBuffer[1], DisableWrites, LESS);

...

}

잠깐! DepthBuffer 0,1번 인덱스에 바인딩? 이런 게 있나?

있으면 좋겠지만 그런 거 없다

단지 Pseudo-code일뿐

두 번째 테스트

depth 값을 비교해서 버림

쓰는 작업이 없기 때문에 구현이 간단

struct PS_INPUT

{

float4 vPosition : SV_POSITION;

float2 vTex : TEXCOORD0;

};

Texture2D txInputDepth;

float4 PSRenderObjects(PS_INPUT intput) : SV_TARGET

{

// Fetch depth value from 2nd depth buffer

float fDepth =

txInputDepth.Load(int3(input.vPosition.xy, 0));

// Discard fragment if LESS depth test failes

float f = (fDepth <= input.vPosition.z);

flip(-f);

// calculate color and alpha etc

...

}

Introduction

Depth Peeling

Reverse Depth Peeling Overview

Algorithm

Emulating Second Depth Buffer

Optimal # of Layers

Optimizations

Conclusion

Layer를 몇 개 쓰면 될까?

간단한 답 depth complexity로 layer 개수를 정한다.

DirectX9::GetDepthComplexity() 현재 장면 깊이 복잡도를 구하는 함수

이런 게 있으면 얼마나 좋을까?

있을 리가 없다.

Layer 개수를 정해서 사용 어느 정도 visual error 감수

좀 더 나은 방법이 없을까?

Occlusion Queries

pixel이 depth test를 통과했는지 못했는지

알 수 있다.

ID3D10Query::Begin() ~ ID3D10Query::End()

ID3D10Query::GetData()

• depth 테스트를 통과한 pixel 개수를 알 수 있다.

Dynamic하게 layer 개수를 조정할 수 있겠다.

Occlusion Queries

픽셀이 안 남을 때까지 peeling

원칙적으로는 맞다

성능을 높이려면 threshold를 둬서 그만 둠

데모에선 threshold 값으로 0.01% 사용

Introduction

Depth Peeling

Reverse Depth Peeling Overview

Algorithm

Emulating Second Depth Buffer

Optimal # of Layers

Optimizations

Conclusion

Transform

반투명 지오메트리를 layer마다

stream-out

Direct3D 10

트랜스폼된 지오메트리를 버퍼에 저장

다시 사용할 수 있다

결국 트랜스폼은 한 번만 해서 여러번 사용

Fill-Rate

dynamic branch를 사용

float fDepth = txInputDepth.Load(int3(input.vPosition.xy, 0));

if (input.vPosition.z < fDepth)

{

// Depth test passes

// calculate color and alpha etc..

}

else

{

// Emulated depth test fails. kill fragment

discard;

}

Introduction

Depth Peeling

Reverse Depth Peeling

Overview

Algorithm

Emulating Second Depth Buffer

Optimal # of Layers

Optimizations

Conclusion

depth peeling, reverse depth peeling 개념 정리

DirectX 10은 되야지 쓸만할 것 같다.

직접 써봐야지 평가할 수 있을 것 같음

아직까짂 가장 현실적인 해결책은

전통적인 방법으로 sorting

품질을 좀 양보하면 Alpha to coverage