Lighting

Date:     Updated:

카테고리:

태그:

Main Reference
- Learn OpenGL
- Rinthel Kwon - OpenGL Lecture


Phong Shading

09_phong_illumination_model

Phong Shading은 가장 대표적인 Local Illumination 모델이다. 즉 다른 물체에 반사되어 발생한 빛(반사광)을 고려하지 않는다는 의미이다. 게임과 같은 Real Time Rendering에서는 많이 쓰이는 기법이다. 우선 간단하게만 설명하자면 Phong Shading에서 물체의 색은 Ambient(고유 색) + Diffuse(난반사) + Specular(정반사)에 의해 결정된다.


Ambient Light

No Ambient Add Ambient
2 3

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만으로는 물체에 입체감이 느껴지지 않음


233115


Diffuse Light

Diffuse Formula
234343 5
  • 빛이 물체 표면에 부딪혔을 때 모든 방향으로 고르게 퍼지는 빛
  • 시선 방향과 상관 없이 빛의 방향, 물체 표면의 방향에 의해 결정
  • 빛이 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 넘겨줘야 함


Ect-48


// 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);
}


003315


Specular Light

Specular Formula
234343 7
  • 빛이 물체 표면에 부딪혀 정반사되는 빛
  • 시선 방향이 반사광의 방향과 동일할 때 가장 강한 빛을 받음
  • 정반사되는 특정 위치를 반짝반짝하게 해줌
  • 보통 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);
}


004650


Result

Ambient Ambient + Diffuse Ambient + Diffuse + Specular
233115 003315 004650



맨 위로 이동하기

OpenGL 카테고리 내 다른 글 보러가기

댓글 남기기