implements cascaded shadow maps with using texture array

23
Texture Array 를 를를를 Cascaded Shadow Maps 를를를 Microsoft Visual C++ MVP tw:@dgtman http://megayuchi.wordpress.com

Upload: yeong-cheon-you

Post on 20-Feb-2017

147 views

Category:

Technology


5 download

TRANSCRIPT

Page 1: Implements Cascaded Shadow Maps with using Texture Array

Texture Array 를 이용한 Cascaded Shadow Maps

유영천 Microsoft Visual C++ MVP

tw:@dgtmanhttp://megayuchi.wordpress.com

Page 2: Implements Cascaded Shadow Maps with using Texture Array

• 현 시점에서 가장 대중적으로 사용되고 있는 그림자 렌더링 기법• 구현하기 쉽다 .• Soft-shadow 처리도 쉽다 .

Shadow Maps

Page 3: Implements Cascaded Shadow Maps with using Texture Array

• 광원 ( 그림자를 드리울 ) 의 뷰공간에서 Shadow Caster 가 될 오브젝트들 ( 혹은 월드 전체 ) 을 렌더링 -> Depth Buffer(Texture) 를 구성

구현 – Pass 0 , Shadow Caster

Page 4: Implements Cascaded Shadow Maps with using Texture Array

구현 – Pass 1 , Shadow Receiver• 광원 ( 그림자를 드리운 ) 의 View- Space 로 변환 .• -1 ~ 1 사이의 좌표공간을 0 – 1 사이로 변환 .• 변환된 (0 – 1 사이 ) 좌표로 Depth Buffer 로부터 depth 값을 샘플링• Receiver 의 depth 값과 Depth Buffer 의 depth 값을 비교• receiver_z > depth_value -> 그림자가 드리워짐

Page 5: Implements Cascaded Shadow Maps with using Texture Array

Shadow Map in Shadow Space On Rendering in Camera Space

Shadow Map applied

① ②

Shader Resource View

Sampling z-value from Shadow Map

Compare z-value ① and ② per pixel.

Page 6: Implements Cascaded Shadow Maps with using Texture Array

• 한 장의 Texture 로 넓은 공간을 표현하기엔 해상도가 부족함 .• Texture 사이즈를 크게 ? -> 품질향상 , But 성능 하락 , GPU 메모리 낭비• PSM, TSM, LiPSM 등등 한 장의 Texture 만을 사용하면서 최대한 낭비 없이 사용하는 기법들 등장

그냥 쓰기엔 약간 문제가…

Page 7: Implements Cascaded Shadow Maps with using Texture Array

• Shadow Map 을 만들 때 한 장의 Texture 가 아닌 여러 장의 Texture에 나눠 그리자 .• 뷰프러스텀 영역을 여러 개의 공간으로 잘라서 여러 장의 Shadow

Map Texture 를 할당 .• 가까운 영역과 먼 영역에 따라 Shadow Map 정밀도 조절 가능 .• Shadow Map 해상도 증가에 따른 낭비가 적다 .

Cascaded Shadow Maps

Page 8: Implements Cascaded Shadow Maps with using Texture Array

eye

Shadow Light

Shadow Map Texture – Size(Width x N , Height)

⓪ ① ② ③

⓪ ① ② ③

⓪ ① ② ③

Page 9: Implements Cascaded Shadow Maps with using Texture Array

• Shadow Map 으로 사용할 Texture 준비 • N 개의 Cascaded 단계를 사용한다면 Texture 사이즈는 Width x N, Height• Width x N 인 이유는 한 장의 Texture 에 N 단계의 Shadow Map 을 담기 위함이다 .

• 루프를 돌며 0 ~ N-1 단계까지 Shadow Caster 를 렌더링 .• 뷰포트 설정을 바꿔가며 한 장의 Texture 에 모두 담는다 .

• Shadow Receiver 를 렌더링할때 픽셀이 어느 Cascaded 단계에 들어가는지 찾아서 tex 좌표의 u 성분 offset 조정• 이후는 일반적인 Shadow Map 과 똑같음 .

구현

Page 10: Implements Cascaded Shadow Maps with using Texture Array

• Cascaded 단계에 따라 Draw Call 회수가 늘어남 . CPU 자원 낭비 . • 코드 복잡해짐 .• 한방에 모든 Cascaded 단계를 처리할 수 없을까 ?

개선하고 싶은 점

Page 11: Implements Cascaded Shadow Maps with using Texture Array

• 말 그대로 Texture 배열• 배열이지만 단일 Texture 처럼 다룰 수 있다 .• SRV, RTV 로 사용 가능 .• CPU 측 코드에서 API 사용 방법은 일반 Texture 와 똑같다 .

• Texture 로부터 샘플링시 좌표의 x,y,z 성분중 z 성분을 배열의 인덱스로 사용

Texture Array

Page 12: Implements Cascaded Shadow Maps with using Texture Array

Texture2DArray texDiffuseArray: register(t0);SamplerState samplerDiffuse: register(s0);

float4 psArrayDiffuse(PS_INPUT input) : SV_Target{

float3 texCoord = float3(input.TexCoord.xy,TexArrayIndex);float4 texColor = texDiffuseArray.Sample(samplerDiffuse, texCoord);

float4 outColor = texColor;

return outColor;}

Using Texture Array as SRV

Page 13: Implements Cascaded Shadow Maps with using Texture Array

Using Texture Array as RTV

struct PS_OUT_TEX_ARRAY{ float4 Pos : SV_POSITION; uint RTIndex : SV_RenderTargetArrayIndex;};

[maxvertexcount(3)]void gsDefault ( triangle GS_INPUT input[3], inout TriangleStream<PS_OUT_TEX_ARRAY> TriStream ){

PS_OUT_TEX_ARRAY output;for (uint i=0; i<3; i++){

output.Pos = mul(input[i].PosWorld,matViewProjList[i]);output.RTIndex = N;TriStream.Append(output[j]);

}TriStream.RestartStrip();

}

Page 14: Implements Cascaded Shadow Maps with using Texture Array

• N 개의 Cascaded 단계가 있을 때 사이즈 Width , Height 에 배열이 N개인 Texture 생성• 일반 Texture 와 마찬가지로 RTV 와 SRV 생성• Shader 안에서 어느 Cascaded 단계에 포함되는지 계산하고 그 인덱스 값을 텍스쳐 좌표의 z 성분으로 사용

Texture Arrary 를 Shadow Maps 에 적용

Page 15: Implements Cascaded Shadow Maps with using Texture Array

UINT Width = DEFAULT_SHADOW_MAP_WIDTH;UINT Height = DEFAULT_SHADOW_MAP_HEIGHT;UINT ArrayCount = MAX_CASCADE_NUM;D3D11_TEXTURE2D_DESC texDesc = {

Width, Height, 1, ArrayCount, DXGI_FORMAT_R32_TYPELESS, 1, 0, D3D11_USAGE_DEFAULT, D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE, 0, 0

};D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = { DXGI_FORMAT_D32_FLOAT, D3D11_DSV_DIMENSION_TEXTURE2DARRAY, 0 };dsvDesc.Texture2DArray.FirstArraySlice = 0;dsvDesc.Texture2DArray.ArraySize = ArrayCount;dsvDesc.Texture2DArray.MipSlice = 0;

D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = { DXGI_FORMAT_R32_FLOAT, D3D11_SRV_DIMENSION_TEXTURE2DARRAY, 0, 0 };srvDesc.Texture2DArray.FirstArraySlice = 0;srvDesc.Texture2DArray.ArraySize = ArrayCount;srvDesc.Texture2DArray.MipLevels = 1;srvDesc.Texture2DArray.MostDetailedMip = 0;

ID3D11Texture2D* pTex = nullptr;

HRESULT hr = m_pD3DDevice->CreateTexture2D(&texDesc, NULL, &pTex);if (FAILED(hr))

__debugbreak(); hr = m_pD3DDevice->CreateDepthStencilView(pTex, &dsvDesc, &m_pShadowMapDSV);if (FAILED(hr))

__debugbreak(); hr = m_pD3DDevice->CreateShaderResourceView(pTex, &srvDesc, &m_pShadowMapSRV);if (FAILED(hr))

__debugbreak();

pTex->Release();

Creating SRV,DSV from Texture Array

Page 16: Implements Cascaded Shadow Maps with using Texture Array

Texture Texture Array

// set matrix for shadow-space,SetCascadedLightSpaceAll(N);

// Draw shadow casters to Depth BufferDrawShadowCasters();

for (DWORD i=0; i<N; i++){

// set matrix for shadow-space,SetCascadedLightSpace(i);

// Draw shadow casters to Depth BufferDrawShadowCasters();

}

CPU Code – Shadow Caster 렌더링 비교

Page 17: Implements Cascaded Shadow Maps with using Texture Array

cbuffer ConstantBufferShadowMap : register( b0 ){

matrix matWorld;matrix matViewList[MAX_CASCADE_NUM];matrix matProjList[MAX_CASCADE_NUM];

}

struct PS_OUT_TEX_ARRAY{

float4 Pos : SV_POSITION;uint RTIndex : SV_RenderTargetArrayIndex;

};

struct GS_INPUT{

float4 PosWorld: POSITION;};

Shader Code – Pass 0 , Shadow Caster

Page 18: Implements Cascaded Shadow Maps with using Texture Array

float4 vsShadowCaster( VS_INPUT_VL input ) : POSITION{ float4 PosWorld = mul( input.Pos, matWorld ); return PosWorld;}

[maxvertexcount(3*MAX_CASCADE_NUM)]void gsShadowCaster( triangle GS_INPUT input[3], inout TriangleStream<PS_OUT_TEX_ARRAY> TriStream ){ PS_OUT_TEX_ARRAY output[3]; for (uint i=0; i<MAX_CASCADE_NUM; i++ ) {

for (uint j=0; j<3; j++) { float4 PosView = mul(input[j].PosWorld,matViewList[i]); PosView.z += 2.5f; // bias value output[j].Pos = mul(PosView,matProjList[i]); output[j].RTIndex = i; TriStream.Append(output[j]); } TriStream.RestartStrip();

}}

Shader Code – Pass 0 , Shadow Caster

Page 19: Implements Cascaded Shadow Maps with using Texture Array

cbuffer ConstantBufferGBufferShader : register (b0){ matrix ViewInv; matrix matShadowViewProjCascade[MAX_CASCADE_NUM]; CASCADE_CONSTNAT CascadeConst[MAX_CASCADE_NUM];};

Texture2DArray texShadowMap: register(t2);SamplerComparisonState samplerComp : register(s2);

void CalcIndex(out float OutIndex, in float Dist){ uint index = MAX_CASCADE_NUM - 1; for (uint i = 0; i < MAX_CASCADE_NUM; i++) { if (Dist <= CascadeConst[i].Dist) { index = i; break; } } OutIndex = index;}

Shader Code – Pass 1 , Shadow Receiver

Page 20: Implements Cascaded Shadow Maps with using Texture Array

float3 CalcShadowColor3x3(Texture2DArray texShadowMap, SamplerComparisonState samplerComp, float4 PosWorld, float Dist){ float3 shadowColor = float3(1, 1, 1); uint index; CalcIndex(index, Dist);

float4 PosShadowSpace = mul(PosWorld, matShadowViewProjCascade[index]); float4 texCoord = PosShadowSpace / PosShadowSpace.w; float cmp_z = texCoord.z;

float litSum = 0; int2 offset[9] = {-1,-1, 0,-1, 1,-1, -1,0, 0,0, 1,0, -1,1, 0,1, 1,1 };

for (int i = 0; i < 9; i++) { litSum += texShadowMap.SampleCmpLevelZero(samplerComp, float3(texCoord.xy,index), cmp_z, offset[i]); } float shadowValue = litSum / 9.0f; shadowColor = lerp(float3(0,0,0), float3(1, 1, 1), shadowValue); return shadowColor;}

Shader Code – Pass 1 , Shadow Receiver

Page 21: Implements Cascaded Shadow Maps with using Texture Array

• Draw Call 을 대폭 줄일 수 있다 . CPU 측 병목을 줄임• 코드가 보다 간결해짐 .

Texture Array 사용의 장점

Page 22: Implements Cascaded Shadow Maps with using Texture Array

• 각각의 Light View Space 프러스텀에 대한 culling• 프러스텀에 대한 culling 을 먼저 수행한 후 Constant Buffer 를 통해 bit flags로 전달 .• Geometry Shader 에서 0,1,2,3… 각 비트를 체크하며 0 – N 까지의 Cascaded단계에 포함되는지를 검사 . 비트가 0 이면 그대로 폐기 .• GPU 상에서 클리핑이 이루어지므로 CPU 측에서 별도의 Culling 작업에 필요한 시간을 감안하면 굳이 필요가 없을지도 ????

추가적인 최적화