1. ShadowMap
๋น์ ๊ด์ ์์ ์ฅ๋ฉด์ ๋ ๋๋งํ๊ณ , ๋น์ ๊ด์ ์์ ๋ณด์ด๋ ๋ชจ๋ ๊ฒ์ ํํ๊ฒ ํ์ํ๊ณ ๋ณผ์ ์๋ ๊ฒ๋ค์ ๊ทธ๋ฆผ์๋ก ํ์ํด์ผ ํ๋ค๋ ๊ฒ์ด๋ค.
๋ ธ๋์ ๋ถ๋ถ๋ค์ด ๋น์ ์์ผ์์ ๋ณด์ด๋ ๋ถ๋ถ๋ค์ด๊ณ ๊ฒ์ ์ ๋ถ๋ถ๋ค์ด ๋น์ ์์ผ์์ ๋ณด์ด์ง ์๋ ๋ถ๋ถ์ด๋ค.
์์ฒ๊ฐ์ ๋น ๋ฐฉํฅ Ray๋ฅผ ํตํด ๊ณ์ฐํ๋ ๊ฒ์ ์ค์๊ฐ ๋ ๋๋ง์์ ๊ต์ฅํ ๋นํจ์จ ์ ์ด๊ธฐ ๋๋ฌธ์ ์๋ก์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํด์ผ ํ๋ค.
์ด๋ฅผ ๋์์ผ๋ก ์๊ฐํ ๊ฒ์ด ๊น์ด ๋ฒํผ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
Shadow Map์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋๊ฐ์ ํจ์ค๋ก ๊ตฌ์ฑํ์ฌ ๊ทธ๋ฆฌ๋ ๊ฒ์ด๋ค.
- ๋น์ ๊ด์ ์์ ๊น์ด ๋ฒํผ๋ฅผ ๊ณ์ฐํ์ฌ ๊ฐ์ฅ ๊ฐ๊น์ด ๊น์ด ๊ฐ์ ์ํ์ ์ถ์ถ ํ๋ค. (๊น์ด ๋งต or ์๋์ฐ ๋งต)
- ์ถ๊ฐ ํ ์คํธ๋ฅผ ํตํด ํ์ฌ fragment๊ฐ ๊ทธ๋ฆผ์๋ก ํ์๋ ์ง ์๋์ง ํ๋จํ์ฌ ๊ทธ๋ฆฐ๋ค.
๋จผ์ ๋น์ ๊ด์ ์์ ๊น์ด ๋ฒํผ๋ฅผ ๊ณ์ฐํ์ฌ ๊ฐ์ฅ ๊ฐ๊น์ด ๊น์ด ๊ฐ์ ์ํ์ ์ถ์ถํ๋ค.
//shadowMap vert
#version 430
layout(location=0) in vec3 coord3d;
out vec4 position;
uniform mat4 lightSpaceMatrix;
uniform mat4 Model;
void main(void)
{
gl_Position = lightSpaceMatrix* Model * vec4( coord3d,1.0);
position = gl_Position;
}
๋น ๊ณต๊ฐ์ ์์น ๊ฐ์ position์ ํตํด fragment ์์ด๋๋ก ๋๊ฒจ์ค๋ค.
๊ทธ๋ฆฌ๊ณ ์ฒ์์๋ fragment ์์ด๋์ ์๋ฌด๋ฐ ์ฒ๋ฆฌ๋ฅผ ํ์ง ์๋๋ค.
๋น fragment ์์ด๋๋ ์๋ฌด๋ฐ ์ฒ๋ฆฌ ์์ด ๋๋๋ฉด ๊น์ด ๋ฒํผ๊ฐ ์ ๋ฐ์ดํธ ๋๋ค.
bias ๊ฐ์ ๊ฐ์ง์ง ์๊ณ ๊ทธ๋ฆฌ๊ฒ ๋๋ ๊ฒฝ์ฐ ์ํฌ๋ค ํ์์ด ์ผ์ด๋๋ค.
ํ์ง๋ง bias๋ฅผ 0.005๋ก ์ค์ ์ ํ๋ฉด ์์ฐ์ค๋ฝ๊ฒ ์์ ๊ทธ๋ฆผ์๊ฐ ์ ํ์ง๋ ๋๋์ ์๋๋ค.
๋ฒ์ ๊ณผ ๋น์ ๋ฐฉํฅ์ ๊ธฐ์ดํ์ฌ bias ๋ฒ์๋ฅผ ์์ ํ๋๋ก ๋ณ๊ฒฝํ์๋ค.
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
๊ฒฐ๊ณผ์ ์ผ๋ก ํจ์ฌ ์์ฐ์ค๋ฝ๊ฒ ๋ณด์ด์ง๋ง ๋๋ฌด ์์ ๊ทธ๋ฆผ์๊ฐ ์ญ์ ๋์ด๋ฒ๋ ธ๋ค.
์๋ง bias ๋ฒ์๊ฐ ์๋ง์ ๋ฏํ๋ค.
2. PCF ์ ์ฉ
PCF๋ percentage-closer filtering ์ ์ฝ์์ธ๋ฐ ์ํฐ ์์ผ๋ฆฌ์ด์ฑ ๋ฐฉ๋ฒ ์ค ํ๋์ด๋ค.
๊น์ด ๋งต์ ์ฃผ๋ณ ํ ์ ์ ์ํ๋งํ๊ณ ๊ฐ๊ฐ ๊ฐ๋ณ ์ํ์ ๋ํด ๊ทธ๋ฆผ์์ธ์ง ์๋์ง ํ๋จํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ํ๊ท ํํ๋ค.
float shadow = 0.0;
vec2 texelSize = 1.0 / textureSize(shadowMap, 0);
for(int x = -1; x <= 1; ++x)
{
for(int y = -1; y <= 1; ++y)
{
float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
}
}
shadow /= 9.0;
์ด ์ฝ๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก
float ShadowCalculationPCF(vec4 fragPosLightSpace,vec3 lightDir){
vec2 size = textureSize(shadowMap,0);
vec2 texelSize = vec2(1.0,1.0)/size;
vec3 projCoords = fragPosLightSpace.xyz/fragPosLightSpace.w;
projCoords = projCoords*0.5+0.5;
vec2 uv = projCoords.xy;
float currentDepth = projCoords.z;
float result = 0.0;
vec2 textureSize = textureSize(shadowMap,0);
float bias = 2.0/textureSize.x;
//๋น์ ๋ํ ํ๋ฉด ๊ฐ์ ๊ธฐ์ค์ผ๋ก ๊ธฐ์ธ๊ธฐ์ ์์ ๋ณ๊ฒฝ
//bias = max(bias * (1.0 - dot(Normal, lightDir)), 0.005);
for(int x=-2;x<=2;x++)
{
for(int y=-2;y<=2;y++)
{
vec2 off = vec2(x,y)/size;
result += InterpolatedCompare(shadowMap,uv+off,currentDepth,bias);
}
}
return result/25.0;
}
PCF๋ฅผ ๊ตฌํํ์๋ค.
์์ ์ฝ๋์์๋ 4๋ฒ์ ์ํ๋ง์ ๊ฑฐ์ณค์ง๋ง NewRo๋ ์ด 8๋ฒ์ ์ํ๋ง์ ํ์๊ณ ๋์ bias๊ฐ์ ์กฐ๊ธ ํค์์ฃผ์๋ค.
3. VSM
VSM์ Variance Shadow Mapping์ ์ค์๋ง์ผ๋ก Shadow edge๋ฅผ ๋ถ๋๋ฝ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ ๊ธฐ๋ฒ ์ค ํ๋์ด๋ค.
PCF์ ๋ฌธ์ ์ ์ ๊น์ด ๋ฒํผ์์ ์์ฑ๋ ๊ฐ์ ํ๋์จ์ด๋ก ํํฐ๋ง ํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
์ฆ ํ๋์จ์ด์์ ์๋์ผ๋ก ์ ํ ํด์ฃผ๋ ๊น์ด ๋ฒํผ ๊ฐ์ ํํฐ๋งํ์ฌ ๊ฐ์ ํ๊ณ ์ถ๋ค๋ ๊ฒ์ด๋ค.
chebyshev๋ PCF๋ฅผ ์งํํ ์์ญ์ Shadowing ๋น์จ์ ์ป์ผ๋ ค๊ณ ํ๋ค.
๊ทธ๋์ ๋ง๋ ๋ถ๋ฑ์์ ๋ถ์ฐ(Variance)๋ฅผ ์ฌ์ฉํ๋ค.
- dpeth์ depth*depth ๊ฐ์ ์์ fbo์ ์ ์ฅํ๊ณ (32๋นํธ floating ์ ๋ฐ๋ ์ฌ์ฉ)
- chebyshev's ๊ณต์์ ์ด์ฉํ์ฌ ์ด๋ค fragmet๊ฐ ๊ทธ๋ฆผ์์ ์๋์ง ์๋์ง ์์๋ด๊ณ , fragment๊ฐ ๊ทธ๋ฆผ์์ ๊ฐ๋ ค์ง ํ๋ฅ ์ ๊ณ์ฐํ๋ค.(์์ ๋ก์ด ๊ฒฝ๊ณ๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๋งค์ฐ ํธ๋ฆฌํจ)
์๊ฐ ์์์ด ๊ณ์ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์
glCullFace(GL_FRONT);
๋ฅผ ์ถ๊ฐํด์ฃผ์ด์ผ ํ๋ค.
glEnable(GL_DEPTH_TEST);
๊น์ด ๋ฒํผ ํ์ฑํ ์ฝ๋๋ ๋ฃ์ด์ค์ผํ๋ค.
//shadowMap frag
#version 430
out vec4 FragColors;
in vec4 position;
void main()
{
float depth = position.z/position.w;
depth = depth*0.5+0.5;
float moment1 = depth;
float moment2 = depth*depth;
//return the partial derivative of an argument with respect to x or y
//x ๋๋ y์ ๋ํ ์ธ์์ ๋ถ๋ถ ๋ฏธ๋ถ์ ๋ฐํํฉ๋๋ค.
//๋ํจ์๋ ๋ธ๋ก์ ํฝ์
๊ฐ ์ฌ์ด์ ์ฐจ์ด๋ฅผ ์ทจํ์ฌ ๊ณ์ฐ๋ฉ๋๋ค.
float dx = dFdx(depth);
float dy = dFdy(depth);
moment2 += 0.25*(dx*dx+dy*dy);
FragColors = vec4(moment1,moment2,0.0,0.0);
}
Shadow์ ๊ฒฝ๊ณ๊ฐ ๋๋ ๋ถ๋ถ์ ํ๋จํ๊ธฐ ์ํด ๋ถ์ฐ๊ฐ์ ์ฌ์ฉํ์ฌ
ํน์ Depth ๊ฐ์ ์ฐจ์ด๊ฐ ํด์๋ก ๋ถ์ฐ ๊ฐ์ด ๋ ์ปค์ง๋ ์ ์ ์ด์ฉํ์ฌ Shadowing์ ๋น์จ์ ๋์ถํด๋ธ๋ค.
float ShadowCalculationVSM(vec4 fragPosLightSpace,vec3 projCoords){
float p_max =0.0;
projCoords = projCoords*0.5+0.5;
float currentDepth = projCoords.z;
vec2 moments = texture(shadowMap,projCoords.xy).rg;
if(projCoords.z<=moments.x)
return 1.0;
float variance = max(moments.y-(moments.x*moments.x),0.0002);
float d = projCoords.z - moments.x;
p_max=variance/(variance+d*d);
return p_max;
}
๋ง์ ์์ธ์ ๋ฐ๋ผ ์ข์ ๊ฒฐ๊ณผ๊ฐ ๋์ค์ง ์์ ๊ฒฝ์ฐ max ๊ฐ์ ๋ณ๊ฒฝํด์ฃผ๋ฉด ์ข๋ค๊ณ ํ๋ค.
์กฐ๊ธ๋ ์์ฐ์ค๋ฌ์์ง๋ค.
*ํด๊ฒฐํด์ผ ํ ๋ฌธ์ ๋ค*
- ortho ๋ฅผ perspective๋ก ๋ณ๊ฒฝ → Directional Light๊ฐ ์๋ Spot Light ๊ตฌํ
์ฐธ๊ณ ํ ์ฌ์ดํธ