Lighting
카테고리: OpenGL
태그: Graphics
Main Reference
- Learn OpenGL
- Rinthel Kwon - OpenGL Lecture
Phong Shading
Phong Shading은 가장 대표적인 Local Illumination 모델이다. 즉 다른 물체에 반사되어 발생한 빛(반사광)을 고려하지 않는다는 의미이다. 게임과 같은 Real Time Rendering에서는 많이 쓰이는 기법이다. 우선 간단하게만 설명하자면 Phong Shading에서 물체의 색은 Ambient(고유 색) + Diffuse(난반사) + Specular(정반사)에 의해 결정된다.
Ambient Light
No Ambient | Add Ambient |
---|---|
Ambient Color란 물체가 빛을 받지 않아도 갖고 있는 물체의 고유한 색이다. 현실 세계에서는 약간 이상하게 들리지만 렌더링 과정에서는 필수적인 요소이다. 예를 들어 위 사진의 왼쪽 그림은 ambient color가 없는 경우의 렌더링 결과이다. 자원의 한계 상 모든 반사광을 계산할 수 없기 때문에 빛을 받지 못하는 오브젝트들이 존재하게 된다. 이런 경우 모든 물체가 어느정도의 반사광을 받는다고 가정한 뒤 고유 색(ambient color)를 갖게 해주면 훨씬 자연스러운 결과가 나오게 된다. 따라서 Ambient Color는 빛의 방향, normal의 방향, 시선(카메라) 방향과 상관 없이 상수값으로 처리된다.
// fragment shader
void main() {
vec3 ambient = ambientStrength * lightColor;
vec3 result = ambient * objectColor;
fragColor = vec4(result, 1.0);
}
- abient color의 결과값은 광원의 색(light color) x 물체 고유의 색(ambient color) x 밝기 (abient strength)로 결정
- ambient color만으로는 물체에 입체감이 느껴지지 않음
Diffuse Light
Diffuse | Formula |
---|---|
- 빛이 물체 표면에 부딪혔을 때 모든 방향으로 고르게 퍼지는 빛
- 시선 방향과 상관 없이 빛의 방향, 물체 표면의 방향에 의해 결정
- 빛이 normal과 방향이 가까울 수록 diffuse가 강해짐
- 90도가 넘어가면(내적값이 음수) 빛을 받지 않는다고 판단
float vertices[] = { // pos.xyz, normal.xyz, texcoord.uv
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
};
m_vertexLayout->SetAttrib(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 8, 0);
m_vertexLayout->SetAttrib(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 8, sizeof(float) * 3);
m_vertexLayout->SetAttrib(2, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 8, sizeof(float) * 6);
- Diffuse부터는 color를 계산하는데 normal 벡터가 필요해짐
- normal VBO 추가 & VAO 수정
- 이때 fragment shader에서 사용하는 normal은 local-normal이 아니라, world 좌표계에서의 normal 벡터
// vertex shader
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoord;
uniform mat4 transform;
uniform mat4 modelTransform;
out vec3 normal;
out vec2 texCoord;
out vec3 position;
void main() {
gl_Position = transform * vec4(aPos, 1.0);
normal = (transpose(inverse(modelTransform)) * vec4(aNormal, 0.0)).xyz;
texCoord = aTexCoord;
position = (modelTransform * vec4(aPos, 1.0)).xyz;
}
- 이제 fragment shader에 넘겨줘야 할 값은 vertex의 canonical 좌표(gl_position) 뿐만이 아니라 여러가지로 늘어나기 시작
- 우선 world 좌표계에서의 normal 값을 넘겨줘야 함
- transpose-inverse(model)을 곱해주는 이유는 단순한 선형 변환시 수직 관계가 보존되지 않음
- 아래 그림에서 자세히 설명..
- 마찬가지로 vertex의 world position 넘겨줘야 함
// fragment shader
void main() {
vec3 ambient = ambientStrength * lightColor;
vec3 lightDir = normalize(lightPos - position);
vec3 pixelNorm = normalize(normal);
vec3 diffuse = max(dot(pixelNorm, lightDir), 0.0) * lightColor;
vec3 result = (ambient + diffuse) * objectColor;
fragColor = vec4(result, 1.0);
}
Specular Light
Specular | Formula |
---|---|
- 빛이 물체 표면에 부딪혀 정반사되는 빛
- 시선 방향이 반사광의 방향과 동일할 때 가장 강한 빛을 받음
- 정반사되는 특정 위치를 반짝반짝하게 해줌
- 보통 specular값을 n제곱 해서 사용 (n : shineness)
- SpecularStrengh는 재질마다 다름
- 일반적인 오브젝트는 여러 재질로 이루어져 있는데, Strengh값을 어떻게 조절..?
- Specular Strengh를 나타내는 Texture Map 이용
// fragment shader
void main() {
vec3 ambient = ambientStrength * lightColor;
vec3 lightDir = normalize(lightPos - position);
vec3 pixelNorm = normalize(normal);
vec3 diffuse = max(dot(pixelNorm, lightDir), 0.0) * lightColor;
vec3 viewDir = normalize(viewPos - position);
vec3 reflectDir = reflect(-lightDir, pixelNorm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), specularShininess);
vec3 specular = specularStrength * spec * lightColor;
vec3 result = (ambient + diffuse + specular) * objectColor;
fragColor = vec4(result, 1.0);
}
Result
Ambient | Ambient + Diffuse | Ambient + Diffuse + Specular |
---|---|---|
댓글 남기기