Home [learn-opengl] Lighting: Materials
Post
Cancel

[learn-opengl] Lighting: Materials

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

전체 코드

출처

Materials

This post is licensed under CC BY 4.0 by the author.

[learn-opengl] Lighting: Basic Lighting

[learn-opengl] Lighting: Lighting maps