โ Phong ์กฐ๋ช ๋ชจ๋ธ
OpenGL์์์ ์กฐ๋ช
์ ํ์ค์ ๋จ์ํํ ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ๊ทผ์ฌํํ๋ค. ์ด ๋ชจ๋ธ๋ค์ ์ฒ๋ฆฌํ๊ธฐ ํจ์ฌ ์ฝ๊ณ ํ์ค๊ณผ ๋น๊ต์ ์ ์ฌํ๊ฒ ๋ณด์ธ๋ค.
OpenGl์์ ์ฃผ๋ก ์ฌ์ฉํ๋ ์กฐ๋ช
๋ชจ๋ธ ์ค Phong ์กฐ๋ช
๋ชจ๋ธ์ด ์๋ค. Phong ์กฐ๋ช
๋ชจ๋ธ์ ์ฃผ์ ๊ตฌ์ฑ ์์๋ Ambient(์ฃผ๋ณ๊ด, ํ๊ฒฝ๊ด), Diffuse(๋ถ์ฐ๊ด, ๋๋ฐ์ฌ๊ด), Specular(๋ฐ์ฌ๊ด, ์ ๋ฐ์ฌ๊ด) ์กฐ๋ช
์ผ๋ก ์ด๋ฃจ์ด์ ธ ์๋ค.

โ Ambient Lighting
์ด๋์ด ํ๊ฒฝ์์๋ ๋น์ ์ฐ๋ํ์ฌ ์ค๋ธ์ ํธ์ ๊ฐ์ ์ ์ผ๋ก ์ํฅ์ ์ค๋ค. ์ด๋ฅผ ์๋ฎฌ๋ ์ด์
ํ๊ธฐ ์ํด ์ค๋ธ์ ํธ Fragment์ ์ต์ข
์ปฌ๋ฌ์ ์ถ๊ฐํ ์์ ์์ (๋น) ์ปฌ๋ฌ๋ฅผ ์ฌ์ฉํ๋ค. ์ด๋ ์ง์ ์ ์ธ ๊ด์์ด ์๋ค๊ณ ํ๋๋ผ๋ ํญ์ ํผ์ง๋ ๋น์ด ์๋ ๊ฒ์ฒ๋ผ๋ณด์ด๊ฒ ๋ง๋ ๋ค.
void main()
{
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
vec3 result = ambient * objectColor;
FragColor = vec4(result, 1.0);
}
์ด ์ค๋ธ์ ํธ๋ ์ด๋ก์ง๋ง Ambient Lighting์ด ์ ์ฉ๋์๊ธฐ ๋๋ฌธ์ ์์ ํ ์ด๋ก์ง๋ ์๋ค.
โ Diffuse Lighting
๊ด์๊ณผ ์ค๋ธ์ ํธ๊ฐ ์ด๋ฃจ๋ ๊ฐ๋์ ๋ฐ๋ผ ๋น์ ์ํฅ์ด ๋ฌ๋ผ์ง๋ค. ๊ด์์์ ๋์จ ๋น์ด ์ค๋ธ์ ํธ์ ์์ง์ผ๋ก ํฅํ๋ค๋ฉด ๋น์ ๊ฐ์ฅ ๋ง์ ์ํฅ์ ์ค๋ค. Diffuse Lighting์ ๊ณ์ฐํ๊ธฐ ์ํด์๋ Vertex์ ๋ฉด์ ์์ง์ธ Normal Vector (๋ฒ์ ๋ฒกํฐ)์ The directed light ray (๋ฐฉํฅ์ ๊ฐ์ง ๊ด์ ) : ๋น์์ Fragment๋ก ํฅํ๋ ๋ฐฉํฅ ๋ฒกํฐ๊ฐ ํ์ํ๋ค.
โ ๋ฒ์ ๋ฒกํฐ
๋ฒ์ ๋ฒกํฐ๋ Vertex์ ๋ฉด์ ์์ง์ธ (๋จ์) ๋ฒกํฐ์ด๋ค. Vertex๋ ๊ทธ์ ํ๋์ ์ ์ด๊ธฐ ๋๋ฌธ์ Vertex์ ๋ฉด์ ์์๋ด๊ธฐ ์ํด ์ฃผ๋ณ์ Vertex๋ค์ ์ฌ์ฉํ์ฌ ๋ฒ์ ๋ฒกํฐ๋ฅผ ๊ตฌํ๋ค. (์ฌ๊ธฐ์๋ ์์์
์ผ๋ก ๋์
)
float vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
};
- Vertex Shader
Vertex ๋ฐฐ์ด์ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํ์ผ๋ฏ๋ก Lighting Vertex Shader๋ฅผ ์์ ํ๋ค.
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
...
Vertex Attribute Pointer์ ์ Vertex ๋ฐฐ์ด์ ํฌ๊ธฐ๋ฅผ ๋ฐ์ํ๋ค.
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
๋ชจ๋ ๋น์ ๋ํ ๊ณ์ฐ์ Fragment Shader์์ ์๋ฃ๋๋ฏ๋ก Vertex Shader์ ๋ฒ์ ๋ฒกํฐ๋ฅผ Fragement Shader์ ์ ๋ฌํ๋ค.
out vec3 Normal;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
Normal = aNormal;
}
- Fragment Shader
Fragment Shader์ ํด๋นํ๋ ์ ๋ ฅ ๋ณ์๋ฅผ ์ ์ธํ๋ค.
in vec3 Normal;
โ Diffuse Color ๊ณ์ฐ
์ด์ ๊ฐ Vertex์ ๋ํ ๋ฒ์ ๋ฒกํฐ๋ฅผ ๊ฐ์ง๊ฒ ๋์๊ณ , ๋น์ ๋ฐฉํฅ ๋ฒกํฐ๋ฅผ ๊ตฌํ๊ธฐ ์ํด Fragment ์์น ๋ฒกํฐ์ ๋น์ ์์น ๋ฒกํฐ๊ฐ ํ์ํ๋ค.
- ๋ณ์ ์ ์ธ
๋น์ ์์น๋ ํ๋์ ์ ์ ๋ณ์์ด๊ธฐ ๋๋ฌธ์ Fragment Shader์ uniform์ผ๋ก ์ ์ธํ๋ค.
uniform vec3 lightPos;
๋ ๋ ๋ฃจํ์์ ํด๋น uniform์ ์ ๋ฐ์ดํธํ๋ค.
glUniform3fv(glGetUniformLocation(lightingShader.ID, "lightPos", 1, lightPos);
์ฐ๋ฆฌ๋ ๋ชจ๋ ๋น์ ๋ํ ๊ณ์ฐ์ World Space์์ ํ ๊ฒ์ด๋ฏ๋ก World Space์ ์๋ Vertex ์์น๊ฐ ํ์ํ๋ค. ์ด๋ Vertex ์์น Attribute๋ฅผ model ํ๋ ฌ๊ณผ ๊ณฑํ์ฌ World Space ์ขํ๋ก ๋ณํํ ์ ์๋ค.
Vertex Shader์์ ์ถ๋ ฅ ๋ณ์ FragPos๋ฅผ ์ ์ธํ๊ณ ๊ณ์ฐํ๋ค.
out vec3 FragPos;
out vec3 Normal;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
FragPos = vec3(model * vec4(aPos, 1.0));
Normal = aNormal;
}
Fragment Shader์ ํด๋นํ๋ ์ ๋ ฅ ๋ณ์๋ฅผ ์ ์ธํ๋ค.
in vec3 FragPos;
์ด์ ํ์ํ ๋ชจ๋ ๋ณ์๋ค์ด ์ค์ ๋์๊ณ Fragment Shader์์ ๋น์ ๋ํ ๊ณ์ฐ์ ์์ํ ์ ์๋ค.
- ๊ณ์ฐ
๊ด์์ ์์น ๋ฒกํฐ์์ Fragment์ ์์น ๋ฒกํฐ๋ฅผ ๋นผ์ ๋น์ ๋ฐฉํฅ ๋ฒกํฐ๋ฅผ ๊ตฌํ๊ณ ์ ๊ทํํ๋ค.
* Lambertian ๋ฐ์ฌ ๋ชจ๋ธ์์๋ Fragment์์ ๊ด์์ ํฅํ๋ ๋ฐฉํฅ ๋ฒกํฐ๋ฅผ ์ฌ์ฉํ๋ค.
* ๋น ๊ณ์ฐ ์ ํฌ๊ธฐ๋ ์๊ด ์๊ณ ๋ฐฉํฅ๋ง ํ์ํ๊ธฐ ๋๋ฌธ์ ์ ๊ทํํ์ฌ ๋จ์ ๋ฒกํฐ๋ก ์ํํ๋ค.
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
๋ค์์ผ๋ก ๋ฒ์ ๋ฒกํฐ์ ๋ฐฉํฅ ๋ฒกํฐ๋ฅผ ๋ด์ ํ์ฌ ์ค์ Diffuse ํจ๊ณผ๋ฅผ ๊ณ์ฐํ๋ค. ์ต์ข ์ ์ผ๋ก ๋ ๋ฒกํฐ ์ฌ์ด์ ๊ฐ๋๊ฐ ํด์๋ก Diffuse ์์๋ ์ด๋์์ง๋ค.
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
๋ ๋ฒกํฐ ์ฌ์ด์ ๊ฐ๋๊ฐ 90๋ ๋ณด๋ค ํฌ๋ฉด ๋ด์ ์ ๊ฒฐ๊ณผ๊ฐ ์์๊ฐ ๋์ด ์์ Diffuse ์์๋ฅผ ๊ฐ์ง๊ฒ ๋๋ค. ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด max ํจ์๋ฅผ ์ฌ์ฉํ์ฌ Diffuse ์์์ ์ปฌ๋ฌ๊ฐ ์์ ๊ฐ์ ๊ฐ์ง ์ ์๊ฒ ํ๋ค.
- ์ ์ฉ
๊ณ์ฐํ Ambient์ Diffuse ์์๋ฅผ ์ฌ์ฉํ์ฌ ์ต์ข Fragment์ ์ปฌ๋ฌ๋ฅผ ๊ฒฐ์ ํ๋ค.
vec3 result = (ambient + diffuse) * objectColor;
FragColor = vec4(result, 1.0);
โ ๊ฒฐ๊ณผ

โ ์์ค ์ฝ๋
โ ๋ฒ์ ํ๋ ฌ
ํ์ฌ๋ ๋ฒ์ ๋ฒกํฐ๋ฅผ Vertex Shader์์ Fragment Shader๋ก ๋ณด๋ด๊ธฐ๋ง ํ๋ค. ํ์ง๋ง Frament Shader์์ ์ํํ ๊ณ์ฐ๋ค์ ๋ชจ๋ World Space ์ขํ์์ ์ํ๋๋ฏ๋ก ๋ฒ์ ๋ฒกํฐ๋ฅผ World Space ์ขํ๋ก ๋ณํํด์ผ ํ์ง ์์๊น? ๊ธฐ๋ณธ์ ์ผ๋ก๋ ๋ง๋ค. ํ์ง๋ง ์ด๋ฅผ ๋จ์ํ model ํ๋ ฌ๊ณผ ๊ณฑํ๋ ๊ฒ๋ณด๋ค ๋ณต์กํ๋ค.
๋จผ์ ๋ฒ์ ๋ฒกํฐ๋ ์ค์ง ๋ฐฉํฅ ๋ฒกํฐ๋ก ๊ณต๊ฐ์์ ํน์ ํ ์์น๋ฅผ ๋ํ๋ด์ง ์๋๋ค. ๋ํ ๋ฒ์ ๋ฒกํฐ๋ ๋์ฐจ ์ขํ (w ์์)๋ฅผ ๊ฐ์ง๊ณ ์์ง ์๋ค. ์ด๋ ์ด๋ ๋ณํ์ด ๋ฒ์ ๋ฒกํฐ์ ์๋ฌด ํจ๊ณผ๊ฐ ์๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฒ์ ๋ฒกํฐ์ model ํ๋ ฌ์ ๊ณฑํ๊ณ ์ถ๋ค๋ฉด model ํ๋ ฌ ์ข์ธก ์๋จ 3x3 ํ๋ ฌ์ ์ทจํ์ฌ ์ด๋ ํ๋ ฌ์ ์ผ๋ถ๋ฅผ ์ง์์ผ ํ๋ค. ์ฐ๋ฆฌ๊ฐ ๋ฒ์ ๋ฒกํฐ์ ์ ์ฉํ ๊ฒ์ ์ค์ผ์ผ๊ณผ ํ์ ๋ณํ์ด๋ค.
๋ ๋ฒ์งธ๋ก model ํ๋ ฌ์ด ๋ถ๊ท ์ผ ์ค์ผ์ผ์ ์ํํ๋ฉด Vertex๋ค์ด ์์ ๋์ด ๋ฒ์ ๋ฒกํฐ๊ฐ ๋ ์ด์ ํด๋น ๋ฉด๊ณผ ์์ง์ด ๋์ง ์๋๋ค. ๋ฐ๋ผ์ ์ด model ํ๋ ฌ๋ก ๋ฒ์ ๋ฒกํฐ๋ฅผ ๋ณํํ ์ ์๋ค.

์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ํน๋ณํ ๋ฒ์ ๋ฒกํฐ์ ๋ง์ถฐ ๋ง๋ค์ด์ง ๋ค๋ฅธ model ํ๋ ฌ์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค. ์ด ํ๋ ฌ์ ๋ฒ์ ํ๋ ฌ์ด๋ผ๊ณ ๋ถ๋ฆฌ๋ฉฐ ๋ฒ์ ๋ฒกํฐ๋ฅผ ์๋ชป๋ ํํ๋ก ์ค์ผ์ผ๋งํ๋ ํจ๊ณผ๋ฅผ ์ง์์ฃผ๋ ์ฐ์ฐ์ ์ฌ์ฉํ๋ค.
Vertex Shader์์ inverse, transpose ํจ์๋ฅผ ์ฌ์ฉํด ๋ฒ์ ํ๋ ฌ์ ์์ฑํ ์ ์๋ค. ์ด๋ ํ๋ ฌ์ 3x3 ํ๋ ฌ๋ก ๋ณํํ๋ฏ๋ก ์ด๋ ์์ฑ์ ์์ง๋ง vec3 ๋ฒ์ ๋ฒกํฐ์ ๊ณฑ์
์ ํ ์ ์๋ค.
// ๋ฒ์ ํ๋ ฌ
Normal = mat3(transpose(inverse(model))) * aNormal;
ํ์ฌ๋ ์ค๋ธ์ ํธ์ ์ด๋ค ์ค์ผ์ผ ์ฐ์ฐ๋ ์ํํ์ง ์์๊ธฐ ๋๋ฌธ์ ๊ด์ฐฎ์ง๋ง ๋์ค์ ๋ถ๊ท ์ผ ์ค์ผ์ผ์ ์ํํ๋ค๋ฉด ๋ฒ์ ๋ฒกํฐ์ ๋ฐ๋์ ์ด ๋ฒ์ ํ๋ ฌ์ ๊ณฑํด์ฃผ์ด์ผ ํ๋ค.
* ์ญํ๋ ฌ๋ก ๋ณํํ๋ ๊ฒ์ ๋น์ฉ์ด ๋ง์ด ๋๋ ์ฐ์ฐ์ด๋ฏ๋ก CPU์์ ๋ฒ์ ํ๋ ฌ์ ๊ณ์ฐํ๊ณ ๋ ๋๋ง ํ๊ธฐ ์ ์ uniform์ ํตํด Shader๋ก ์ ๋ฌํ๋๋ก ํ์. (model ํ๋ ฌ์ฒ๋ผ)
โ Specular Lighting
Diffuse Lighting๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก Specular Lighting์ ๋น์ ๋ฐฉํฅ ๋ฒกํฐ์ ์ค๋ธ์ ํธ์ ๋ฒ์ ๋ฒกํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ์ง๋ง, ํ๋ ์ด์ด๊ฐ Fragment๋ฅผ ๋ฐ๋ผ๋ณด๊ณ ์๋ ๋ฐฉํฅ์ ๋ํ View ๋ฒกํฐ๋ ๊ธฐ๋ฐ์ผ๋ก ํ๋ค. ์ค๋ธ์ ํธ์ ๋ฉด์ ๊ฑฐ์ธ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ์ด ๋ฉด์์ ๋ฐ์ฌ๋์ด์ง ๋น์ ๋ณด๋ Specular Lighting์ ๊ฐ์ฅ ์ผ ๋น์ผ๊ฒ์ด๋ค.

๋ฒ์ ๋ฒกํฐ๋ฅผ ๊ธฐ์ค์ผ๋ก ๋น์ ๋ฐฉํฅ์ ๋ฐ์ฌํ์ฌ ๋ฐ์ฌ ๋ฒกํฐ๋ฅผ ๊ณ์ฐํ ๋ค์ ์ด ๋ฐ์ฌ ๋ฒกํฐ์ View ๋ฒกํฐ ์ฌ์ด์ Angular Distance (๊ฐ ๊ฑฐ๋ฆฌ)๋ฅผ ๊ณ์ฐํ๋ค. ๋ ๋ฒกํฐ ์ฌ์ด์ ๊ฐ์ด ๊ฐ๊น์ธ์๋ก Specular Light์ ๊ฐ๋๋ ๊ฐํด์ง๋ค.
View ๋ฒกํฐ๋ Specular Lighting์ ํ์ํ ๋ณ์๋ก Viewer์ World Space ์์น์ Fragment๋ค์ ์์น๋ฅผ ์ฌ์ฉํ์ฌ ๊ณ์ฐํ ์ ์๋ค. ๊ทธ๋ฐ ๋ค์ Specular์ ๊ฐ๋๋ฅผ ๊ณ์ฐํ๊ณ ์ด๋ฅผ ๋น์ ์์๊ณผ ๊ณฑํ์ฌ Ambient, Diffuse ์์์ ์ถ๊ฐํ๋ค.
Viewer์ World Space ์ขํ๋ฅผ ์ป๊ธฐ ์ํด์ ์นด๋ฉ๋ผ ์ค๋ธ์ ํธ(Viewer)์ ์์น ๋ฒกํฐ๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค. ์ด์ Fragment Shader์ ๋ค๋ฅธ uniform์ ์ถ๊ฐํ๊ณ ํด๋น ์นด๋ฉ๋ผ ์์น ๋ฒกํฐ๋ฅผ Fragment Shader์ ์ ๋ฌํ๋ค.
// Fragment Shader
uniform vec3 viewPos;
// main
glUniform3fv(glGetUniformLocation(lightingShader.ID, "viewPos"), 1, &(camera.Position)[0]);
์ด์ ํ์ํ ๋ชจ๋ ๋ณ์๊ฐ ์ค๋น๋์์ผ๋ฏ๋ก Specular ์ธ๊ธฐ๋ฅผ ๊ณ์ฐํ ์ ์๋ค.
float specularStrength = 0.5f;
๊ทธ ๋ค์ View ๋ฐฉํฅ ๋ฒกํฐ์ ํด๋น ๋ฐ์ฌ ๋ฒกํฐ๋ฅผ ๊ณ์ฐํ๋ค.
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
* lightDir ๋ฒกํฐ๋ Fragment๋ก๋ถํฐ ๊ด์์ผ๋ก ํฅํ๋ ๋ฒกํฐ์ด๋ฏ๋ก reflect ํจ์์์ ์ฌ์ฉํ๊ธฐ ์ํด ๋ถํธ๋ฅผ ๋ฐ๋๋ก ๋ฐ๊พธ์ด ์ฌ์ฉํ๋ค.
์ต์ข Specular ์์๋ฅผ ๊ณ์ฐํ๋ค.
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = specularStrength * spec * lightColor;
๋จผ์ View ๋ฒกํฐ์ Reflect ๋ฒกํฐ๋ฅผ ๋ด์ ํ ๋ค 32์ ๊ณฑ ํ๋ค. ์ด ๊ฐ์ด ๋์ ์๋ก ๋น์ ์ฃผ๋ณ์ ํผ์ง๊ฒ ํ์ง ์๊ณ ๋ฐ์ฌํ๋ค.
* ๋ด์ ํ ๊ฐ์ด ์์๊ฐ ๋์ง ์๋๋ก ํ๋ค.
๋ง์ง๋ง์ผ๋ก ์ด ์์๋ฅผ Ambient์ Diffuse ์์์ ์ถ๊ฐํ๊ณ ์ค๋ธ์ ํธ ์ปฌ๋ฌ์ ๊ฒฐ๊ณผ๊ฐ์ ๊ณฑํด ํผํฉํ๋ค.
vec3 result = (ambient + diffuse + specular) * objectColor;
FragColor = vec4(result, 1.0);
โ ๊ฒฐ๊ณผ

โ ์ต์ข ์์ค ์ฝ๋
- main
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <Shader.h>
#include <Camera.h>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow* window);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;
// timing
float deltaTime = 0.0f;
float lastFrame = 0.0f;
// lighting
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
int main()
{
// ---------- [ 1. GLFW, GLAD ์ธํ
] ----------
// GLFW ์ด๊ธฐํ ๋ฐ ์ค์
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// GLFW ์๋์ฐ ์์ฑ
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// ์ฝ๋ฐฑ ํจ์๋ค ๋ฑ๋ก
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// ๋ง์ฐ์ค ์ปค์ ์จ๊ธฐ๊ธฐ
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// GLAD - OpenGL ํจ์ ํฌ์ธํฐ๋ฅผ ๋ก๋
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// ์
ฐ์ด๋ ํ๋ก๊ทธ๋จ ๋น๋ ๋ฐ ์ปดํ์ผ
Shader lightingShader("Shaders/colors.vs", "Shaders/colors.fs");
Shader lightCubeShader("Shaders/light_cube.vs", "Shaders/light_cube.fs");
// ---------- [ 2. ์ ์ ๋ฐ์ดํฐ ์
๋ ฅ / ์ ์ ์์ฑ ๊ตฌ์ฑ ] ----------
float vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
};
// ๊น์ด ํ
์คํธ ํ์ฑํ
glEnable(GL_DEPTH_TEST);
// VAO, VBO ์์ฑ
// VAO: VBO์ ์ ์ ์์ฑ ํฌ์ธํฐ์ ์ํ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ๊ฐ์ฒด
// VBO: GPU ๋ฉ๋ชจ๋ฆฌ์ ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ๋ฒํผ ๊ฐ์ฒด
unsigned int VBO, cubeVAO;
glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &VBO);
// ์ ์ ๋ฐฐ์ด ๊ฐ์ฒด(VAO) ๋ฐ์ธ๋ฉ
glBindVertexArray(cubeVAO);
// ์ ์ ๋ฒํผ ๊ฐ์ฒด(VBO)๋ฅผ ๋ฐ์ธ๋ฉ
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// ๋ฐ์ธ๋ฉ๋ ๋ฒํผ ๊ฐ์ฒด์ vertices ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌํ๊ณ ,๋ฒํผ ๊ฐ์ฒด์ ํฌ๊ธฐ์ ๋ฐ์ดํฐ ์ค์
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Position Attribute ๊ตฌ์ฑ
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// Normal Attribute ๊ตฌ์ฑ
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// ๊ด์ ํ๋ธ์ฉ VAO ์์ฑ
unsigned int lightCubeVAO;
glGenVertexArrays(1, &lightCubeVAO);
glBindVertexArray(lightCubeVAO);
// VBO ๋ฐ์ธ๋๋ง ํ๋ฉด ๋๋ค (์ด๋ฏธ ๋ฐ์ดํฐ ํฌํจ๋์ด ์์)
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// ---------- [ 3. ๋ ๋ ๋ฃจํ ] ----------
while (!glfwWindowShouldClose(window))
{
// ํ๋ ์ ์ฌ์ด deltaTime ์ธก์
float currentFrame = static_cast<float>(glfwGetTime());
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
// ์
๋ ฅ ์ฒ๋ฆฌ
processInput(window);
// ๋ฐฐ๊ฒฝ ๋ ๋
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Uniform ๋ณ์ ํ ๋น
lightingShader.use();
//lightingShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
glUniform3f(glGetUniformLocation(lightingShader.ID, "objectColor"), 1.0f, 0.5f, 0.31f);
//lightingShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
glUniform3f(glGetUniformLocation(lightingShader.ID, "lightColor"), 1.0f, 1.0f, 1.0f);
//lightingShader.setVec3("lightPos", lightPos);
glUniform3fv(glGetUniformLocation(lightingShader.ID, "lightPos"), 1, &lightPos[0]);
//lightingShader.setVec3("viewPos", camera.Position);
glUniform3fv(glGetUniformLocation(lightingShader.ID, "viewPos"), 1, &(camera.Position)[0]);
// View / Projection ๋ณํ
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glm::mat4 view = camera.GetViewMatrix();
//lightingShader.setMat4("projection", projection);
glUniformMatrix4fv(glGetUniformLocation(lightingShader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
//lightingShader.setMat4("view", view);
glUniformMatrix4fv(glGetUniformLocation(lightingShader.ID, "view"), 1, GL_FALSE, glm::value_ptr(view));
// World ๋ณํ
glm::mat4 model = glm::mat4(1.0f);
//lightingShader.setMat4("model", model);
glUniformMatrix4fv(glGetUniformLocation(lightingShader.ID, "model"), 1, GL_FALSE, glm::value_ptr(model));
// ํ๋ธ ๋ ๋
glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
// ๊ด์ ํ๋ธ ๋ ๋
lightCubeShader.use();
//lightCubeShader.setMat4("projection", projection);
glUniformMatrix4fv(glGetUniformLocation(lightCubeShader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
//lightCubeShader.setMat4("view", view);
glUniformMatrix4fv(glGetUniformLocation(lightCubeShader.ID, "view"), 1, GL_FALSE, glm::value_ptr(view));
model = glm::mat4(1.0f);
model = glm::translate(model, lightPos);
model = glm::scale(model, glm::vec3(0.2f)); // a smaller cube
//lightCubeShader.setMat4("model", model);
glUniformMatrix4fv(glGetUniformLocation(lightCubeShader.ID, "model"), 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(lightCubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
// ํ๋ก ํธ, ๋ฐฑ ๋ฒํผ ๊ต์ฒด
glfwSwapBuffers(window);
// ์ด๋ฒคํธ ์ฒ๋ฆฌ
glfwPollEvents();
}
// VAO, VBO ๋ฉ๋ชจ๋ฆฌ ํด์
glDeleteVertexArrays(1, &cubeVAO);
glDeleteVertexArrays(1, &lightCubeVAO);
glDeleteBuffers(1, &VBO);
// ์ฌ์ฉ๋ ๋ฆฌ์์ค ํด์ , ์ด๊ธฐํ ๋ฐ ์ ๋ฆฌ ์์
glfwTerminate();
return 0;
}
// ์ฌ์ฉ์ ์
๋ ฅ ์ฒ๋ฆฌ ํจ์
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime);
}
// ์๋์ฐ ์ฌ์ด์ฆ ๋ณ๊ฒฝ ์ฝ๋ฐฑ ํจ์
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
// ๋ง์ฐ์ค ์ด๋ ์ฝ๋ฐฑ ํจ์
void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
{
float xpos = static_cast<float>(xposIn);
float ypos = static_cast<float>(yposIn);
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos;
lastY = ypos;
camera.ProcessMouseMovement(xoffset, yoffset);
}
// ๋ง์ฐ์ค ํ ์ฝ๋ฐฑ ํจ์
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
camera.ProcessMouseScroll(static_cast<float>(yoffset));
}
- Vertex Shader
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
out vec3 FragPos;
out vec3 Normal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
FragPos = vec3(model * vec4(aPos, 1.0));
Normal = aNormal;
gl_Position = projection * view * vec4(FragPos, 1.0);
}
- Fragment 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);
}
- ๋งํฌ
'๐จ Graphics > ๐ต OpenGL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [OpenGL] Lighting Maps (0) | 2024.08.15 |
|---|---|
| [OpenGL] ๋จธํฐ๋ฆฌ์ผ (Material) (0) | 2024.08.12 |
| [OpenGL] ์นด๋ฉ๋ผ ์ค์ ๋ฐ ๋ณํ (์ด๋, ํ์ ) (0) | 2024.08.08 |
| [OpenGL] ์์ผ๊ฐ(FOV), ํ๋ฉด๋น(Aspect Ratio) (0) | 2024.08.08 |
| [OpenGL] 3์ฐจ์ ๊ฐ์ฒด ๋ ๋ 2 (0) | 2024.08.08 |