Materials
실제 세계에서 사물들은 빛에 각자 다르게 반응한다.
- 철로된 사물과 너무로된 사물은 빛에 반응 정도가 다르다.
- 이에따라 specular 하이라이트도 다르게 반응한다.
- 이를 시뮬레이션하기위해 필요한게
material
속성
material
에 3가지 lighting 요소인ambient
,diffuse
,specular
를 정의할 수 있다.- 각 요소에 컬러를 지정하여, 객체의 컬러 출력을 세부적으로 제어할 수 있음.
shininess
컴포넌트를 추가하면, 지금 필요한 모든 속성을 가지게된다.
1
2
3
4
5
6
7
8
9
#version 330 core
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
uniform Material material;
material
의 속성을 위와 같이 struct로 저장할 수 있다. 그리고 uniform 변수로 접근한다.Phong
모델의 요소들에 대한 컬러 벡터 정의ambient
: 주변광에 대해 어떤 컬러를 반사할지 정의(보통 오브젝트의 컬러와 동일)diffuse
: 분산광에 대한 컬러 설정, 원하는 오브젝트의 컬러specular
: 반사광에 영향을 받아 생성되는 컬러 설정shininess
: 객체의 반사는 아무런 영향을 받지 않는다.
오브젝트의
material
을 정의하하면, 실세계의 재질을 시뮬레이션할 수 있다.- 테이블 <-이를 사용하여 시뮬레이션할 수 있음.
- 이런
material
속성을 설정하여 보기좋게 만드는것은 어려움.
Setting materials
- 이제 새로운 material 속성을 사용하여 lighting 계산을 해야한다.
- 각 속성들은 lightingColor와 곱해진다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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);
}
- glsl의 struct를 cpp코드에서 설정할 때, 아래 코드처럼 struct 이름의 접두사가 붙은 uniform 변수를 사용해야함
1
2
3
4
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);
- 이제 코드를 실행해보면 아래와 같을 것이다.
Light properties
- 위 이미지에서 오브젝트는 너무 밝음.
- 모든 요소의 컬러들이 모든 광원으로부터 완전하게 반사되기 때문.
- 광원은 ambient, diffuse, specular 컴포넌트마다 각각 세기가 다르다.
- 각 lighting 요소를 조절하는 세기 벡터를 선언해야한다.
- 빛의 속성을 위해 material struct와 비슷한 것을 만들어야한다.
1
2
3
4
5
6
7
8
9
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light light;
광원은 ambient, diffuse, specular 빛에 대해 다른 세기를 가진다.
ambient
: 일반적으로 작은 세기diffuse
: 일반적으로 우리가 원하는 정확한 컬러로 설정(밝은 흰색)specular
: 일반적으로 최대vec3(1.0)
- 추가적으로 빛의 위치벡터
material uniform과 마찬가지로 fragment shader를 수정해야한다.
1
2
3
4
vec3 ambient = light.ambient * material.ambient;
vec3 diffuse = light.diffuse * (diff * material.diffuse);
vec3 specular = light.specular * (spec * material.specular);
- 그런다음 응용프로그램에서 빛의 세기를 설정한다.
1
2
3
4
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);
- 이제 다음과 같이 약간 어두워졌다.
Different light colors
- 이제 빛의 속성에 쉽게 접근할 수 있으며, 컬러를 변경할 수있다.
- sin, glfwGetTime 함수를 통해 빛의 ambient, diffuse 컬러를 수정하여, 시간이 지남에 따라 빛의 컬러를 쉽게 수정할 수 있다.
1
2
3
4
5
6
7
8
9
10
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);