โ Lighting Map
์ค์ ์ธ๊ณ์ ๊ฐ์ฒด๋ค์ ์ผ๋ฐ์ ์ผ๋ก ์ฌ๋ฌ ์ฌ์ง(Material)๋ก ์ด๋ฃจ์ด์ ธ ์์ผ๋ฉฐ ๊ฐ ๋ถ๋ถ๋ง๋ค ๋ค๋ฅธ ์ฌ์ง ์์ฑ์ ๊ฐ์ง๊ณ ์๋ค. ๋ฐ๋ผ์ Diffuse, Specular Map์ ์ด์ฉํ์ฌ Material ์์คํ
์ ํ์ฅํ๊ณ ๊ฐ์ฒด๋ฅผ ์ข ๋ ์ ํํ๊ฒ ๋ฌ์ฌํ ์ ์๊ฒ ํ๋ค.
โ Diffuse Map
๊ฐ์ฒด์ ๊ฐ ๊ฐ๋ณ Fragment์ ๋ํด Diffuse Color๋ฅผ ์ค์ ํ ์ ์๋ ๋ฐฉ๋ฒ, ์ฆ Fragment์ ๊ฐ์ฒด ์ ์์น์ ๋ฐ๋ผ ์์ ๊ฐ์ ๊ฐ์ ธ์ฌ ์ ์๋ ์์คํ
์ด ํ์ํ๋ค.
์ด๊ฒ์ ํ
์ค์ฒ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๊ฐ์ ์๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค. ๊ฐ์ฒด๋ฅผ ๊ฐ์ผ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ์ฌ Fragment๋ณ๋ก ๊ณ ์ ํ ์์ ๊ฐ์ ์ป๋ ๊ฒ์ด๋ค. ์กฐ๋ช
์ด ์๋ ์ฅ๋ฉด์์ ์ด๊ฒ์ ์ผ๋ฐ์ ์ผ๋ก ํ์ฐ ๋งต(Diffuse Map)์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
ํ์ฐ ๋งต์ ์ค๋ช
ํ๊ธฐ ์ํด ๋ค์ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋ค.

ํ
์ค์ฒ๋ฅผ Material Struct ๋ด๋ถ์ sampler2D๋ก ์ ์ฅํ๊ณ ์ด์ ์ ์ ์ํ vec3 diffuse ์ปฌ๋ฌ๋ฅผ diffuse map์ผ๋ก ์์ ํ๋ค.
* sampler2D๋ ๋ถํฌ๋ช
ํ์
(Opaque Type)์ด๋ผ๊ณ ๋ถ๋ฆฌ๋ฉฐ, ์ด๋ ์ฐ๋ฆฌ๊ฐ ์ด๋ฌํ ํ์
์ ์ธ์คํด์คํํ ์ ์๊ณ , ๋จ์ง ์ ๋ํผ์ผ๋ก๋ง ์ ์ํ ์ ์์์ ์๋ฏธํ๋ค. ๋ง์ฝ ์ด ๊ตฌ์กฐ์ฒด๊ฐ ์ ๋ํผ์ด ์๋ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก(์๋ฅผ ๋ค์ด ํจ์ ๋งค๊ฐ๋ณ์๋ก) ์ธ์คํด์คํ๋๋ค๋ฉด, GLSL์ ์ด์ํ ์ค๋ฅ๋ฅผ ๋ฐ์์ํฌ ์ ์๋ค. (๋ถํฌ๋ช
ํ์
์ ํฌํจํ๋ ๊ตฌ์กฐ์ฒด์๋ ๋์ผํ๊ฒ ์ ์ฉ๋๋ค)
๋ํ ambient ์ปฌ๋ฌ๋ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ์ diffuse ์ปฌ๋ฌ์ ๋์ผํ๋ฏ๋ก ambient material ์ปฌ๋ฌ ๋ฒกํฐ๋ ๋ฐ๋ก ์ ์ฅํ์ง ์๋๋ค.
struct Material
{
sampler2D diffuse;
vec3 specular;
float shininess;
};
...
in vec2 TexCoords;
Fragment Shader์์ ํ ์ค์ฒ ์ขํ๊ฐ ํ์ํ๋ฏ๋ก ์ถ๊ฐ ์ ๋ ฅ ๋ณ์๋ฅผ ์ ์ธํ๋ค. ๊ทธ๋ฐ ๋ค์ ๋จ์ํ ํ ์ค์ฒ์์ ์ํ๋งํ์ฌ ํ๋๊ทธ๋จผํธ์ diffuse ์์ ๊ฐ์ ๊ฐ์ ธ์จ๋ค.
vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;
๋ํ ambient ๋จธํฐ๋ฆฌ์ผ ์์ ๊ฐ๋ diffuse ๋จธํฐ๋ฆฌ์ผ ์์ ๊ฐ๊ณผ ๋์ผํ๊ฒ ์ค์ ํ๋ค.
vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;
์ด๋ฅผ ์๋์ํค๋ ค๋ฉด ํ ์ค์ฒ ์ขํ๊ฐ ํฌํจ๋ Vertex ๋ฐ์ดํฐ๋ฅผ ์ ๋ฐ์ดํธํ๊ณ , ์ด๋ฅผ Vertex Attribute๋ก Fragment Shader์ ์ ๋ฌํ๋ฉฐ ํ ์ค์ฒ๋ฅผ ๋ก๋ํ๊ณ ์ ์ ํ ํ ์ค์ฒ ์ ๋์ ํ ์ค์ฒ๋ฅผ ๋ฐ์ธ๋ฉํด์ผ ํ๋ค.
- ์์ ๋ Vertex ๋ฐ์ดํฐ : https://learnopengl.com/code_viewer.php?code=lighting/vertex_data_textures
์ด Vertex ๋ฐ์ดํฐ๋ ํ๋ธ์ ๊ฐ Vertex์ ๋ํด Vertex ์์น, ๋ฒ์ ๋ฒกํฐ, ํ ์ค์ฒ ์ขํ๋ฅผ ํฌํจํ๊ณ ์๋ค. ์ด์ Vertex Shader๋ฅผ ํ ์ค์ฒ ์ขํ๋ฅผ Attribute๋ก ๋ฐ์ Fragment Shader๋ก ์ ๋ฌํ๋๋ก ์์ ํ๋ค.
- Vertex Shader
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
...
out vec2 TexCoords;
void main()
{
...
TexCoords = aTexCoords;
}
๋ ๊ฐ์ VAO ๋ชจ๋ ์๋ก์ด Vertex ๋ฐ์ดํฐ์ ๋ง์ถ์ด ์์ ํ๊ณ (stride ์์ฑ์ '8 * sizeof(float)'์ผ๋ก ์์ ), ์ปจํ
์ด๋ ์ด๋ฏธ์ง๋ฅผ ํ
์ค์ฒ๋ก ๋ถ๋ฌ์จ๋ค. ์ปจํ
์ด๋๋ฅผ ๊ทธ๋ฆฌ๊ธฐ ์ ์ ํ
์ค์ฒ ์ ๋์ material.diffuse uniform sampler์ ํ ๋นํ๊ณ ์ปจํ
์ด๋ ํ
์ค์ฒ๋ฅผ ์ด ํ
์ค์ฒ ์ ๋์ ๋ฐ์ธ๋ฉํด์ผ ํ๋ค.
- main
// ํ
์ค์ฒ ๊ฐ์ฒด ์์ฑ
unsigned int diffuseMap;
// ์ํ ๋ฐ์ ์ค์
stbi_set_flip_vertically_on_load(true);
// ํ
์ค์ฒ ๋ฐ์ธ๋ฉ
glGenTextures(1, &diffuseMap);
glBindTexture(GL_TEXTURE_2D, diffuseMap);
// Wrapping ์ต์
์ค์
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Filtering ์ต์
์ค์
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// ์ด๋ฏธ์ง ๋ก๋ (png)
int width, height, nrChannels;
unsigned char* data = stbi_load("Textures/container2.jpg", &width, &height, &nrChannels, 0);
// ํ
์ค์ฒ ์์ฑ (RGBA)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// ๋ฉ๋ชจ๋ฆฌ ๋ฐํ
stbi_image_free(data);
// shader configuration
lightingShader.setInt("material.diffuse", 0);
...
// render loop - bind diffuse map
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, diffuseMap);
โ ์์ค ์ฝ๋
https://learnopengl.com/code_viewer_gh.php?code=src/2.lighting/4.1.lighting_maps_diffuse_map/lighting_maps_diffuse.cpp
โ Specular map
ํ์ฌ ์ค๋ธ์ ํธ์ ์ฒ ๋ถ๋ถ์๋ง Specular ํ์ด๋ผ์ดํธ๋ฅผ ์ฃผ๊ณ , ๋๋ฌด ๋ถ๋ถ์๋ Specular ํ์ด๋ผ์ดํธ๋ฅผ ์์จ ๊ฒ์ด๋ค. ์ด๋ฅผ ์ํด Specular ํ์ด๋ผ์ดํธ๋ฅผ ์ํ ํ
์ค์ฒ ๋งต์ ์ฌ์ฉํ๋ค. ์ด๋ ์ค๋ธ์ ํธ์ ๊ฐ ๋ถ๋ถ์ Specular ์ธ๊ธฐ๋ฅผ ์ ์ํ๋ ํ๋ฐฑ(์ํ๋ค๋ฉด ์ปฌ๋ฌ) ํ
์ค์ฒ๋ฅผ ์์ฑํด์ผํ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค. ์์ ์ Specular map์ ๋ค์๊ณผ ๊ฐ๋ค.

Specular ํ์ด๋ผ์ดํธ์ ์ธ๊ธฐ๋ ์ด ์ด๋ฏธ์ง์ ๊ฐ ํฝ์
์ '๋ฐ๊ธฐ'์ ์ํด ์ป์ ์ ์๋ค. Fragment Shader์์ Specular map ๊ฐ ํฝ์
์ ์ปฌ๋ฌ ๊ฐ์ ์ํ๋งํ๊ณ ์ด ๊ฐ๊ณผ light์ Specular ์ธ๊ธฐ์ ๊ณฑํ๋ค. ํฝ์
์ด ํฐ์๊ณผ ๊ฐ๊น์ธ์๋ก ์ต์ข
๊ฒฐ๊ณผ๊ฐ ์ฆ๊ฐํ์ฌ ์ค๋ธ์ ํธ์ Specular ์์๊ฐ ๋ฐ์์ง๋ค.
์ด ์ปจํ
์ด๋์ ์ด๋ฏธ์ง ๋๋ฌด ๋ถ๋ถ์ ํ์ด๋ผ์ดํธ๋ฅผ ์์ ๊ธฐ ์ํด Diffuse ํ
์ค์ฒ์ ๋๋ฌด๋ก๋ ๋ถ๋ถ์ ๊ฒ์ ์์ผ๋ก ์ฒ๋ฆฌํ๋ค. ๊ฒ์ ์ ๋ถ๋ถ์ ์ด๋ ํ Specular ํ์ด๋ผ์ดํธ๋ ๊ฐ์ง์ง ์๋๋ค. ์ปจํ
์ด๋์ ์ฒ ๋ก๋ ๋ชจ์๋ฆฌ๋ ๊ฐ์ ๋ค๋ฅธ Specular ์ธ๊ธฐ๋ฅผ ๊ฐ์ง๋ค.
โ Specular map ์ํ๋ง
Specular map์ ๋ค๋ฅธ ํ
์ค์ฒ๋ค๊ณผ ๋น์ทํ๋ค. Diffuse map๊ณผ ๊ฐ์ด ์ ์ ํ ์ด๋ฏธ์ง๋ฅผ ๋ก๋ํ๊ณ ํ
์ค์ฒ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค. Fragment Shader์์ ๋ค๋ฅธ ํ
์ค์ฒ ์ํ๋ฌ๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ Specular map์ ๋ค๋ฅธ ํ
์ค์ฒ ์ ๋์ ์ฌ์ฉํด์ผ ํ๋ค. ๊ทธ๋ฆฌ๊ณ ๋ ๋๋งํ๊ธฐ ์ ์ ์ ์ ํ ํ
์ค์ฒ ์ ๋์ ๋ฐ์ธ๋ฉํ๊ฒ ํ๋ค.
// main
lightingShader.use();
glUniform1i(glGetUniformLocation(lightingShader.ID, "material.specular"), 1);
...
// render loop
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, specularMap);
๊ทธ๋ฐ ๋ค์ Fragment Shader์ material ์์ฑ ์ค specular ์์๋ฅผ vec3 ๋์ ์ sampler2D๋ก ๋ฐ์ ์ ์๋๋ก ์์ ํ๋ค.
// Fragment Shader
struct Material
{
sampler2D diffuse;
sampler2D specular;
float shininess;
};
๋ง์ง๋ง์ผ๋ก Fragment์ ํด๋น Specular ์ธ๊ธฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด Specular map์ ์ํ๋งํ๋ค.
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
FragColor = vec4(ambient + diffuse + specular, 1.0);
Specular map์ ์ฌ์ฉํจ์ผ๋ก์จ ์ค๋ธ์ ํธ์ ์ด๋ ํ ๋ถ๋ถ์ด ์ค์ ๋ก ๋น๋์ผํ๋์ง์ ๋ํด ์์ธํ๊ฒ ์ง์ ํ ์ ์๊ณ ๊ทธ์ ๋ฐ๋ฅธ ์ธ๊ธฐ๋ ์ค์ ํ ์ ์๋ค. ๋ฐ๋ผ์ Specular map์ Diffuse map์ ์์ ๋ ์ด์ด๋ฅผ ์ถ๊ฐํ๊ฒ ํด์ค๋ค.
โ ๊ฒฐ๊ณผ

โ ์์ค ์ฝ๋
- main
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <Shader.h>
#include <Camera.h>
#include <iostream>
unsigned int loadTexture(char const* path);
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 = glm::vec3(2.0f, 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[] = {
// positions // normals // texture coords
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
// ๊น์ด ํ
์คํธ ํ์ฑํ
glEnable(GL_DEPTH_TEST);
// VAO, VBO ์์ฑ
// VAO: VBO์ ์ ์ ์์ฑ ํฌ์ธํฐ์ ์ํ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ๊ฐ์ฒด
// VBO: GPU ๋ฉ๋ชจ๋ฆฌ์ ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ๋ฒํผ ๊ฐ์ฒด
unsigned int VBO, cubeVAO;
glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &VBO);
// ์ ์ ๋ฒํผ ๊ฐ์ฒด(VBO)๋ฅผ ๋ฐ์ธ๋ฉ
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// ๋ฐ์ธ๋ฉ๋ ๋ฒํผ ๊ฐ์ฒด์ vertices ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌํ๊ณ ,๋ฒํผ ๊ฐ์ฒด์ ํฌ๊ธฐ์ ๋ฐ์ดํฐ ์ค์
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// ์ ์ ๋ฐฐ์ด ๊ฐ์ฒด(VAO) ๋ฐ์ธ๋ฉ
glBindVertexArray(cubeVAO);
// Position Attribute ๊ตฌ์ฑ
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// Normal Attribute ๊ตฌ์ฑ
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// Texture(Diffuse Map) Attribute ๊ตฌ์ฑ
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
// ๊ด์ ํ๋ธ์ฉ VAO ์์ฑ
unsigned int lightCubeVAO;
glGenVertexArrays(1, &lightCubeVAO);
glBindVertexArray(lightCubeVAO);
// VBO ๋ฐ์ธ๋๋ง ํ๋ฉด ๋๋ค (์ด๋ฏธ ๋ฐ์ดํฐ ํฌํจ๋์ด ์์)
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// ---------- [ 3. Diffuse map, Specular map ๋ก๋ (ํจ์ํ) ] ----------
unsigned int diffuseMap = loadTexture("Textures/container2.png");
unsigned int specularMap = loadTexture("Textures/container2_specular.png");
// shader configuration
lightingShader.use();
glUniform1i(glGetUniformLocation(lightingShader.ID, "material.diffuse"), 0);
glUniform1i(glGetUniformLocation(lightingShader.ID, "material.specular"), 1);
// ---------- [ 4. ๋ ๋ ๋ฃจํ ] ----------
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();
// ์นด๋ฉ๋ผ ์์น ์์ฑ
glUniform3fv(glGetUniformLocation(lightingShader.ID, "viewPos"), 1, &(camera.Position)[0]);
// ๊ด์ ์์น ์์ฑ
glUniform3fv(glGetUniformLocation(lightingShader.ID, "light.position"), 1, &lightPos[0]);
// ๊ด์ ์์ ์์ฑ
glm::vec3 lightColor = glm::vec3(1.0f);
glUniform3f(glGetUniformLocation(lightingShader.ID, "light.ambient"), 0.2f, 0.2f, 0.2f);
glUniform3f(glGetUniformLocation(lightingShader.ID, "light.diffuse"), 0.5f, 0.5f, 0.5f);
glUniform3f(glGetUniformLocation(lightingShader.ID, "light.specular"), 1.0f, 1.0f, 1.0f);
// ๋จธํฐ๋ฆฌ์ผ ์์ฑ (diffuse: ์๋ ์ค๋ธ์ ํธ์ ์์์ ์๋ฏธ, ์กฐ๋ช
๋ชจ๋ธ์์ Diffuse ์กฐ๋ช
๊ณ์ฐ ์ ์ฌ์ฉ)
glUniform3f(glGetUniformLocation(lightingShader.ID, "material.specular"), 0.5f, 0.5f, 0.5f);
glUniform1f(glGetUniformLocation(lightingShader.ID, "material.shininess"), 64.0f);
// 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();
glUniformMatrix4fv(glGetUniformLocation(lightingShader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(glGetUniformLocation(lightingShader.ID, "view"), 1, GL_FALSE, glm::value_ptr(view));
// World ๋ณํ
glm::mat4 model = glm::mat4(1.0f);
glUniformMatrix4fv(glGetUniformLocation(lightingShader.ID, "model"), 1, GL_FALSE, glm::value_ptr(model));
// Diffuse map ๋ฐ์ธ๋ฉ
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, diffuseMap);
// Specular map ๋ฐ์ธ๋ฉ
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, specularMap);
// ํ๋ธ ๋ ๋
glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
// ๊ด์ ํ๋ธ ๋ ๋
lightCubeShader.use();
glUniformMatrix4fv(glGetUniformLocation(lightCubeShader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
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
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));
}
// ํ
์ค์ฒ ๋ก๋ ํจ์
unsigned int loadTexture(char const* path)
{
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char* data = stbi_load(path, &width, &height, &nrComponents, 0);
if (data)
{
GLenum format{};
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}
- Fragment Shader
#version 330 core
out vec4 FragColor;
struct Material
{
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light
{
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
in vec3 Normal;
in vec3 FragPos;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform Material material;
uniform Light light;
void main()
{
// ambient
vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;
// diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;
// specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}
โ Emission map
Emission map์ Fragment์ Emission ๊ฐ์ ์ ์ฅํ๋ ํ
์ค์ฒ์ด๋ค. Emission ๊ฐ์ ์ค๋ธ์ ํธ๊ฐ ๊ด์์ ์์ฒด์ ์ผ๋ก ๊ฐ์ง๊ณ ์๋ค๋ฉด ๊ทธ ๋น์ ๋ฐฉ์ถ(Emit)ํ๋ ์ปฌ๋ฌ์ด๋ค. ์ด ๋ฐฉ๋ฒ์ผ๋ก ์ค๋ธ์ ํธ๋ ๋น์ ์ํฉ์ ์๊ด์์ด ๋น๋ ์ ์๋ค.
๋ค๋ฅธ map๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก Fragment Shader์ material์ sampler2D emission ์์๋ฅผ ์ถ๊ฐํ๊ณ , ํ
์ค์ฒ๋ฅผ ๋ก๋ํ๊ณ ๋ฐ์ธ๋ฉํ๋ค.
// Fragment Shader
struct Material
{
sampler2D diffuse;
sampler2D specular;
sampler2D emission;
float shininess;
};
...
vec3 emission = texture(material.emission, TexCoords).rgb;
vec3 result = ambient + diffuse + specular;
'๐จ Graphics > ๐ต OpenGL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [OpenGL] Multiple Lights (0) | 2024.08.15 |
|---|---|
| [OpenGL] Lighting Caster (0) | 2024.08.15 |
| [OpenGL] ๋จธํฐ๋ฆฌ์ผ (Material) (0) | 2024.08.12 |
| [OpenGL] Phong ์กฐ๋ช ๋ชจ๋ธ (0) | 2024.08.12 |
| [OpenGL] ์นด๋ฉ๋ผ ์ค์ ๋ฐ ๋ณํ (์ด๋, ํ์ ) (0) | 2024.08.08 |