shaderX7 4.1Practical Cascaded Shadow Maps<br />http://cafe.naver.com/shader.cafe<br />http://ohyecloudy.com<br />
CSM<br />
Overview<br />CSM 기본 구현에 대한 내용이 아니다.<br />실무에 적용할 때, 생기는 문제들 해결 방법을 알려주는 글.<br />
flickering of shadow quality<br />storage strategy<br />non-optimized split selection<br />correct computation of texture ...
그림자 품질이 다음 프레임에 급격히 변한다.<br />light, viewer 위치가 변하면 발생.<br />
Exact Solution<br />split을 감싸는 bounding sphere사용<br />shadow map size가 stable<br />scale, offset 문제 해결<br />
// step 1 : calculate the light basis<br />vector3 direction = normalize(WORLD.getColumn3(2));<br />vector3 side = normali...
// step 1 : calculate the light basis<br />direction, side, up<br />// update all splits<br />for (inti = 0; i &lt; numSpl...
// step 1 : calculate the light basis<br />direction, side, up<br />// update all splits<br />for (inti = 0; i &lt; numSpl...
Approximated Solution<br />sphere를 사용하니 그림자 텍스쳐낭비 심함.<br />bounding-box 사용.<br />scale, offset 직접 계산.<br />구한 scale, offse...
// calculate scale values<br />float scaleX = 2.0f / (maxX – minX);<br />float scaleY = 2.0f / (maxY – minY);<br />// the ...
// calculate scale values<br />// calculate offset values<br />float offsetX = -0.5f * (maxX + minX) * scaleX;<br />float ...
flickering of shadow quality<br />storage strategy<br />non-optimized split selection<br />correct computation of texture ...
Texture arrays<br />Direct3D 10.1 이상<br />Cube maps<br />항상 6개 shadow map 텍스쳐<br />Multiple textures<br />CSM 마다 텍스쳐 한 장씩....
flickering of shadow quality<br />storage strategy<br />non-optimized split selection<br />correct computation of texture ...
fragment P<br />Z 값을 따지면 split-1<br />X,Y 값을 따지면 split-0<br />품질을 극대화 하려면 split-0를 사용하는 게 맞다.<br />
float shadow = 0.0;<br />// get the potential texture coordinates in the first shadow map<br />float4 texcoord = mul(matri...
flickering of shadow quality<br />storage strategy<br />non-optimized split selection<br />correct computation of texture ...
기존 방법<br />Vertex Shader<br />split 번호를 판단 X.<br />가능한 모든 정보를 PS에 넘긴다.<br />Pixel Shader<br />split 번호를 계산.<br />해당하는 shad...
struct VS_OUTPUT<br />{<br />	float4 position : POSITION;<br />float4 tex0 : TEXCOORD0; // CSM0<br />	float4 tex1 : TEXCOO...
개선된 방법<br />Vertex Shader<br />split 번호를 판단 X<br />월드 좌표를 PS에 넘겨준다.<br />Pixel Shader<br />split 번호를 계산<br />world  texco...
struct VS_OUTPUT<br />{<br />	float4 position : POSITION;<br />	float4 tex0 : TEXCOORD0;<br />}<br />// VS<br />VSOutput.p...
Upcoming SlideShare
Loading in …5
×

[shaderx7] 4.1 Practical Cascaded Shadow Maps

3,577 views

Published on

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,577
On SlideShare
0
From Embeds
0
Number of Embeds
21
Actions
Shares
0
Downloads
42
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

[shaderx7] 4.1 Practical Cascaded Shadow Maps

  1. 1. shaderX7 4.1Practical Cascaded Shadow Maps<br />http://cafe.naver.com/shader.cafe<br />http://ohyecloudy.com<br />
  2. 2. CSM<br />
  3. 3. Overview<br />CSM 기본 구현에 대한 내용이 아니다.<br />실무에 적용할 때, 생기는 문제들 해결 방법을 알려주는 글.<br />
  4. 4. flickering of shadow quality<br />storage strategy<br />non-optimized split selection<br />correct computation of texture coordinates<br />filter across splits<br />
  5. 5. 그림자 품질이 다음 프레임에 급격히 변한다.<br />light, viewer 위치가 변하면 발생.<br />
  6. 6.
  7. 7. Exact Solution<br />split을 감싸는 bounding sphere사용<br />shadow map size가 stable<br />scale, offset 문제 해결<br />
  8. 8. // step 1 : calculate the light basis<br />vector3 direction = normalize(WORLD.getColumn3(2));<br />vector3 side = normalize(WORLD.getColumn3(1));<br />vector3 up = normalize(WORLD.getColumn3(0));<br />// update all splits<br />for (inti = 0; i &lt; numSplits; i++)<br />{<br />// Step 2 : Calculate the bounding sphere “bs” of each split<br /> // Step 3 : update the split-specific view matrix<br /> // ‘matrixView[i]’ and projection matrix ‘matrixProjections[i]’<br />}<br />
  9. 9. // step 1 : calculate the light basis<br />direction, side, up<br />// update all splits<br />for (inti = 0; i &lt; numSplits; i++)<br />{<br />// Step 2 : Calculate the bounding sphere “bs” of each split<br /> Sphere bs = CalculateBoundingSphere(split[i]);<br /> vector3 center = INVWORLDVIEW * bs.getCenter();<br /> float radius = bs.getRadius();<br /> // adjust the sphere’s center to make sure it is transformed into the center of the shadow map<br /> float x = ceilf(dot(center,up)*sizeSM/radius)*radius/sizeSM;<br /> float y = ceilf(dot(center,side)*sizeSM/radius)*radius/sizeSM;<br /> center = up*x + side*y + direction * dot(center, direction);<br /> // Step 3 : update the split-specific view matrix<br />// ‘matrixView[i]’ and projection matrix ‘matrixProjections[i]’<br />}<br />
  10. 10. // step 1 : calculate the light basis<br />direction, side, up<br />// update all splits<br />for (inti = 0; i &lt; numSplits; i++)<br />{<br />// Step 2 : Calculate the bounding sphere “bs” of each split<br /> // Step 3 : update the split-specific view matrix<br /> // ‘matrixView[i]’ and projection matrix ‘matrixProjections[i]’<br />matrixProjections[i]<br /> = MatrixOrthoProjection(<br /> -radius, radius, radius, -radius, near, far);<br /> vector3 origin = center – direction * far;<br />matrixView[i] = MatrixLookAt(origin, center, up);<br />}<br />
  11. 11.
  12. 12. Approximated Solution<br />sphere를 사용하니 그림자 텍스쳐낭비 심함.<br />bounding-box 사용.<br />scale, offset 직접 계산.<br />구한 scale, offset을 여러 프레임에 걸쳐 부드럽게 보간.<br />
  13. 13. // calculate scale values<br />float scaleX = 2.0f / (maxX – minX);<br />float scaleY = 2.0f / (maxY – minY);<br />// the scale values will be quantized into 64 discrete levels<br />float scaleQuantizer = 64.0f;<br />// quantize scale<br />scaleX = scaleQuantizer/ ceilf(scaleQuantizer/ scaleX);<br />scaleY = scaleQuantizer/ ceilf(scaleQuantizer/ scaleY);<br />// calculate offset values<br />
  14. 14. // calculate scale values<br />// calculate offset values<br />float offsetX = -0.5f * (maxX + minX) * scaleX;<br />float offsetY = -0.5f * (maxY + minY) * scaleY;<br />// quantize offset<br />float halfTextureSize = 0.5f * sizeSM;<br />offsetX = ceilf(offsetX * halfTextureSize) / halfTextureSize;<br />offsetY = ceilf(offsetY * halfTextureSize) / halfTextureSize;<br />
  15. 15. flickering of shadow quality<br />storage strategy<br />non-optimized split selection<br />correct computation of texture coordinates<br />filter across splits<br />
  16. 16. Texture arrays<br />Direct3D 10.1 이상<br />Cube maps<br />항상 6개 shadow map 텍스쳐<br />Multiple textures<br />CSM 마다 텍스쳐 한 장씩.<br />Texture atlas<br />
  17. 17. flickering of shadow quality<br />storage strategy<br />non-optimized split selection<br />correct computation of texture coordinates<br />filter across splits<br />
  18. 18. fragment P<br />Z 값을 따지면 split-1<br />X,Y 값을 따지면 split-0<br />품질을 극대화 하려면 split-0를 사용하는 게 맞다.<br />
  19. 19. float shadow = 0.0;<br />// get the potential texture coordinates in the first shadow map<br />float4 texcoord = mul(matrixWorld2Texture[0], PS_Input.world_position);<br />// projective coordinates<br />texcoord.xyz = texcoord.xyz / texcoord.w;<br />// 1st SM x,y:[0,0.5]<br />if (max(abs(texcoord.x – 0.25), abs(texcoord.y – 0.25)) &gt;= 0.25)<br />{<br />texcoord = mul(matrixWorld2Texture[1], PS_Input.world_position);<br />texcoord.xyz = texcoord.xyz / texcoord.w;<br />// 2nd SM, x:[0,0.5], y:[0.5,1] <br />if(max(abs(texcoord.x – 0.25), abs(texcoord.y – 0.75)) &gt;= 0.25)<br /> {<br /> shadow = 1.0;<br /> }<br />}<br />if (shadow != 1.0)<br />{<br />shadow = tex2D(samplerAtlas, texcoord);<br />}<br />
  20. 20.
  21. 21. flickering of shadow quality<br />storage strategy<br />non-optimized split selection<br />correct computation of texture coordinates<br />filter across splits<br />
  22. 22. 기존 방법<br />Vertex Shader<br />split 번호를 판단 X.<br />가능한 모든 정보를 PS에 넘긴다.<br />Pixel Shader<br />split 번호를 계산.<br />해당하는 shadow maps에서 depth 샘플링.<br />
  23. 23. struct VS_OUTPUT<br />{<br /> float4 position : POSITION;<br />float4 tex0 : TEXCOORD0; // CSM0<br /> float4 tex1 : TEXCOORD0; // CSM1<br /> float4 tex2 : TEXCOORD0; // CSM2<br />}<br />// VS<br />float4 posWorldSpace = mul(VSInput.position, WORLD);<br />VSOutput.position = mul(posWorldSpace, matrixViewProj);<br />VSOutput.tex0 = mul(posWorldSpace, matrixTexture[0]);<br />VSOutput.tex1 = mul(posWorldSpace, matrixTexture[1]);<br />VSOutput.tex2 = mul(posWorldSpace, matrixTexture[2]);<br />// PS<br />float shadow;<br />int split = .....;<br />if (split &lt; 1)<br /> shadow = tex2DProj(samplerCSM0, PSInput.tex0);<br />else if (split &lt; 2)<br />...<br />
  24. 24. 개선된 방법<br />Vertex Shader<br />split 번호를 판단 X<br />월드 좌표를 PS에 넘겨준다.<br />Pixel Shader<br />split 번호를 계산<br />world  texcoord트랜스폼<br />해당하는 shadow maps에서 depth 샘플링.<br />수학적으로 틀렸으나 빠르고 눈에 띄는 artifacts X<br />
  25. 25. struct VS_OUTPUT<br />{<br /> float4 position : POSITION;<br /> float4 tex0 : TEXCOORD0;<br />}<br />// VS<br />VSOutput.position = mul(VSInput.position, WORLDVIEWPROJ);<br />VSOutput.tex0 = mul(VSInput.position, WORLD);<br />// PS<br />float shadow;<br />float4 texCoords;<br />int split = ...;<br />if (split &lt; 1)<br />{<br />texCoords = mul(PSInput.tex0, matrixWorld2Texture[split]);<br /> shadow = tex2DProj(samplerCSM0, texCoords);<br />}<br />else if (split &lt; 2)<br />...<br />

×