본문 바로가기

OpenGL Study

OpenGL "Materials"

[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