LearnOpenGL(9) - Materials

흑빡·2026년 6월 9일

그래픽스

목록 보기
30/40
post-thumbnail

shader에서 구조체 사용

#version 330 core
out vec4 FragColor;

in vec3 Normal;  
in vec3 FragPos;  
  
uniform vec3 lightPos; 
uniform vec3 viewPos; 
uniform vec3 lightColor;
uniform vec3 objectColor;

void main()
{
    // ambient
    float ambientStrength = 0.1;
    vec3 ambient = ambientStrength * lightColor;
  	
    // diffuse 
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;
    
    // specular
    float specularStrength = 0.5;
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);  
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
    vec3 specular = specularStrength * spec * lightColor;  
        
    vec3 result = (ambient + diffuse + specular) * objectColor;
    FragColor = vec4(result, 1.0);
} 

fragment shader의 원래 코드는 이랬음

3D materials parameter
이런거나
OpenGL Materials
이런 웹사이트를 보면

ambient, diffuse, specular는 RGB(A)값으로 vec3를 사용하고
shiness는 float을 사용하는걸 알 수 있음

즉, 우리가 설정한 object color에서 색상을 결정짓는게 아니라
각 ambient, diffuse, specular에서 각각 적용되는 색상이 따로 존재한다는거임

이런 머티리얼을 사용하려면서 fragment shader를 약간 수정해줘야함

#version 330 core
struct Material
{
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float shininess;
};

uniform Material mat;

먼저 이런 struct를 만들어줌
GLSL, 쉐이더 내부에서도 이렇게 구조체를 선언해서
그걸 uniform으로 외부에 노출시켜 값을 지정해서 사용하도록 할 수 있음

그리고
위의 웹사이트 등을 기반으로 머티리얼을 설정할거라,
color가 필요한곳에 직접 머티리얼의 변수들을 사용해주면 됨

#version 330 core
struct Material
{
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float shininess;
};

out vec4 FragColor;

in vec3 FragPos;
in vec3 Normal;
in vec3 LightPos;

uniform vec3 viewPos;
uniform Material mat;

void main()
{
    // ambient
    vec3 ambient = mat.ambient * lightColor;

    // diffuse 
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(LightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * mat.diffuse * lightColor;

    // specular
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), mat.shininess);
    vec3 specular = mat.specular * spec * lightColor;

    vec3 result = (ambient + diffuse + specular);
    FragColor = vec4(result, 1.0);
}

이렇게 코드가 바뀌게 됨

사용

이 brass라는 머티리얼을 사용해볼거임

대충 이런 재질임

//material 설정
normalCubeShader.use();
normalCubeShader.setVec3("mat.ambient", glm::vec3(0.329412f, 0.223529f, 0.027451f));
normalCubeShader.setVec3("mat.diffuse", glm::vec3(0.780392f, 0.568627f, 0.113725f));
normalCubeShader.setVec3("mat.specular", glm::vec3(0.992157f, 0.941176f, 0.807843f));
normalCubeShader.setFloat("mat.shininess", 27.8974f);

이렇게 머티리얼을 설정해줌

이게 맞음?ㅋㅋㅋㅋㅋㅋㅋㅋㅋ

빛도 세기를 가지고 있음

ambient나 diffuse나 specular에 적용될 세기는 다 달라야함

void main()
{
    // ambient
    vec3 ambient = mat.ambient * lightColor;

    // diffuse 
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(LightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * mat.diffuse * lightColor;

    // specular
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), mat.shininess);
    vec3 specular = mat.specular * spec * lightColor;

    vec3 result = (ambient + diffuse + specular);
    FragColor = vec4(result, 1.0);
}

근데 우리 fragment shader를 보면
다 일정한 lightColor를 곱하주고 있는걸 볼 수 있음

따라서 이를 위한 struct도 하나 만들어주는게 좋음
전체 fragment shader는 아래처럼 바뀜

#version 330 core
struct Material
{
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float shininess;
};

struct Light
{
    vec3 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

out vec4 FragColor;

in vec3 FragPos;
in vec3 Normal;

uniform vec3 viewPos;
uniform Material mat;
uniform Light light;


void main()
{
    // ambient
    vec3 ambient = mat.ambient * light.ambient;

    // diffuse 
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(light.position - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * mat.diffuse * light.diffuse;

    // specular
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), mat.shininess);
    vec3 specular = mat.specular * spec * light.specular;

    vec3 result = (ambient + diffuse + specular);
    FragColor = vec4(result, 1.0);
}

보면 light 구조체를 만들어서 사용하고 있다는걸 알 수 있음

그리고 main.cpp도 아래처럼 바뀜

렌더링로직 밖
//....

//material 설정
normalCubeShader.use();
normalCubeShader.setVec3("mat.ambient", glm::vec3(0.329412f, 0.223529f, 0.027451f));
normalCubeShader.setVec3("mat.diffuse", glm::vec3(0.780392f, 0.568627f, 0.113725f));
normalCubeShader.setVec3("mat.specular", glm::vec3(0.992157f, 0.941176f, 0.807843f));
normalCubeShader.setFloat("mat.shininess", 27.8974f);
//light 설정
normalCubeShader.setVec3("light.ambient", glm::vec3(0.8f));
normalCubeShader.setVec3("light.diffuse", glm::vec3(0.5f, 0.5f, 0.5f));
normalCubeShader.setVec3("light.specular", glm::vec3(1.0f, 1.0f, 1.0f));

//...

while (!glfwWindowShouldClose(window))
{
    //...

    //light position수정
    normalCubeShader.setVec3("light.position", lightPos);
    normalCubeShader.setVec3("viewPos", camera.Position);

}

좀 비슷하네잉~

profile
그래픽스 하는 퍼그

0개의 댓글