์๋ณธ : http://www.opengl-tutorial.org/kr/intermediate-tutorials/tutorial-16-shadow-mapping/
ํํ ๋ฆฌ์ผ 15์์๋ ์ ์ ์กฐ๋ช
์ ํฌํจํ๋ ๋ผ์ดํธ ๋งต์ ๋ง๋๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์ ์ต๋๋ค.
์์ฃผ ๋ฉ์ง ๊ทธ๋ฆผ์๋ฅผ ๋ง๋ค์ด๋ด๊ธฐ๋ ํ์ง๋ง, ์ ๋๋ฉ์ด์
๋ชจ๋ธ์ ๋ค๋ฃจ์ง ์์ต๋๋ค.
Shadow Map์ ํ์ฌ(2016๋
๊ธฐ์ค) ๋์ Shadow๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์
๋๋ค. ์ด ๋ฐฉ๋ฒ์ ์ข์ ์ ์ ์์
์ ์์ํ๊ธฐ์ ๊ฝค ์ฝ๋ค๋ ๊ฒ์
๋๋ค. ๋์์ ์ ์ ๋๋ก ์์
ํ๊ธฐ๊ฐ ๋งค์ฐ ์ด๋ ต๋ค๋ ๊ฒ์
๋๋ค.
์ด ํํ ๋ฆฌ์ผ์์๋ ๋จผ์ ๊ธฐ๋ณธ ์๊ณ ๋ฆฌ์ฆ์ ์๊ฐํ๊ณ ๋จ์ ์ ํ์ธํ ๋ค์ ๋ช ๊ฐ์ง ๊ธฐ์ ์ ๊ตฌํํ์ฌ ๋ ๋์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ๊ฒ์
๋๋ค. Shadow Map์ ์์ฑํ ๋น์(2012๋
)์๋ ์ฌ์ ํ ๋ง์ ์ฐ๊ตฌ๊ฐ ์งํ ์ค์ธ ์ฃผ์ ์ด๊ธฐ ๋๋ฌธ์ ํ์์ ๋ฐ๋ผ ์์ฒด Shadow Map์ ๋์ฑ ๊ฐ์ ํ ์ ์๋ ๋ช ๊ฐ์ง ๋ฐฉ๋ฒ์ ์๋ ค๋๋ฆฌ๊ฒ ์ต๋๋ค.
๊ธฐ๋ณธ Shadowmap
๊ธฐ๋ณธ Shadow Map ์๊ณ ๋ฆฌ์ฆ์ ๋ ๊ฐ์ ํจ์ค๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
๋จผ์ , ์ฅ๋ฉด์ ๋น์ ๊ด์ ์์ ๋ ๋๋ง๋ฉ๋๋ค. ๊ฐ fragment์ ๊น์ด๋ง ๊ณ์ฐ๋ฉ๋๋ค.
๊ทธ๋ฐ ๋ค์ ์ฌ(scene)์ด ํ์์ ๊ฐ์ด ๋ ๋๋ง๋์ง๋ง ์ถ๊ฐ ํ
์คํธ๋ฅผ ํตํด ํ์ฌ ์กฐ๊ฐ์ด ๊ทธ๋ฆผ์์ ํ์๋ฉ๋๋ค.
"๊ทธ๋ฆผ์ ์์ ์๋ ๋ฌผ์ฒด" ํ
์คํธ๋ ์ฌ์ค ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค.
ํ์ฌ ์ํ์ด ๋์ผํ ์ ์์ ๊ทธ๋ฆผ์ ๋งต๋ณด๋ค ๋น์์ ๋ฉ๋ฆฌ ๋จ์ด์ ธ ์์ผ๋ฉด ์ฌ(scene)์ ๋น์ ๋ ๊ฐ๊น์ด ๊ฐ์ฒด๊ฐ ํฌํจ๋์ด ์์์ ์๋ฏธํฉ๋๋ค.
์ฆ, ํ์ฌ fragment๋ ๊ทธ๋ฆผ์์ ์์ต๋๋ค.
๋ค์ ์ด๋ฏธ์ง๋ ์๋ฆฌ๋ฅผ ์ดํดํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
Shadowmap ๋ ๋๋งํ๊ธฐ
์ด ํํ ๋ฆฌ์ผ์์๋ directional lights(๋ชจ๋ ๊ด์ ์ด ํํํ๋ค๊ณ ๊ฐ์ฃผ๋ ์ ์์ ์ ๋๋ก ๋ฉ๋ฆฌ ๋จ์ด์ ธ ์๋ ์กฐ๋ช
)๋ง ๊ณ ๋ คํฉ๋๋ค. ๋ฐ๋ผ์ Shadow Map ๋ ๋๋ง์ ์ง๊ต ํฌ์ ํ๋ ฌ์ ์ฌ์ฉํ์ฌ ์ํ๋ฉ๋๋ค. ์ง๊ต ํ๋ ฌ์ ์๊ทผ๋ฒ์ด ๊ณ ๋ ค๋์ง ์๋๋ค๋ ์ ์ ์ ์ธํ๊ณ ๋ ์ผ๋ฐ์ ์ธ ์๊ทผ๋ฒ ํฌ์ ํ๋ ฌ๊ณผ ๊ฐ์ต๋๋ค. ๋ฌผ์ฒด๋ ์นด๋ฉ๋ผ ๊ฐ๊น์ด์ ์๋ ๋ฉ๋ฆฌ์๋ ๋์ผํ๊ฒ ๋ณด์
๋๋ค.
๋ ๋ ๋์ ๋ฐ MVP ๋งคํธ๋ฆญ์ค ์ค์
ํํ ๋ฆฌ์ผ 14๋ถํฐ๋ ์์ด๋์์ ๋์ค์ ์ก์ธ์คํ๊ธฐ ์ํด ์ฅ๋ฉด์ ํ
์ค์ฒ๋ก ๋ ๋๋งํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์ ์ต๋๋ค.
์ฌ๊ธฐ์๋ Shadow Map์ ํฌํจํ๊ธฐ ์ํด 1024x1024 16๋นํธ depth ํ
์ค์ฒ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
Shadow Map์๋ ์ผ๋ฐ์ ์ผ๋ก 16๋นํธ๋ก ์ถฉ๋ถํฉ๋๋ค. ์ด ๊ฐ๋ค์ ์์ ๋กญ๊ฒ ์ํํด๋ณด์ธ์. ๋์ค์ ์ํ๋งํด์ผ ํ๋ฏ๋ก depth ๋ ๋ ๋ฒํผ๊ฐ ์๋ depth ํ
์ค์ฒ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
// The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer.
GLuint FramebufferName = 0;
glGenFramebuffers(1, &FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
// Depth texture. Slower than a depth buffer, but you can sample it later in your shader
GLuint depthTexture;
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, 1024, 1024, 0,GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0);
glDrawBuffer(GL_NONE); // No color buffer is drawn to.
// Always check that our framebuffer is ok
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
return false;
๋น์ ๊ด์ ์์ ์ฅ๋ฉด์ ๋ ๋๋งํ๋ ๋ฐ ์ฌ์ฉ๋๋ MVP ๋งคํธ๋ฆญ์ค๋ ๋ค์๊ณผ ๊ฐ์ด ๊ณ์ฐ๋ฉ๋๋ค:
- Projection ํ๋ ฌ์ X,Y ๋ฐ Z ์ถ์์ ๊ฐ๊ฐ ์ถ ์ ๋ ฌ ์์(-10, 10), (-10,10), (-10, 20)์ ๋ชจ๋ ๊ฒ์ ํฌํจํ๋ ์ง๊ต ํ๋ ฌ์
๋๋ค. ์ด๋ฌํ ๊ฐ์ ์ ์ฒด *๊ฐ์์ ์ธ* ์ฅ๋ฉด์ ํญ์ ๋ณผ ์ ์๋๋ก ๋ง๋ค์ด์ก์ผ๋ฉฐ, ์ด์ ๋ํ ์์ธํ ๋ด์ฉ์ ์ถ๊ฐ ์งํ ์น์
์ ์ฐธ์กฐํ์ญ์์ค.
- View ํ๋ ฌ์ ์นด๋ฉ๋ผ ๊ณต๊ฐ์์ ์กฐ๋ช
๋ฐฉํฅ์ด -Z๊ฐ ๋๋๋ก ์๋๋ฅผ ํ์ ์ํต๋๋ค(ํํ ๋ฆฌ์ผ 3 ์ฐธ์กฐ)
- Model ํ๋ ฌ์ ์ํ๋ ๋๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
glm::vec3 lightInvDir = glm::vec3(0.5f,2,2);
// Compute the MVP matrix from the light's point of view
glm::mat4 depthProjectionMatrix = glm::ortho<float>(-10,10,-10,10,-10,20);
glm::mat4 depthViewMatrix = glm::lookAt(lightInvDir, glm::vec3(0,0,0), glm::vec3(0,1,0));
glm::mat4 depthModelMatrix = glm::mat4(1.0);
glm::mat4 depthMVP = depthProjectionMatrix * depthViewMatrix * depthModelMatrix;
// Send our transformation to the currently bound shader,
// in the "MVP" uniform
glUniformMatrix4fv(depthMatrixID, 1, GL_FALSE, &depthMVP[0][0])
์์ด๋
์ด ํจ์ค ๋์ ์ฌ์ฉ๋๋ ์์ด๋๋ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค. vertex ์์ด๋๋ ๊ท ์ง ์ขํ์์ ์ ์ ์ ์์น๋ฅผ ๊ฐ๋จํ ๊ณ์ฐํ๋ ํต๊ณผ ์์ด๋์
๋๋ค:
#version 330 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
// Values that stay constant for the whole mesh.
uniform mat4 depthMVP;
void main(){
gl_Position = depthMVP * vec4(vertexPosition_modelspace,1);
}
fragment ์์ด๋๋ ๋จ์ํ๊ธฐ ๋๋ฌธ์ fragment์ ๊น์ด๋ฅผ ์์น 0(์ฆ, ๊น์ด ํ
์ค์ฒ)์ ๊ธฐ๋กํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
#version 330 core
// Ouput data
layout(location = 0) out float fragmentdepth;
void main(){
// Not really needed, OpenGL does it anyway
fragmentdepth = gl_FragCoord.z;
}
Shadow Map์ ๋ ๋๋งํ๋ ์๋๋ ์ผ๋ฐ์ ์ผ๋ก ์ผ๋ฐ ๋ ๋๋ง๋ณด๋ค ๋ ๋ฐฐ ์ด์ ๋น ๋ฆ
๋๋ค. ๊น์ด์ ์์ ๋์ ์ ๋ฐ๋๊ฐ ๋ฎ์ ๊น์ด๋ง ๊ธฐ๋ก๋๊ธฐ ๋๋ฌธ์
๋๋ค. ๋ฉ๋ชจ๋ฆฌ ๋์ญํญ์ GPU์์ ๊ฐ์ฅ ํฐ ์ฑ๋ฅ ๋ฌธ์ ์
๋๋ค.
๊ฒฐ๊ณผ
๊ฒฐ๊ณผ ํ
์ค์ฒ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ด๋์ด ์์์ ์์ z๋ฅผ ์๋ฏธํฉ๋๋ค. ๋ฐ๋ผ์ ๋ฒฝ์ ์ค๋ฅธ์ชฝ ์๋จ ๋ชจ์๋ฆฌ๊ฐ ์นด๋ฉ๋ผ ๊ทผ์ฒ์ ์์ต๋๋ค.
๋ฐ๋๋ก ํฐ์์ z=1(๋์ผํ ์ขํ)์ ์๋ฏธํ๋ฏ๋ก ๋งค์ฐ ๋ฉ๋ฆฌ ๋จ์ด์ ธ ์์ต๋๋ค.
Shadowmap ์ฌ์ฉํ๊ธฐ
๊ธฐ๋ณธ ์์ด๋
์ด์ ํ์์ ์์ด๋๋ก ๋์๊ฐ๋๋ค. ๊ณ์ฐํ๋ ๊ฐ fragment์ ๋ํด Shadow Map ๋ค์ ์๋์ง ์ฌ๋ถ๋ฅผ ํ
์คํธํด์ผ ํฉ๋๋ค.
์ด๋ฅผ ์ํด Shadow Map์ ๋ง๋ค ๋ ์ฌ์ฉํ ๊ณต๊ฐ๊ณผ ๋์ผํ ๊ณต๊ฐ์์ ํ์ฌ fragment์ ์์น๋ฅผ ๊ณ์ฐํด์ผ ํฉ๋๋ค. ๋ฐ๋ผ์ ์ผ๋ฐ์ ์ธ MVP ํ๋ ฌ๋ก ํ ๋ฒ ๋ณํํ๊ณ ๊น์ด MVP ํ๋ ฌ๋ก ํ ๋ฒ ๋ณํํด์ผ ํฉ๋๋ค.
ํ์ง๋ง ์ฝ๊ฐ์ ์์์๊ฐ ์์ต๋๋ค. ์ ์ ์์น์ ๊น์ด๋ฅผ ๊ณฑํ๋ฉด MVP๋ [-1,1]์ ์๋ ๊ท ์ผํ ์ขํ๋ฅผ ์ ๊ณตํ์ง๋ง ํ
์ค์ฒ ์ํ๋ง์ [0,1]์์ ์ํํด์ผ ํฉ๋๋ค.
์๋ฅผ ๋ค์ด, ํ๋ฉด ์ค์์ ์๋ fragment๋ ๊ท ์ผํ ์ขํ๋ก (0,0)์ ์์ ๊ฒ์
๋๋ค. ๊ทธ๋ฌ๋ ์ง๊ฐ ์ค๊ฐ์ ์ํ๋งํด์ผ ํ๋ฏ๋ก UV๋ (0.5,05)์ด์ด์ผ ํฉ๋๋ค.
์ด๊ฒ์ fragment shader์์ ์ง์ fetch ์ขํ๋ฅผ ์กฐ์ ํ์ฌ ํด๊ฒฐํ ์ ์์ง๋ง, ๋จ์ํ ์ขํ๋ฅผ 2(๋๊ฐ์ : [-1.1] -> [-0.5,0.5])๋ก ๋๋๊ณ ๋ณํํ๋ ํ๋ ฌ(์๋ ํ : [-0.5,0.5]->[0,1])์ ๊ณฑํ๋ ๊ฒ์ด ๋ ํจ์จ์ ์
๋๋ค.
glm::mat4 biasMatrix(
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0
);
glm::mat4 depthBiasMVP = biasMatrix*depthMVP;
์ด์ vertex ์์ด๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ด์ ๊ณผ ๋์ผํ์ง๋ง 1:1์ด ์๋ 2๊ฐ์ ์์น๋ฅผ ์ถ๋ ฅํฉ๋๋ค:
- gl_Position ์ ํ์ฌ ์นด๋ฉ๋ผ์์ ๋ณผ ์ ์๋ ์ ์ ์ ์์น์
๋๋ค.
- ShadowCoord๋ ๋ง์ง๋ง ์นด๋ฉ๋ผ(๋น)์์ ๋ณผ ์ ์๋ ์ ์ ์ ์์น์
๋๋ค.
// Output position of the vertex, in clip space : MVP * position
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
// Same, but with the light's view matrix
ShadowCoord = DepthBiasMVP * vec4(vertexPosition_modelspace,1);
๊ทธ๋ฐ ๋ค์ fragment ์์ด๋๋ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค:
- texture(shadowMap, ShadowCoord.xy).z ๋ ๋น๊ณผ ๊ฐ์ฅ ๊ฐ๊น์ด ๋น์ ์ฐจ๋จํ๋ ํ์์ ์ฌ์ด์ ๊ฑฐ๋ฆฌ์
๋๋ค.
- ShadowCoord.z๋ ๋น๊ณผ ํ์ฌ fragment ์ฌ์ด์ ๊ฑฐ๋ฆฌ์
๋๋ค.
...๋ฐ๋ผ์ ํ์ฌ fragment๊ฐ ๊ฐ์ฅ ๊ฐ๊น์ด ํ์์๋ณด๋ค ๋ฉ๋ฆฌ ์์ผ๋ฉด, ์ด๊ฒ์ ์ฐ๋ฆฌ๊ฐ (ํด๋น ๊ฐ์ฅ ๊ฐ๊น์ด ํ์์์) ๊ทธ๋ฆผ์์ ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
float visibility = 1.0;
if ( texture( shadowMap, ShadowCoord.xy ).z < ShadowCoord.z){
visibility = 0.5;
}
์ฐ๋ฆฌ๋ ์ด ์ง์์ ์ด์ฉํ์ฌ ์์์ ์์ ํด์ผ ํฉ๋๋ค. ๋ฌผ๋ก ์ฃผ๋ณ ์์์ ์์ ๋์ง ์์ต๋๋ค. ์ํ ์์ ๋ชฉ์ ์ ์ฐ๋ฆฌ๊ฐ ๊ทธ๋ฆผ์ ์์ ์์ ๋๋ ๋ค์ด์ค๋ ๋น์ ๊ฐ์ง๋ก ๋ง๋๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์
๋๋ค(๋๋ ๋ชจ๋ ๊ฒ์ด ์์ํ ๊ฒ์์์ผ ๊ฒ์
๋๋ค)
color =
// Ambient : simulates indirect lighting
MaterialAmbientColor +
// Diffuse : "color" of the object
visibility * MaterialDiffuseColor * LightColor * LightPower * cosTheta+
// Specular : reflective highlight, like a mirror
visibility * MaterialSpecularColor * LightColor * LightPower * pow(cosAlpha,5);
๊ฒฐ๊ณผ - ์๋์ฐ ์ํฌ๋ค
๋ค์์ ํ์ฌ ์ฝ๋์ ๊ฒฐ๊ณผ์
๋๋ค. ๋ถ๋ช
ํ, ์์ด๋์ด๋ ๋ฐ์ด๋์ง๋ง , ํ์ง์ ๋ฐ์๋ค์ผ ์ ์์ต๋๋ค.
์ด ์ด๋ฏธ์ง์ ๊ฐ ๋ฌธ์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ฝ๋์๋ ShadowMap๊ณผ ShadowMap_simple์ ๋ ๊ฐ์ง ํ๋ก์ ํธ๊ฐ ์์ผ๋ฉฐ, ๋ ์ค ๋ ๋ง์์ ๋๋ ๊ฒ์ผ๋ก ์์ํ์ธ์.
๊ฐ๋จํ ๋ฒ์ ์ ์์ ์ด๋ฏธ์ง๋งํผ ํ์ง์ด ์ข์ง ์์ง๋ง ์ดํดํ๊ธฐ๊ฐ ๋ ์ฝ์ต๋๋ค.
๋ฌธ์ ์ ๋ค
Shadow acne
๊ฐ์ฅ ๋ช
๋ฐฑํ ๋ฌธ์ ์ ์ shadow acne์ด๋ค:
์ด ํ์์ ๊ฐ๋จํ ์ด๋ฏธ์ง๋ก ์ฝ๊ฒ ์ค๋ช
ํ ์ ์์ต๋๋ค:
์ด์ ๋ํ ์ผ๋ฐ์ ์ธ "์์ "์ error margin์ ์ถ๊ฐํ๋ ๊ฒ์
๋๋ค. ํ์ฌ fragment์ depth(๋ค์๋งํด, ๋น ๊ณต๊ฐ)๊ฐ ๋ผ์ดํธ๋งต ๊ฐ์์ ์ ๋ง ๋ฉ๋ฆฌ ๋จ์ด์ ธ ์๋ ๊ฒฝ์ฐ์๋ง ์์ ์ฒ๋ฆฌํฉ๋๋ค. ํธํฅ์ ์ถ๊ฐํ์ฌ ์ด๋ฅผ ์ํํฉ๋๋ค:
float bias = 0.005;
float visibility = 1.0;
if ( texture( shadowMap, ShadowCoord.xy ).z < ShadowCoord.z-bias){
visibility = 0.5;
}
๊ฒฐ๊ณผ๋ฌผ์ ํจ์ฌ ๋์์ง๋๋ค:
ํ์ง๋ง, ์ฌ๋ฌ๋ถ์ ์ฐ๋ฆฌ์ ํธ๊ฒฌ ๋๋ฌธ์ ๋
๊ณผ ๋ฒฝ ์ฌ์ด์ ์ธ๊ณต๋ฌผ์ด ๋ ๋๋น ์ก๋ค๋ ๊ฒ์ ์์์ฐจ๋ฆด ์ ์์ต๋๋ค.
๊ฒ๋ค๊ฐ, 0.005์ ํธํฅ์ ๋
์์๋ ๋๋ฌด ๋ง์ด ๋ณด์ด์ง๋ง, ๊ณก๋ฉด์์๋ ์ถฉ๋ถํ์ง ์์ต๋๋ค: ๋ช๋ช ์ธ๊ณต๋ฌผ๋ค์ ์ค๋ฆฐ๋์ ๊ตฌ์ ๋จ์ ์์ต๋๋ค.
์ผ๋ฐ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ๊ธฐ์ธ๊ธฐ์ ๋ฐ๋ผ ์น์ฐ์นจ์ ์์ ํ๋ ๊ฒ์
๋๋ค:
float bias = 0.005*tan(acos(cosTheta)); // cosTheta is dot( n,l ), clamped between 0 and 1
bias = clamp(bias, 0,0.01);
Shadow acne๋ ์ด์ , ๊ตฌ๋ถ๋ฌ์ง ํ๋ฉด์์๋ ์ฌ๋ผ์ก์ต๋๋ค.
์ง์ค๋ฉํธ๋ฆฌ์ ๋ฐ๋ผ ์๋ํ๊ฑฐ๋ ์๋ํ์ง ์์ ์ ์๋ ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ShadowMap์์ ๋ท๋ฉด๋ง ๋ ๋๋งํ๋ ๊ฒ์
๋๋ค. ์ด๊ฒ์ ์ฐ๋ฆฌ๊ฐ ๋๊บผ์ด ๋ฒฝ์ ๊ฐ์ง ํน๋ณํ ๊ธฐํํ์ ๊ตฌ์กฐ(๋ค์ ์น์
- Peter Panning ์ฐธ์กฐ)๋ฅผ ๊ฐ๋๋ก ๊ฐ์ํ์ง๋ง, ์ ์ด๋ acne๋ ๊ทธ๋ฆผ์์ ์๋ ํ๋ฉด์ ์์ ๊ฒ์
๋๋ค.
ShadowMap์ ๋ ๋๋งํ ๋ ์ ๋ฉด ์ผ๊ฐํ์ ์๋ผ๋
๋๋ค.
// We don't use bias in the shader, but instead we draw back faces,
// which are already separated from the front faces by a small distance
// (if your geometry is made this way)
glCullFace(GL_FRONT); // Cull front-facing triangles -> draw only back-facing triangles
๊ทธ๋ฆฌ๊ณ ์ฌ(scene)์ ๋ ๋๋งํ ๋๋ ์ ์์ ์ผ๋ก ๋ ๋๋งํฉ๋๋ค(๋ท๋ฉด ์ ๋จ)
glCullFace(GL_BACK); // Cull back-facing triangles -> draw only front-facing triangles
์ด ๋ฐฉ๋ฒ์ ํธํฅ ์ธ์๋ ์ฝ๋์ ์ฌ์ฉ๋ฉ๋๋ค.
Peter Panning
์ฐ๋ฆฌ๋ ๋ ์ด์ Shadow acne๊ฐ ์์ง๋ง, ์ฌ์ ํ ์๋ชป๋ ์์์ ๋
์ ๊ฐ์ง๊ณ ์๊ณ , ๋ฒฝ์ ๋ ์๋ค๋๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๊ฒ ํฉ๋๋ค(์ดํ "ํผํฐ ํจ๋"์ด๋ผ๋ ์ฉ์ด). ์ฌ์ค, ํธํฅ(bias)์ ๋ํ๋ ๊ฒ์ ์ํฉ์ ๋ ์
ํ์์ผฐ์ต๋๋ค.
์ด๊ฒ์ ๋งค์ฐ ์ฝ๊ฒ ๊ณ ์น ์ ์์ต๋๋ค. ์์ ๊ธฐํํ์ ๊ตฌ์กฐ๋ฅผ ํผํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค. ๋ ๊ฐ์ง ์ด์ ์ด ์์ต๋๋ค.
- ๋จผ์ , ํผํฐ ํจ๋์ ํด๊ฒฐํฉ๋๋ค. ๊ธฐํํ์ด ์ฌ๋ฌ๋ถ์ ํธ๊ฒฌ๋ณด๋ค ๋ ๊น๋ค๋ฉด, ์ฌ๋ฌ๋ถ์ ์ค๋น๊ฐ ๋ค ๋ ๊ฒ์
๋๋ค.
- ๋ ๋ฒ์งธ๋ก, ๋ผ์ดํธ๋งต์ ๋ ๋๋งํ ๋ ํ๋ฉด ์ ๋จ ๊ธฐ๋ฅ์ ์ค์ ํ ์ ์์ต๋๋ค. ์๋ํ๋ฉด ์ด์ ๋ฒฝ์ ๋ค๊ฐํ์ด ๋น์ ํฅํ๊ณ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ์ด ๋ค๊ฐํ์ ๋ท๋ฉด ์ ๋จ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ ๋ ๋๋ง๋์ง ์์ ์ ์์ต๋๋ค.
๋จ์ ์ ๋ ๋๋งํ ์ผ๊ฐํ์ด ๋ ๋ง๋ค๋ ๊ฒ์
๋๋ค(ํ๋ ์๋น ๋ ๋ฒ!)
Aliasing
์ด ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์๋ ๋ถ๊ตฌํ๊ณ , ์ฌ๋ฌ๋ถ์ ๊ทธ๋ฆผ์์ ๊ฒฝ๊ณ์ ์ฌ์ ํ ์จ๋ฆฌ์ด์ฑ์ด ์๋ค๋ ๊ฒ์ ์์์ฐจ๋ฆด ๊ฒ์
๋๋ค. ์ฆ, ํ ํฝ์
์ ํฐ์์ด๊ณ ๋ค์ ํฝ์
์ ๊ฒ์์์
๋๋ค. ๊ทธ ์ฌ์ด์ ๋งค๋๋ฌ์ด ์ ํ์ด ์์ต๋๋ค.
PCF
์ด๋ฅผ ๊ฐ์ ํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ShadowMap์ ์ํ๋ฌ ์ ํ์ Sampler2D ์์ด๋๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์
๋๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก ShadowMap์ ํ ๋ฒ ์ํ๋งํ๋ฉด ํ๋์จ์ด๊ฐ ์ค์ ๋ก ์ธ์ ํ ํ
์
๋ ์ํ๋งํ๊ณ ๋ชจ๋ ํ
์
์ ๋ํด ๋น๊ต๋ฅผ ์ํํ๋ฉฐ ๋น๊ต ๊ฒฐ๊ณผ์ ์ด์ค ์ ํ ํํฐ๋ง๊ณผ ํจ๊ป [0,1]์ ๋ถ๋ ์์์ ์ ๋ฐํํฉ๋๋ค.
์๋ฅผ ๋ค์ด, 0.5๋ ๋ ๊ฐ์ ํ๋ณธ์ด ๊ทธ๋ฆผ์์ ์๊ณ ๋ ๊ฐ์ ํ๋ณธ์ด ๋น์ ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
ํํฐ๋ง๋ ๊น์ด ๋งต์ ๋จ์ผ ์ํ๋ง๊ณผ ๋์ผํ์ง ์์ต๋๋ค! ๋น๊ต๋ ํญ์ true ๋๋ false๋ฅผ ๋ฐํํฉ๋๋ค. PCF๋ 4 "true ๋๋ false"์ ๋ณด๊ฐ๊ฐ์ ์ ๊ณตํฉ๋๋ค.
๋ณด์๋ค์ํผ ๊ทธ๋ฆผ์ ํ
๋๋ฆฌ๋ ๋งค๋๋ฝ์ง๋ง ๊ทธ๋ฆผ์ ๋งต์ ํ
์ค์ฒ๋ ์ฌ์ ํ ๋ณด์
๋๋ค.
Poisson Sampling
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ์ฌ์ด ๋ฐฉ๋ฒ์ ์๋์ฐ ๋งต์ ํ ๋ฒ์ด ์๋๋ผ N๋ฒ ์ํ๋งํ๋ ๊ฒ์
๋๋ค. PCF์ ํจ๊ป ์ฌ์ฉํ๋ฉด N์ด ์๋๋ผ๋ ๋งค์ฐ ์ข์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค. ์ํ 4๊ฐ์ ๋ํ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
for (int i=0;i<4;i++){
if ( texture( shadowMap, ShadowCoord.xy + poissonDisk[i]/700.0 ).z < ShadowCoord.z-bias ){
visibility-=0.2;
}
}
poissonDisk๋ ์๋ฅผ ๋ค์ด ๋ค์๊ณผ ๊ฐ์ด ์ ์๋ ์์ ๋ฐฐ์ด์
๋๋ค:
vec2 poissonDisk[4] = vec2[](
vec2( -0.94201624, -0.39906216 ),
vec2( 0.94558609, -0.76890725 ),
vec2( -0.094184101, -0.92938870 ),
vec2( 0.34495938, 0.29387760 )
);
์ด ๋ฐฉ๋ฒ์ ํต๊ณผํ ์๋์ฐ ๋งต ์ํ ์์ ๋ฐ๋ผ ์์ฑ๋ fragment๊ฐ ๋ค์ ์ด๋์์ง๋๋ค.
700.0 ์์๋ ํ๋ณธ์ด "ํ์ฐ"๋๋ ์ ๋๋ฅผ ์ ์ํฉ๋๋ค. ๋๋ฌด ์ ๊ฒ ํผ๋จ๋ฆฌ๋ฉด ๋ค์ ์จ๋ฆฌ์ด์ฑ์ด ๋ฐ์ํ๊ณ , ๋๋ฌด ๋ง์ด ํผ๋จ๋ฆฌ๋ฉด ๋ฐด๋ฉ์ด ๋ฐ์ํฉ๋๋ค.*(์ด ์คํฌ๋ฆฐ์ท์ ๋ ๊ทน์ ์ธ ํจ๊ณผ๋ฅผ ์ํด PCF๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋์ 16๊ฐ์ ์ํ์ ์ฌ์ฉํฉ๋๋ค.*
Stratified Poisson Sampling
ํฝ์
๋ง๋ค ๋ค๋ฅธ ์ํ์ ์ ํํ์ฌ ์ด ๋ฐด๋ฉ์ ์ ๊ฑฐํ ์ ์์ต๋๋ค.
๋ ๊ฐ์ง ์ฃผ์ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค : Stratified Poisson ๋๋ Rotated Poisson
Stratified๋ ์๋ก ๋ค๋ฅธ ํ๋ณธ์ ์ ํํฉ๋๋ค. Rotated๋ ํญ์ ๊ฐ์ ๊ฒ์ ์ฌ์ฉํ์ง๋ง ๋๋ค ํ์ ์ ์ฌ์ฉํ์ฌ ์๋ก ๋ค๋ฅด๊ฒ ๋ณด์
๋๋ค. ์ด ํํ ๋ฆฌ์ผ์์๋ Stratified ๋ฒ์ ๋ง ์ค๋ช
ํ๊ฒ ์ต๋๋ค.
์ด์ ๋ฒ์ ๊ณผ์ ์ ์ผํ ์ฐจ์ด์ ์ ๋๋ค ์ธ๋ฑ์ค๋ก poissonDisk๋ฅผ ์ธ๋ฑ์ฑํ๋ค๋ ๊ฒ์
๋๋ค:
for (int i=0;i<4;i++){
int index = // A random number between 0 and 15, different for each pixel (and each i !)
visibility -= 0.2*(1.0-texture( shadowMap, vec3(ShadowCoord.xy + poissonDisk[index]/700.0, (ShadowCoord.z-bias)/ShadowCoord.w) ));
}
๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ก ๋์๋ฅผ ์์ฑํ ์ ์์ผ๋ฉฐ,[0,1]์์ ๋์๋ฅผ ๋ฐํํฉ๋๋ค:
float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
return fract(sin(dot_product) * 43758.5453);
์ฐ๋ฆฌ์ ๊ฒฝ์ฐ seed4๋ i(4๊ฐ์ ์๋ก ๋ค๋ฅธ ์์น์์ ์ํ์ ์ฑ์ทจํ ์ ์๋๋ก)์ ...์ ์กฐํฉ์ด ๋ฉ๋๋ค.
gl_FragCord(ํ๋ฉด์ ํฝ์
์์น)๋๋ Position_worldspace๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
// - A random sample, based on the pixel's screen location.
// No banding, but the shadow moves with the camera, which looks weird.
int index = int(16.0*random(gl_FragCoord.xyy, i))%16;
// - A random sample, based on the pixel's position in world space.
// The position is rounded to the millimeter to avoid too much aliasing
//int index = int(16.0*random(floor(Position_worldspace.xyz*1000.0), i))%16;
์ด๋ ๊ฒ ํ๋ฉด ์์ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ ํจํด์ด ์ฌ๋ผ์ง๊ณ ์๊ฐ์ ๋
ธ์ด์ฆ๊ฐ ์ฌ๋ผ์ง๋๋ค.
๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ์ ์ํ๋ ๋
ธ์ด์ฆ๋ ์ข
์ข
์ด๋ฌํ ํจํด๋ณด๋ค ๋ ๋ถ์พํฉ๋๋ค.
์ธ ๊ฐ์ง ๊ตฌํ์ ๋ํ ์๋ tutorial16/ShadowMapping.fragmentshader ๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
๋ ๋์๊ฐ๊ธฐ
์ด ๋ชจ๋ ๋ฐฉ๋ฒ์๋ ๋ถ๊ตฌํ๊ณ , ์ฐ๋ฆฌ์ ๊ทธ๋ฆผ์๋ฅผ ๊ฐ์ ํ ์ ์๋ ๋ง์ ๋ฐฉ๋ฒ๋ค์ด ์์ต๋๋ค.
๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ๊ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
Early bailing
๊ฐ fragment์ ๋ํด 16๊ฐ์ ํ๋ณธ์ ์ถ์ถํ๋ ๋์ (๋ค์ ๋งํ๋ฉด ๋ง์ ์) 4๊ฐ์ ๋ฉ๋ฆฌ ์๋ ํ๋ณธ์ ์ถ์ถํฉ๋๋ค.
๋ง์ฝ ๊ทธ๋ค ๋ชจ๋๊ฐ ๋น์ด๋ ๊ทธ๋ฆผ์ ์์ ์๋ค๋ฉด, ์ฌ๋ฌ๋ถ์ 16๊ฐ์ ์ํ ๋ชจ๋๊ฐ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋์ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ ์ ์์ต๋๋ค: Early bailing. ๋ง์ฝ ์ด๋ค ๊ฒ๋ค์ด ๋ค๋ฅด๋ค๋ฉด, ์ฌ๋ฌ๋ถ์ ์๋ง๋ ๊ทธ๋ฆผ์ ๊ฒฝ๊ณ์ ์์ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ 16๊ฐ์ ์ํ์ด ํ์ํฉ๋๋ค.
Spot lights
์คํฌํธ๋ผ์ดํธ๋ฅผ ๋ค๋ฃจ๋ ๋ฐ๋ ๋ณ๊ฒฝ ์ฌํญ์ด ๊ฑฐ์ ํ์ํ์ง ์์ต๋๋ค. ๊ฐ์ฅ ํ์คํ ๊ฒ์ ์ง๊ต ํฌ์ฉ ํ๋ ฌ์ ์๊ทผ ํฌ์ ํ๋ ฌ๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์
๋๋ค.
glm::vec3 lightPos(5, 20, 20);
glm::mat4 depthProjectionMatrix = glm::perspective<float>(glm::radians(45.0f), 1.0f, 2.0f, 50.0f);
glm::mat4 depthViewMatrix = glm::lookAt(lightPos, lightPos-lightInvDir, glm::vec3(0,1,0));
๊ฐ์ ๊ฒ์ด์ง๋ง, orthographic frustum ๋์ ์ perspective frustum์ ์ฌ์ฉํฉ๋๋ค.
texture2Dproj ๋ฅผ ์ฌ์ฉํ์ฌ ์๊ทผ ๋ถํ ์ ํฉ๋๋ค.(์์ต์4- ํ๋ ฌ์ ๊ฐ์ฃผ ์ฐธ์กฐ)
๋๋ฒ์งธ ๋จ๊ณ๋ ์์ด๋์ ๊ด์ ์์ ๊ณ ๋ คํ๋ ๊ฒ์
๋๋ค.(์์ต์ 4- ํ๋ ฌ์ ๊ฐ์ฃผ ์ฐธ์กฐ). ๊ฐ๋จํ ๋งํด์, ํฌ์ ํฌ์ ํ๋ ฌ์ ์ค์ ๋ก ์ด๋ค ํฌ์๋ ํ์ง ์์ต๋๋ค. ์ด ์์
์ ํ๋์จ์ด์์ ์์ ์ขํ๋ฅผ w๋ก ๋๋์ด ์ํํฉ๋๋ค.
์ฌ๊ธฐ์, ์ฐ๋ฆฌ๋ ์์ด๋์ ๋ณํ์ ๋ชจ๋ฐฉํ๊ธฐ ๋๋ฌธ์, ์ฐ๋ฆฌ๋ ์ฐ๋ฆฌ ์์ ์ ๋ถํ ํ๋ ๊ด์ ์ ํด์ผ ํฉ๋๋ค. ์ฐธ๊ณ ๋ก, orthographic ํ๋ ฌ์ ํญ์ w=1์ ๊ท ์ง ๋ฒกํฐ๋ฅผ ์์ฑํ๋ฏ๋ก ์๊ทผ๋ฒ์ ์์ฑํ์ง ์์ต๋๋ค).
GLSL์์ ์ด๋ฅผ ์ํํ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ๋ ๋ฒ์งธ์ค์ ๋ด์ฅ textureProj ํจ์๋ฅผ ์ฌ์ฉํ์ง๋ง ๋ ๋ฐฉ๋ฒ ๋ชจ๋ ์ ํํ๊ฒ ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ์์ฑํฉ๋๋ค.
if ( texture( shadowMap, (ShadowCoord.xy/ShadowCoord.w) ).z < (ShadowCoord.z-bias)/ShadowCoord.w )
if ( textureProj( shadowMap, ShadowCoord.xyw ).z < (ShadowCoord.z-bias)/ShadowCoord.w )
Point lights
๋์ผํ์ง๋ง depth ๊ท๋ธ ๋งต์ ์ฌ์ฉํฉ๋๋ค. ํ๋ธ ๋งต์ ํ๋ธ์ ๊ฐ ๋ฉด์ ํ๋์ฉ ์๋ 6๊ฐ์ ํ
์ค์ฒ ์ธํธ์
๋๋ค. ๋ํ ํ์ค UV ์ขํ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ฐฉํฅ์ ๋ํ๋ด๋ 3D ๋ฒกํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ก์ธ์ค ํ ์ ์์ต๋๋ค.
๊น์ด๋ ๊ณต๊ฐ์ ๋ชจ๋ ๋ฐฉํฅ์ ๋ํด ์ ์ฅ๋๋ฏ๋ก ์ ๊ด ์ฃผ์์ ๊ทธ๋ฆผ์๊ฐ ๋๋ฆฌ์ธ ์ ์์ต๋๋ค.
์ฌ๋ฌ๊ฐ์ ๋น ํผํฉ
์๊ณ ๋ฆฌ์ฆ์ ์ฌ๋ฌ ๊ฐ์ ์กฐ๋ช
์ ์ฒ๋ฆฌํ์ง๋ง ๊ฐ ์กฐ๋ช
์ ๊ทธ๋ฆผ์ ๋งต์ ์์ฑํ๊ธฐ ์ํด ์ฅ๋ฉด์ ์ถ๊ฐ๋ก ๋ ๋๋งํด์ผ ํฉ๋๋ค. Shadow๋ฅผ ์ ์ฉํ ๋ ์์ฒญ๋ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํ์ํ๋ฉฐ ๋์ญํญ์ด ๋งค์ฐ ๋น ๋ฅด๊ฒ ์ ํ๋ ์ ์์ต๋๋ค.
์๋ ๋น frustum
์ด ํํ ๋ฆฌ์ผ์์๋ ์ ์ฒด ์ฅ๋ฉด์ ํฌํจํ๋๋ก ์์ผ๋ก ๋ง๋ ๋น frustum์
๋๋ค. ์ด ์ ํ๋ ์์ ์์๋ ์ด ์์
์ด ์๋ํ์ง๋ง ์ด ์์
์ ํผํด์ผ ํฉ๋๋ค.
๋ง์ฝ ๋น์ ์ ์ง๋๊ฐ 1Km x 1Km์ด๋ผ๋ฉด, ๋น์ ์ 1024x1024 ๊ทธ๋ฆผ์ ์ง๋์ ๊ฐ ํ
์คํธ๋ 1ํ๋ฐฉ๋ฏธํฐ๋ฅผ ์ฐจ์งํ ๊ฒ์
๋๋ค. ์ด๊ฒ์ ํํธ ์์ต๋๋ค. ์กฐ๋ช
์ ํฌ์ ํ๋ ฌ์ ๊ฐ๋ฅํํ ํ์ดํธํด์ผํฉ๋๋ค.
์คํฌํธ๋ผ์ดํธ์ ๊ฒฝ์ฐ ๋ฒ์๋ฅผ ์กฐ์ ํ์ฌ ์ฝ๊ฒ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
ํ์๊ณผ ๊ฐ์ ๋ฐฉํฅ ์กฐ๋ช
์ ๋ ๊น๋ค๋กญ์ต๋๋ค. ๊ทธ๊ฒ๋ค์ ์ ๋ง๋ก ์ ์ฒด ์ฅ๋ฉด์ ๋น์ถ์ฃ . ๊ด๊ฒฉ์๋ฅผ ๊ณ์ฐํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ ์ฌ์ ๊ทธ๋ฆผ์ ์์ ๊ธฐ ๋๋ ์ค์ฌ์ PSR์ ๋น์ frustum, view frustum ๋ฐ ์ฅ๋ฉด ๊ฒฝ๊ณ ์์์ ๋์์ ์ํ๋ ๊ฐ์ฒด ์
๋๋ค. ์ด๋ฆ์์ ์ ์ ์๋ฏ์ด, ์ด ๋ฌผ์ฒด๋ค์ ์์์ ๋ฐ๊ธฐ ์ฝ์ต๋๋ค. ์นด๋ฉ๋ผ์ ๋น์ผ๋ก ๋ณผ ์ ์์ต๋๋ค.
- ์ ์ฌ์ ๊ทธ๋ฆผ์ ์บ์คํฐ(PCF)๋ ๋ชจ๋ ์ ์ฌ์ ๊ทธ๋ฆผ์ ์์ ๊ธฐ์ด๋ฉฐ, ๊ทธ ์ฌ์ด์ ์๋ ๋ชจ๋ ๋ฌผ์ฒด(๋ฌผ์ฒด๋ ๋ณด์ด์ง ์์ง๋ง ์ฌ์ ํ ๋ณด์ด๋ ๊ทธ๋ฆผ์๋ฅผ ๋๋ฆฌ์ธ ์ ์์)์
๋๋ค.
๋ฐ๋ผ์ ๋น ํฌ์ ํ๋ ฌ์ ๊ณ์ฐํ๋ ค๋ฉด ๋ณด์ด๋ ๋ชจ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์์ ๋๋ฌด ๋ฉ๋ฆฌ ์๋ ๊ฐ์ฒด๋ฅผ ์ ๊ฑฐํ๊ณ ๊ฒฝ๊ณ ์์๋ฅผ ๊ณ์ฐํฉ๋๋ค. ์ด ๊ฒฝ๊ณ ์์์ ์กฐ๋ช
์ฌ์ด์ ์๋ ๊ฐ์ฒด๋ฅผ ์ถ๊ฐํ๊ณ ์ ๊ฒฝ๊ณ ์์๋ฅผ ๊ณ์ฐํฉ๋๋ค(๊ทธ๋ฌ๋ ์ด๋ฒ์๋ ์กฐ๋ช
๋ฐฉํฅ์ ๋ฐ๋ผ ์ ๋ ฌ๋จ).
์ด๋ฌํ ์งํฉ์ ์ ํํ ๊ณ์ฐ์๋ ๋ณผ๋ก ๊ป์ง ๊ต์ฐจ์ ๊ณ์ฐ์ด ํฌํจ๋์ง๋ง, ์ด ๋ฐฉ๋ฒ์ ๊ตฌํํ๊ธฐ๊ฐ ํจ์ฌ ์ฝ์ต๋๋ค.
์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉด ๊ทธ๋ฆผ์ ๋งต ํด์๋๊ฐ ๊ฐ์๊ธฐ ์ฆ๊ฐํ๊ธฐ ๋๋ฌธ์ ๋ฌผ์น๊ฐ frustum์์ ์ฌ๋ผ์ง๋ฉด ํํ์ด ๋ฐ์ํฉ๋๋ค. ๊ณ๋จ์ Shadow Map์๋ ์ด๋ฌํ ๋ฌธ์ ๊ฐ ์์ง๋ง ๊ตฌํํ๊ธฐ๊ฐ ๋ ์ด๋ ค์ฐ๋ฉฐ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ๊ฐ์ ๋งค๋๋ฝ๊ฒ ํ์ฌ ๋ณด์ ํ ์ ์์ต๋๋ค.
์ง์ shadow maps
์ง์ ๊ทธ๋ฆผ์ ๋งต์ ๊ทธ๋ฆผ์์ ์์ง๋ง ๋น ํ๋ฉด ๊ทผ์ฒ์ ์๋ fragment๊ฐ ์ค์ ๋ก "๊ฐ์ด๋ฐ ์ด๋๊ฐ"๋ผ๊ณ ๊ฐ์ ํ์ฌ ์จ๋ฆฌ์ด์ฑ์ ์ ํํ๋ ค๊ณ ํฉ๋๋ค. ํ
์คํธ๊ฐ ๋์ด์ ์ด์ง๋ฒ์ด ์๋๋ผ๋ ์ ์ ์ ์ธํ๋ฉด ์ด๋ ํธํฅ๊ณผ ๊ด๋ จ ์์ต๋๋ค. ๋น์ด ์๋ ํ๋ฉด๊น์ง์ ๊ฑฐ๋ฆฌ๊ฐ ์ฆ๊ฐํ๋ฉด fragment๊ฐ ์ ์ ์ด๋์์ง๋๋ค.
์ด๊ฒ์ ๋ช
๋ฐฑํ ๋ถ์ ํ์์ด๋ฉฐ, ๋ ๋ฌผ์ฒด๊ฐ ๊ฒน์น ๋ ์ธ๊ณต๋ฌผ์ด ๋ํ๋ ์ ์์ต๋๋ค.
๋น-๊ณต๊ฐ ์๊ทผ๋ฒ shadow maps
LiSPSM์ ์นด๋ฉ๋ผ ๊ทผ์ฒ์์ ๋ ์ ํํ๊ฒ ํ๊ธฐ ์ํด ๋น ํฌ์ ํ๋ ฌ์ ์กฐ์ ํฉ๋๋ค. ์ด๊ฒ์ "๋ถ์์ ํ frustra"์ ๊ฒฝ์ฐ์๋ ํนํ ์ค์ํฉ๋๋ค. ์ฌ๋ฌ๋ถ์ ๋ฐฉํฅ์ ๋ฐ๋ผ์ง๋ง, ์คํฟ๋ผ์ดํธ๋ ๋ฐ๋ ๋ฐฉํฅ์ ๋ฐ๋ผ๋ด
๋๋ค. ๋น์ ์ ๋น ๊ทผ์ฒ, ์ฆ ๋น์ ์ผ๋ก๋ถํฐ ๋ฉ๋ฆฌ ๋จ์ด์ง ๊ณณ์ ๋ง์ ๊ทธ๋ฆผ์ ์ง๋ ์ ๋ฐ๋๋ฅผ ๊ฐ์ง๊ณ ์๊ณ , ๋น์ ์ด ๊ฐ์ฅ ํ์๋ก ํ๋ ์นด๋ฉ๋ผ ๊ทผ์ฒ์ ๋ฎ์ ํด์๋๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
๊ทธ๋ฌ๋ LiSPSM์ ๊ตฌํํ๊ธฐ๊ฐ ๊น๋ค๋กญ์ต๋๋ค. ๊ตฌํ์ ๋ํ ์์ธํ ๋ด์ฉ์ ๋ ํผ๋ฐ์ค๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
๊ณ๋จ์ shadow maps
CSM์ LiSPSM๊ณผ ์์ ํ ๋์ผํ ๋ฌธ์ ๋ฅผ ๋ค๋ฃจ์ง๋ง ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ๋จ์ํ view frustum์ ์ฌ๋ฌ ๋ถ๋ถ์ ๋ํด ์ฌ๋ฌ ๊ฐ์(2-4) ํ์ค ๊ทธ๋ฆผ์ ๋งต์ ์ฌ์ฉํฉ๋๋ค.
์ฒซ ๋ฒ์งธ ๊ฒ์ ์ฒซ ๋ฒ์งธ ๋ฏธํฐ๋ฅผ ๋ค๋ฃจ๊ธฐ ๋๋ฌธ์ ๊ฝค ์์ ๊ตฌ์ญ์ ๋ํด์๋ ํ๋ฅญํ ํด์๋๋ฅผ ์ป์ ์ ์์ต๋๋ค. ๋ค์ ๊ทธ๋ฆผ์ ์ง๋๋ ๋ ๋จผ ๋ฌผ์ฒด๋ฅผ ๋ค๋ฃน๋๋ค. ๋ง์ง๋ง shadow map์ ์ฅ๋ฉด์ ํฐ ๋ถ๋ถ์ ๋ค๋ฃจ์ง๋ง, ๊ด์ ๋๋ฌธ์ ๊ฐ์ฅ ๊ฐ๊น์ด ๊ตฌ์ญ๋ณด๋ค ์๊ฐ์ ์ผ๋ก ๋ ์ค์ํ์ง๋ ์์ ๊ฒ์
๋๋ค.
๊ณ๋จ์ ์๋์ฐ ๋งต์ ์์ฑ ๋น์(2012๋
) ์ต๊ณ ์ ๋ณต์ก์ฑ/ํ์ง ๋น์จ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ด๊ฒ์ ๋ง์ ๊ฒฝ์ฐ์ ์ ํ์ ํด๊ฒฐ์ฑ
์
๋๋ค.
๊ฒฐ๋ก
๋ณด์๋ค์ํผ, ๊ทธ๋ฆผ์ ์ง๋๋ ๋ณต์กํ ์ฃผ์ ์
๋๋ค. ๋งค๋
์๋ก์ด ๋ณํ๊ณผ ๊ฐ์ ์ฌํญ์ด ๋ฐํ๋๊ณ ์์ผ๋ฉฐ, ํ์ฌ๋ก์๋ ์ด๋ค ์๋ฃจ์
๋ ์๋ฒฝํ์ง ์์ต๋๋ค.
๋คํํ, ์ ์๋ ๋๋ถ๋ถ์ ๋ฐฉ๋ฒ์ ํจ๊ป ํผํฉ๋ ์ ์์ต๋๋ค. ๋น ๊ณต๊ฐ ๊ด์ ์์ ๊ณ์ฐ์ shadow map์ PCF๋ก ๋งค๋๋ฝ๊ฒ ๋ง๋๋ ๊ฒ์ด ์๋ฒฝํ๊ฒ ๊ฐ๋ฅํฉ๋๋ค.. ์ด ๋ชจ๋ ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ์คํํด ๋ณด์ญ์์ค.
๊ฒฐ๋ก ์ ์ผ๋ก, ์ ๋ ๋น์ ์ด ๊ฐ๋ฅํ ๋๋ง๋ค ๋ฏธ๋ฆฌ ๊ณ์ฐ๋ ๋ผ์ดํธ๋งต์ ๊ณ ์ํ๊ณ , ๋์ ๊ฐ์ฒด์๋ง shadowmap์ ์ฌ์ฉํ ๊ฒ์ ์ ์ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ ๊ฐ์ง์ ์์์ ํ์ง์ด ๋์ผํ์ง ํ์ธํ์ญ์์ค. ์๋ฒฝํ ์ ์ ํ๊ฒฝ๊ณผ ๋ชจ์์๊ฐ ์ข์ง ์์ ๊ทธ๋ฆผ์๊ฐ ์๋ ๊ฒ๋ ์ข์ง ์์ต๋๋ค.