12
Most read
15
Most read
18
Most read
Texture Array를 이용한 Cascaded
Shadow Maps
유영천
Microsoft Visual C++ MVP
tw:@dgtman
http://megayuchi.wordpress.com
• 현 시점에서 가장 대중적으로 사용되고 있는 그림자 렌더링 기법
• 구현하기 쉽다.
• Soft-shadow처리도 쉽다.
Shadow Maps
• 광원(그림자를 드리울)의 뷰공간에서 Shadow Caster가 될
오브젝트들(혹은 월드 전체)을 렌더링 -> Depth Buffer(Texture)를
구성
구현 – Pass 0 , Shadow Caster
구현 – Pass 1 , Shadow Receiver
• 광원(그림자를 드리운)의 View- Space로 변환.
• -1 ~ 1사이의 좌표공간을 0 – 1사이로 변환.
• 변환된 (0 – 1사이) 좌표로 Depth Buffer로부터 depth값을 샘플링
• Receiver의 depth값과 Depth Buffer의 depth값을 비교
• receiver_z > depth_value -> 그림자가 드리워짐
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.
• 한 장의 Texture로 넓은 공간을 표현하기엔 해상도가 부족함.
• Texture 사이즈를 크게? -> 품질향상, But 성능 하락, GPU메모리
낭비
• PSM, TSM, LiPSM 등등 한 장의 Texture만을 사용하면서 최대한
낭비 없이 사용하는 기법들 등장
그냥 쓰기엔 약간 문제가…
• Shadow Map을 만들 때 한 장의 Texture가 아닌 여러 장의 Texture에
나눠 그리자.
• 뷰프러스텀 영역을 여러 개의 공간으로 잘라서 여러 장의 Shadow
Map Texture를 할당.
• 가까운 영역과 먼 영역에 따라 Shadow Map 정밀도 조절 가능.
• Shadow Map 해상도 증가에 따른 낭비가 적다.
Cascaded Shadow Maps
eye
Shadow Light
Shadow Map Texture – Size(Width x N , Height)
⓪ ① ② ③
⓪ ① ② ③
⓪ ① ② ③
• 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과 똑같음.
구현
• Cascaded단계에 따라 Draw Call회수가 늘어남. CPU 자원 낭비.
• 코드 복잡해짐.
• 한방에 모든 Cascaded 단계를 처리할 수 없을까?
개선하고 싶은 점
• 말 그대로 Texture배열
• 배열이지만 단일 Texture처럼 다룰 수 있다.
• SRV, RTV로 사용 가능.
• CPU측 코드에서 API사용 방법은 일반 Texture와 똑같다.
• Texture로부터 샘플링시 좌표의 x,y,z성분중 z성분을 배열의
인덱스로 사용
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
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();
}
• N개의 Cascaded단계가 있을 때 사이즈 Width , Height에 배열이
N개인 Texture 생성
• 일반 Texture와 마찬가지로 RTV와 SRV생성
• Shader안에서 어느 Cascaded 단계에 포함되는지 계산하고 그
인덱스 값을 텍스쳐 좌표의 z성분으로 사용
Texture Arrary를 Shadow Maps에 적용
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
Texture Texture Array
// set matrix for shadow-space,
SetCascadedLightSpaceAll(N);
// Draw shadow casters to Depth Buffer
DrawShadowCasters();
for (DWORD i=0; i<N; i++)
{
// set matrix for shadow-space,
SetCascadedLightSpace(i);
// Draw shadow casters to Depth Buffer
DrawShadowCasters();
}
CPU Code – Shadow Caster 렌더링 비교
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
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
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
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
• Draw Call을 대폭 줄일 수 있다. CPU측 병목을 줄임
• 코드가 보다 간결해짐.
Texture Array사용의 장점
• 각각의 Light View Space 프러스텀에 대한 culling
• 프러스텀에 대한 culling을 먼저 수행한 후 Constant Buffer를 통해 bit
flags로 전달.
• Geometry Shader에서 0,1,2,3… 각 비트를 체크하며 0 – N까지의
Cascaded단계에 포함되는지를 검사. 비트가 0이면 그대로 폐기.
• GPU상에서 클리핑이 이루어지므로 CPU측에서 별도의 Culling작업에
필요한 시간을 감안하면 굳이 필요가 없을지도????
추가적인 최적화
Reference
• https://msdn.microsoft.com/en-
us/library/windows/desktop/ee416307(v=vs.85).aspx
• http://developer.download.nvidia.com/SDK/10.5/opengl/src/cascade
d_shadow_maps/doc/cascaded_shadow_maps.pdf

More Related Content

PPTX
Hierachical z Map Occlusion Culling
PDF
멀티스레드 렌더링 (Multithreaded rendering)
PDF
쉐도우맵을 압축하여 대규모씬에 라이팅을 적용해보자
PDF
Cascade Shadow Mapping
PPTX
TA가 뭐예요? (What is a Technical Artist? 블루홀스튜디오)
PPTX
Screen space reflection
PDF
[Kgc2012] deferred forward 이창희
PDF
Ndc11 이창희_hdr
Hierachical z Map Occlusion Culling
멀티스레드 렌더링 (Multithreaded rendering)
쉐도우맵을 압축하여 대규모씬에 라이팅을 적용해보자
Cascade Shadow Mapping
TA가 뭐예요? (What is a Technical Artist? 블루홀스튜디오)
Screen space reflection
[Kgc2012] deferred forward 이창희
Ndc11 이창희_hdr

What's hot (20)

PPTX
[0903 구경원] recast 네비메쉬
PDF
스크린 스페이스 데칼에 대해 자세히 알아보자(워햄머 40,000: 스페이스 마린)
PDF
NDC2016 프로젝트 A1의 AAA급 캐릭터 렌더링 기술
PPTX
[KGC2014] DX9에서DX11로의이행경험공유
PPT
Shadow mapping 정리
PPTX
Compute shader DX11
PDF
빠른 렌더링을 위한 오브젝트 제외 기술
PDF
김혁, <드래곤 하운드>의 PBR과 레이트레이싱 렌더링 기법, NDC2019
PDF
Brdf기반 사전정의 스킨 셰이더
PDF
2018.12.22 깊이 버퍼 그림자 매핑
PDF
Ndc2010 전형규 마비노기2 캐릭터 렌더링 기술
PPTX
Ue4 에서의 환경변화 구현
PDF
나만의 엔진 개발하기
PDF
레퍼런스만 알면 언리얼 엔진이 제대로 보인다
PDF
Compute shader
PPTX
[NDC 2014] 던전앤파이터 클라이언트 로딩 최적화
PPTX
포인트 셰도우
PPTX
게임프로젝트에 적용하는 GPGPU
PPTX
High dynamic range
PPTX
Tips and experience of DX12 Engine development .
[0903 구경원] recast 네비메쉬
스크린 스페이스 데칼에 대해 자세히 알아보자(워햄머 40,000: 스페이스 마린)
NDC2016 프로젝트 A1의 AAA급 캐릭터 렌더링 기술
[KGC2014] DX9에서DX11로의이행경험공유
Shadow mapping 정리
Compute shader DX11
빠른 렌더링을 위한 오브젝트 제외 기술
김혁, <드래곤 하운드>의 PBR과 레이트레이싱 렌더링 기법, NDC2019
Brdf기반 사전정의 스킨 셰이더
2018.12.22 깊이 버퍼 그림자 매핑
Ndc2010 전형규 마비노기2 캐릭터 렌더링 기술
Ue4 에서의 환경변화 구현
나만의 엔진 개발하기
레퍼런스만 알면 언리얼 엔진이 제대로 보인다
Compute shader
[NDC 2014] 던전앤파이터 클라이언트 로딩 최적화
포인트 셰도우
게임프로젝트에 적용하는 GPGPU
High dynamic range
Tips and experience of DX12 Engine development .
Ad

Viewers also liked (11)

PPTX
프로그래밍 언어의 F1머신 C++을 타고 Windows 10 UWP 앱 개발의 세계로~
PPTX
[0122 구경원]게임에서의 충돌처리
PPTX
Porting direct x 11 desktop game to uwp app
PPTX
GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리
PPTX
10_Raytracing Introduction
PPTX
Hierarchical z buffer occlusion culling
PPTX
DirectX + C++을 이용한 WindowsStore App과 Windows Phone용 게임 개발
PDF
[0602 박민근] Direct2D
PDF
[스마트스터디] 재택근무 잘 하고 있어요
PDF
[NDC12] 게임 물리 엔진의 내부 동작 원리 이해
PDF
스타트업에서 기술책임자로 살아가기
프로그래밍 언어의 F1머신 C++을 타고 Windows 10 UWP 앱 개발의 세계로~
[0122 구경원]게임에서의 충돌처리
Porting direct x 11 desktop game to uwp app
GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리
10_Raytracing Introduction
Hierarchical z buffer occlusion culling
DirectX + C++을 이용한 WindowsStore App과 Windows Phone용 게임 개발
[0602 박민근] Direct2D
[스마트스터디] 재택근무 잘 하고 있어요
[NDC12] 게임 물리 엔진의 내부 동작 원리 이해
스타트업에서 기술책임자로 살아가기
Ad

Similar to Implements Cascaded Shadow Maps with using Texture Array (20)

PDF
NDC11_슈퍼클래스
PPTX
[14.10.21] Far Cry and DX9 번역(shaderstudy)
PDF
[ShaderX5] 4.4 Edge Masking and Per-Texel Depth Extent Propagation For Comput...
PPTX
[0312 조진현] good bye dx9
PPTX
Bs webgl소모임002
PDF
Unity Surface Shader for Artist 01
PPT
NDC11_김성익_슈퍼클래스
PDF
Reflective Shadow Maps
PDF
스위프트 성능 이해하기
PDF
자료구조(data structure)_NOTE 11. 그래프2.pdf
PDF
D2 Rain (1/2)
PDF
Modern gpu optimize blog
PDF
Modern gpu optimize
PPTX
Light in screen_space(Light Pre Pass)
PDF
NDC12_Lockless게임서버설계와구현
PPTX
5-1. html5 graphics
PPT
3ds maxscript 튜토리얼_20151206_서진택
PDF
Javascript 조금 더 잘 알기
PPTX
D2 Rain (2/2)
PDF
Voxel based game_optimazation_relelase
NDC11_슈퍼클래스
[14.10.21] Far Cry and DX9 번역(shaderstudy)
[ShaderX5] 4.4 Edge Masking and Per-Texel Depth Extent Propagation For Comput...
[0312 조진현] good bye dx9
Bs webgl소모임002
Unity Surface Shader for Artist 01
NDC11_김성익_슈퍼클래스
Reflective Shadow Maps
스위프트 성능 이해하기
자료구조(data structure)_NOTE 11. 그래프2.pdf
D2 Rain (1/2)
Modern gpu optimize blog
Modern gpu optimize
Light in screen_space(Light Pre Pass)
NDC12_Lockless게임서버설계와구현
5-1. html5 graphics
3ds maxscript 튜토리얼_20151206_서진택
Javascript 조금 더 잘 알기
D2 Rain (2/2)
Voxel based game_optimazation_relelase

More from YEONG-CHEON YOU (18)

PDF
DirectStroage프로그래밍소개
PDF
CUDA Raytracing을 이용한 Voxel오브젝트 가시성 테스트
PDF
Visual Studio를 이용한 어셈블리어 학습 part 2
PDF
Visual Studio를 이용한 어셈블리어 학습 part 1
PDF
XDK없이 XBOX게임 개발하기(UWP on XBOX)
PDF
Introduction to DirectX 12 Programming , Ver 1.5
PDF
MMOG Server-Side 충돌 및 이동처리 설계와 구현
PDF
실시간 게임 서버 최적화 전략
PDF
Voxelizaition with GPU
PDF
Sw occlusion culling
PPTX
CUDA를 게임 프로젝트에 적용하기
PPTX
서버와 클라이언트 같은 엔진 사용하기
PPT
프레임레이트 향상을 위한 공간분할 및 오브젝트 컬링 기법
PPTX
win32 app에서 UWP API호출하기
PPTX
Azure로 MMO게임 서비스하기
PPTX
Development AR App with C++ and Windows Holographic API
PDF
빌드관리 및 디버깅 (2010년 자료)
PPTX
Tips and experience_of_dx12_engine_development._ver_1.2
DirectStroage프로그래밍소개
CUDA Raytracing을 이용한 Voxel오브젝트 가시성 테스트
Visual Studio를 이용한 어셈블리어 학습 part 2
Visual Studio를 이용한 어셈블리어 학습 part 1
XDK없이 XBOX게임 개발하기(UWP on XBOX)
Introduction to DirectX 12 Programming , Ver 1.5
MMOG Server-Side 충돌 및 이동처리 설계와 구현
실시간 게임 서버 최적화 전략
Voxelizaition with GPU
Sw occlusion culling
CUDA를 게임 프로젝트에 적용하기
서버와 클라이언트 같은 엔진 사용하기
프레임레이트 향상을 위한 공간분할 및 오브젝트 컬링 기법
win32 app에서 UWP API호출하기
Azure로 MMO게임 서비스하기
Development AR App with C++ and Windows Holographic API
빌드관리 및 디버깅 (2010년 자료)
Tips and experience_of_dx12_engine_development._ver_1.2

Implements Cascaded Shadow Maps with using Texture Array

  • 1. Texture Array를 이용한 Cascaded Shadow Maps 유영천 Microsoft Visual C++ MVP tw:@dgtman http://megayuchi.wordpress.com
  • 2. • 현 시점에서 가장 대중적으로 사용되고 있는 그림자 렌더링 기법 • 구현하기 쉽다. • Soft-shadow처리도 쉽다. Shadow Maps
  • 3. • 광원(그림자를 드리울)의 뷰공간에서 Shadow Caster가 될 오브젝트들(혹은 월드 전체)을 렌더링 -> Depth Buffer(Texture)를 구성 구현 – Pass 0 , Shadow Caster
  • 4. 구현 – Pass 1 , Shadow Receiver • 광원(그림자를 드리운)의 View- Space로 변환. • -1 ~ 1사이의 좌표공간을 0 – 1사이로 변환. • 변환된 (0 – 1사이) 좌표로 Depth Buffer로부터 depth값을 샘플링 • Receiver의 depth값과 Depth Buffer의 depth값을 비교 • receiver_z > depth_value -> 그림자가 드리워짐
  • 5. 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.
  • 6. • 한 장의 Texture로 넓은 공간을 표현하기엔 해상도가 부족함. • Texture 사이즈를 크게? -> 품질향상, But 성능 하락, GPU메모리 낭비 • PSM, TSM, LiPSM 등등 한 장의 Texture만을 사용하면서 최대한 낭비 없이 사용하는 기법들 등장 그냥 쓰기엔 약간 문제가…
  • 7. • Shadow Map을 만들 때 한 장의 Texture가 아닌 여러 장의 Texture에 나눠 그리자. • 뷰프러스텀 영역을 여러 개의 공간으로 잘라서 여러 장의 Shadow Map Texture를 할당. • 가까운 영역과 먼 영역에 따라 Shadow Map 정밀도 조절 가능. • Shadow Map 해상도 증가에 따른 낭비가 적다. Cascaded Shadow Maps
  • 8. eye Shadow Light Shadow Map Texture – Size(Width x N , Height) ⓪ ① ② ③ ⓪ ① ② ③ ⓪ ① ② ③
  • 9. • 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과 똑같음. 구현
  • 10. • Cascaded단계에 따라 Draw Call회수가 늘어남. CPU 자원 낭비. • 코드 복잡해짐. • 한방에 모든 Cascaded 단계를 처리할 수 없을까? 개선하고 싶은 점
  • 11. • 말 그대로 Texture배열 • 배열이지만 단일 Texture처럼 다룰 수 있다. • SRV, RTV로 사용 가능. • CPU측 코드에서 API사용 방법은 일반 Texture와 똑같다. • Texture로부터 샘플링시 좌표의 x,y,z성분중 z성분을 배열의 인덱스로 사용 Texture Array
  • 12. 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
  • 13. 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(); }
  • 14. • N개의 Cascaded단계가 있을 때 사이즈 Width , Height에 배열이 N개인 Texture 생성 • 일반 Texture와 마찬가지로 RTV와 SRV생성 • Shader안에서 어느 Cascaded 단계에 포함되는지 계산하고 그 인덱스 값을 텍스쳐 좌표의 z성분으로 사용 Texture Arrary를 Shadow Maps에 적용
  • 15. 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
  • 16. Texture Texture Array // set matrix for shadow-space, SetCascadedLightSpaceAll(N); // Draw shadow casters to Depth Buffer DrawShadowCasters(); for (DWORD i=0; i<N; i++) { // set matrix for shadow-space, SetCascadedLightSpace(i); // Draw shadow casters to Depth Buffer DrawShadowCasters(); } CPU Code – Shadow Caster 렌더링 비교
  • 17. 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
  • 18. 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
  • 19. 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
  • 20. 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
  • 21. • Draw Call을 대폭 줄일 수 있다. CPU측 병목을 줄임 • 코드가 보다 간결해짐. Texture Array사용의 장점
  • 22. • 각각의 Light View Space 프러스텀에 대한 culling • 프러스텀에 대한 culling을 먼저 수행한 후 Constant Buffer를 통해 bit flags로 전달. • Geometry Shader에서 0,1,2,3… 각 비트를 체크하며 0 – N까지의 Cascaded단계에 포함되는지를 검사. 비트가 0이면 그대로 폐기. • GPU상에서 클리핑이 이루어지므로 CPU측에서 별도의 Culling작업에 필요한 시간을 감안하면 굳이 필요가 없을지도???? 추가적인 최적화