[MATERIALS]
1. Before
- 실제 세계에서 사물들은 빛에 각자 다르게 반응한다
: 철로 된 사물은 점토로 된 사물보다 반짝이고, 나무로 된 컨테이너는 철로 된 컨테이너가 빛에 반응하는 것과 반대로 빛에 반응하지 않는다
: 어떤 사물은 많은 양의 빛을 퍼지게 하지 않고 반사하기 때문에 결과적으로 작은 specular highlights를 만들고, 다른 어떤 사물은 빛을 많이 퍼지게 함으로써 큰 반지름을 가진 하이라이트를 만든다
- 이러한 특성 때문에, OpenGL에서 여러 유형의 object를 시뮬레이션 하려면 각 표면에 특정한 재료 특성을 정의해야한다
2. Shininess Component (광택 성분)
- (블로그에는 아직 정리하지 않았지만) 이전 파트에서 object의 시각적인 출력을 정의하기 위해 object와 빛의 색상을 지정했다
- object를 묘사할 때, ambient / diffuse / specular의 3가지 lighting component 각각에 대한 material color를 정의할 수 있다
: 각 component에 색상을 지정함으로써 object의 색상 출력을 세부적으로 제어할 수 있다
: 위 세 가지 색상에 shininess component를 추가하면 필요한 모든 material 특성을 얻을 수 있다
#version 330 core
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
uniform Material material;
- Fragment shader에서 object의 material 속성들을 저장하기 위해 struct를 생성한다
: 이것들은 각각의 uniform 값으로 저장할 수 있지만, struct로 저장하는 것이 조금 더 체계적이므로 struct를 생성해 사용한다
- struct의 layout을 정의하고, 새로 생성된 struct를 타입으로 사용하여 uniform변수를 선언한다
- Phong lighting의 각 component에 대한 color vector를 정의한다
- ambient material vector는 object가 ambient lighting에서 object의 표면이 어떤 색상을 반사할 것인지 정의한다
: 이 색상은 일반적으로 object 표면의 색상과 동일하다
- diffuse material vector는 ambient lighting과 마찬가지로 원하는 표면 색상으로 설정된다
- specular mateial vector는 specular highight의 색상을 표면에 설정한다
: 표면 특정 색상을 반영할 수도 있다
- shininess는 specular highlight의 퍼짐 정도, 반지름에 영향을 준다
- 위 코드 속 4개의 component를 사용해 다양한 실세계의 material들을 시뮬레이션 할 수 있다
- 위의 이미지는 실세계의 material들이 우리가 생성한 cube에서 어떤 효과를 내는지를 시각화한 이미지이다
- object의 material 속성을 정확히 지정함으로써 물체에 대한 인식을 바꾼다
- 가장 현실적인 결과를 위해서는 더 복잡한 model이 필요한데, 이는 'Model Loading' 챕터에서 설명할 예정이다
[SETTING MATERIALS]
1. Modify Fragment Shader
void main()
{
// ambient
vec3 ambient = lightColor * material.ambient;
// diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = lightColor * (diff * material.diffuse);
// specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = lightColor * (spec * material.specular);
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}
- 위에서 fragment shader에 uniform material struct를 생성했기 때문에 새로운 material 속성에 따라 lighting 계산을 변경할 수 있다
: 모든 material 변수들이 struct 안에 저장되어 있기 때문에 material uniform으로 각 변수에 접근할 수 있다
- 필요한 모든 곳에서 material struct의 모든 속성에 접근하는 것을 확인할 수 있다
- material 색상을 사용하여 최종 출력 색상을 계산한다
: object 각각의 material 속성들은 각각의 lighting component에 곱해진다
lightingShader.setVec3("material.ambient", 1.0f, 0.5f, 0.31f);
lightingShader.setVec3("material.diffuse", 1.0f, 0.5f, 0.31f);
lightingShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f);
lightingShader.setFloat("material.shininess", 32.0f);
- 적절한 uniform을 설정하여 application에 있는 object의 material을 설정할 수 있다
: GLSL의 struct는 uniform을 설정할 때 특별한 점이 없다
: strcut는 uniform 변수의 namespace 역할만 한다
: struct를 채우기 위해서 struct 이름을 접두사로 붙인 uniform 변수를 설정한다
- ambient/diffuse component를 원하는 object의 색상으로 설정하고, specular component를 중간 밝기 색상으로 설정한다
- shininess는 32로 유지한다
1-1. Result
2. Light Properties
- 지금까지 생성한 object는 너무 밝다
: ambient, diffuse, specular 색상이 모든 광원으로부터 완전히 반사되기 때문이다
- 광원은 ambient, diffuse, specular component마다 각각 세기가 다르다
: (아직 블로그에 정리하지 않았지만) 이전 파트에서는 ambien 세기와 specular 세기를 strength 값을 통해 다르게 함으로써 해결했다
: 이번 파트에서는 각 lighting component의 세기 vector를 지정해서 사용한다
vec3 ambient = vec3(1.0) * material.ambient;
vec3 diffuse = vec3(1.0) * (diff * material.diffuse);
vec3 specular = vec3(1.0) * (spec * material.specular);
- lightcolor를 vec3로 시각화한 코드이다
- 각 object의 material 속성들은 각 light component들의 가장 센 값을 return하게 된다
: vec3(1.0) 값은 광원에 대해 각각 영향을 받을 수 있다 (이것이 일반적으로 우리가 원하는 것이다)
- 위 코드에서 object의 ambient component는 완전히 object의 색상에 영향을 미치고 있다
vec3 ambient = vec3(0.1) * material.ambient;
- ambient component는 최종 색상에 많은 영향을 줄 필요가 없기 때문에 빛의 ambient 세기를 낮추어 ambient 색상을 제한할 수 있다
: 동일한 방식으로 광원의 diffuse, specular 세기를 조절할 수 있다
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light light;
- 빛의 속성을 위해 material struct와 비슷한 형태의 light struct를 생성한다
- 광원은 ambient, diffuse, specular 빛에 대해 다른 세기를 가지고 있다
: ambient 빛은 일반적으로 작은 세기로 설정된다
: diffuse component는 일반적으로 사용자가 원하는 정확한 색상으로 설정한다 (보통 밝은 흰색으로 설정한다)
: specular component는 일반적으로 최대한의 세기로 빛나는 vec3(1.0) 값으로 유지된다
- 빛의 위치 vector를 light struct에 추가한다
vec3 ambient = light.ambient * material.ambient;
vec3 diffuse = light.diffuse * (diff * material.diffuse);
vec3 specular = light.specular * (spec * material.specular);
- material uniform과 마찬가지로 light uniform을 사용해 fragment shader를 수정한다
lightingShader.setVec3("light.ambient", 0.2f, 0.2f, 0.2f);
lightingShader.setVec3("light.diffuse", 0.5f, 0.5f, 0.5f); // darken diffuse light a bit
lightingShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f);
- light uniform을 사용하여 application에서 빛의 세기를 설정한다
2-1. Result
3. Different Light Colors
glm::vec3 lightColor;
lightColor.x = sin(glfwGetTime() * 2.0f);
lightColor.y = sin(glfwGetTime() * 0.7f);
lightColor.z = sin(glfwGetTime() * 1.3f);
glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f);
glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f);
lightingShader.setVec3("light.ambient", ambientColor);
lightingShader.setVec3("light.diffuse", diffuseColor);
- 앞서 공부한 sin, glfwGetTime 함수를 통해 빛의 ambient, diffuse 색상을 수정함으로써 시간이 지남에 따라 빛의 색상을 변경할 수 있다
'OpenGL Study' 카테고리의 다른 글
OpenGL "Light Casters" (0) | 2023.01.20 |
---|---|
OpenGL "Lighting Maps" (0) | 2023.01.12 |
OpenGL "Colors" (0) | 2023.01.06 |
OpenGL "Textures" (0) | 2023.01.06 |
OpenGL "Camera" (0) | 2022.12.06 |