โ Multiple Lights
6๊ฐ์ ํ์ฑํ๋ ๊ด์๋ค๋ก ์์ ํ ๋น์ถฐ์ง scene์ ์์ฑํด ๋ณผ ๊ฒ์ด๋ค. Directional Light๋ก ํ์๊ณผ ๊ฐ์ ๋น์ ์๋ฎฌ๋ ์ด์
ํ๊ณ 4๊ฐ์ Point Light๋ฅผ ์ฌ์ฉํ์ฌ scene ์ ์ฒด์ ๋น์ ์ฐ๋ํ๊ณ Flashlight๋ ์ถ๊ฐํ ๊ฒ์ด๋ค.
ํ๋ ์ด์์ ๊ด์์ scene์ ์ฌ์ฉํ๊ธฐ ์ํด lighting ๊ณ์ฐ์ GLSL์ functions์ ์บก์ํํด์ผํ๋ค. ์ด๋ ๊ฒ ํ๋ ์ด์ ๋ ์ฌ๋ฌ๊ฐ์ง ๋น์ ์๊ตฌ๋ ๋ค๋ฅธ ๊ณ์ฐ๋ฒ๋ค๋ก lighting์ ๊ณ์ฐํ๋ ๊ฒ์ ์ฝ๋๋ฅผ ๋์ฐํ๊ฒ ๋ง๋ค๊ธฐ ๋๋ฌธ์ด๋ค. ๋ง์ฝ ๋ชจ๋ ๊ณ์ฐ๋ค์ main ํจ์ ์์์ ์ํํ๋ค๋ฉด ์ฝ๋๋ ์ดํดํ๊ธฐ ์ด๋ ค์ด ํํ๊ฐ ๋์ ๊ฒ์ด๋ค.
GLSL์ Functions๋ C์์์ ํจ์๋ค๊ณผ ๋น์ทํ๋ค. ํจ์์ ์ด๋ฆ๊ณผ ๋ฆฌํด ํ์
์ ๊ฐ์ง๊ณ ์๊ณ , main ํจ์ ์ ์ ์ ์ธ๋์ด ์์ง ์๋ค๋ฉด ์ฝ๋ ํ์ผ์ ์ต์์์ ํ๋กํ ํ์
์ ์ ์ธํด์ผ ํ๋ค. ๊ฐ light์ ํ์
์ ๋ํ ํจ์๋ฅผ ๋ฐ๋ก ๋ง๋ค ๊ฒ์ด๋ค(Directional Lights, Point Lights, Spotlights).
์ฌ๋ฌ๊ฐ์ง light๋ฅผ ์ฌ์ฉํ ๋ ์ ๊ทผ ๋ฐฉ์์ ์ผ๋ฐ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ๋ค : Fragment์ ์ถ๋ ฅ ์ปฌ๋ฌ๋ฅผ ๋ํ๋ด๋ ํ๋์ ์ปฌ๋ฌ ๋ฒกํฐ๋ฅผ ๊ฐ์ง๋ค. ๊ฐ light๋ค์ ์ํด ์ด Fragment์ light๊ฐ ๊ธฐ์ฌํ๋ ์ปฌ๋ฌ๋ฅผ ์ด Fragment์ ์ถ๋ ฅ ์ปฌ๋ฌ์ ๋ํ๋ค. ๊ทธ๋ฆฌ๊ณ scene์ ๊ฐ light๋ ์์ ์ธ๊ธํ Fragment์ ๋ฏธ์น๋ ํจ๊ณผ๋ฅผ ๊ณ์ฐํ๊ณ ์ต์ข
์ถ๋ ฅ ์ปฌ๋ฌ์ ๊ธฐ์ฌํ๊ฒ ๋ ๊ฒ์ด๋ค.
// Fragment Shader
out vec4 FragColor;
void main()
{
// ์ถ๋ ฅ ์ปฌ๋ฌ ๊ฐ์ ์ ์
vec3 output = vec3(0.0);
// Directional Light์ ์ํฅ์ ์ถ๋ ฅ์ ๋ํ๋ค.
output += someFunctionToCalculateDirectionalLight();
// Point Light์ ์ํฅ์ ์ถ๋ ฅ์ ๋ํ๋ค.
for (int i = 0; i < nr_of_point_lights; i++)
{
output += someFunctionToCalculatePointLight();
}
// ๋ค๋ฅธ Light์ ์ํฅ๋ ๋ํ๋ค (Spotlight ๊ฐ์ ๊ฒ๋ค)
output += someFunctionToCalculateSpotLight();
FragColor = vec4(output, 1.0);
}
์ผ๋ฐ์ ์ธ ๊ตฌ์กฐ๋ ๊ด์์ ๋ํ ํจ๊ณผ๋ฅผ ๊ณ์ฐํ๋ ์ฌ๋ฌ๊ฐ์ง ํจ์๋ค์ ์ ์ํ๊ณ ๊ทธ ๊ฒฐ๊ณผ ์ปฌ๋ฌ๋ฅผ ์ถ๋ ฅ ์ปฌ๋ฌ ๋ฒกํฐ์ ๋ํ๋ค. ์๋ฅผ ๋ค์ด 2๊ฐ์ ๊ด์์ด Fragment์ ๊ฐ๊น์ด์ ์๋ค๋ฉด ๊ทธ๋ค์ด ํผํฉ๋ ๊ธฐ์ฌ๋๋ ํ๋์ ๊ด์์ด Fragment๋ฅผ ๋น์ถ๋ ๊ฒ๋ณด๋ค ์ข ๋ ๋ฐ๊ฒ ๋๋ค.
โ Directional Light
์ด์ Fragment Shader์ ํจ์๋ฅผ ์ ์ํ ๊ฒ์ด๋ค. ์ด ํจ์๋ ํด๋น Fragment์ ๋ํ Directional Light์ ์ํฅ์ ๊ณ์ฐํ๋ค. ๋ช ๊ฐ์ง์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ๊ณ ๊ณ์ฐ๋ Directional Lighting ์ปฌ๋ฌ๋ฅผ ๋ฆฌํดํ๋ค.
DirLight๋ผ๊ณ ๋ถ๋ฆฌ๋ struct์ Directional Light์ ํ์ํ ๋ณ์๋ค์ ์ ์ธํ๊ณ uniform์ผ๋ก ์ ์ธํ๋ค.
struct DirLight
{
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform DirLight dirLight;
๊ทธ ๋ค์ dirLight uniform์ ๋ค์๊ณผ ๊ฐ์ด ํจ์์ ์ ๋ฌํ๋ค.
// Directional Light ๊ณ์ฐ ํจ์
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir)
{
vec3 lightDir = normalize(-light.direction);
// diffuse
float diff = max(dot(normal, lightDir), 0.0);
// specular
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// ์ต์ข
๊ฒฐ๊ณผ
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));
return (ambient + diffuse + specular);
}
โ Point Light
Directional light์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ฃผ์ด์ง Fragment์ ๋ํ Point Light๊ฐ ์ฃผ๋ ์ํฅ์ ๊ณ์ฐํ ํจ์๋ฅผ ์ ์ํ๋ค.
struct PointLight
{
vec3 position;
float constant;
float linear;
float quadratic;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
#define NR_POINT_LIGHTS 4
uniform PointLight pointLights[NR_POINT_LIGHTS];
scene์ ๋ฐฐ์นํ Point Light์ ๊ฐ์๋ฅผ GLSL์์ ์ ์ฒ๋ฆฌ๊ธฐ๋ก ์ ์ธํ ๊ฒ์ ๋ณผ ์ ์๋ค. ๊ทธ ๋ค์ PointLight struct ๋ฐฐ์ด์ ์์ฑํ๋ค.
ํ์ํ ๋ฐ์ดํฐ๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์ Fragment์ ๋ํ ํน์ Point Light์ ์ํฅ ์ปฌ๋ฌ๋ฅผ ์๋ฏธํ๋ vec3๋ฅผ ๋ฆฌํดํ๋ ํจ์๋ฅผ ์์ฑํ๋ค.
// Point Light ๊ณ์ฐ ํจ์
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 lightDir = normalize(light.position - fragPos);
// diffuse
float diff = max(dot(normal, lightDir), 0.0);
// specular
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(light.position - fragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
// ์ต์ข
๊ฒฐ๊ณผ
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));
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
return (ambient + diffuse + specular);
}
โ Spotlight
struct SpotLight
{
vec3 position;
vec3 direction;
float cutOff;
float outerCutOff;
float constant;
float linear;
float quadratic;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform SpotLight spotLight;
// Spotlight ๊ณ์ฐ ํจ์
vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 lightDir = normalize(light.position - fragPos);
// diffuse
float diff = max(dot(normal, lightDir), 0.0);
// specular
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(light.position - fragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
// spotlight (๋ถ๋๋ฌ์ด ์ธ๊ณฝ์ )
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = (light.cutOff - light.outerCutOff);
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
// ์ต์ข
๊ฒฐ๊ณผ
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));
ambient *= attenuation * intensity;
diffuse *= attenuation * intensity;
specular *= attenuation * intensity;
return (ambient + diffuse + specular);
}
โ ์ข ํฉ
์ ์ํ ํจ์๋ค์ ์ฌ์ฉํ์ฌ ์ต์ข ์ปฌ๋ฌ๋ฅผ ๊ณ์ฐํ๋ค.
void main()
{
// ์์ฑ
vec3 norm = normalize(Normal);
vec3 viewDir = normalize(viewPos - FragPos);
// 1 ๋จ๊ณ: Directional lighting
vec3 result = CalcDirLight(dirLight, norm, viewDir);
// 2 ๋จ๊ณ: Point lights
for(int i = 0; i < NR_POINT_LIGHTS; i++)
result += CalcPointLight(pointLights[i], norm, FragPos, viewDir);
// 3 ๋จ๊ณ: Spot light
result += CalcSpotLight(spotLight, norm, FragPos, viewDir);
FragColor = vec4(result, 1.0);
}
struct์ ๋ฐฐ์ด์ ๋ํ uniform์ ์ค์ ํ๋ ๊ฒ์ ํ๋์ struct uniform์ ์ค์ ํ๋ ๊ฒ๊ณผ ๋น์ทํ๋ค. uniform์ location์ ๋ํ ์ ์ ํ ์ธ๋ฑ์ค๋ฅผ ์ ์ํด์ผ ํ๋ค๋ ๊ฒ๋ง ๋ค๋ฅผ ๋ฟ์ด๋ค.
lightingShader.setFloat("pointLights[0].constant", 1.0f);
์ฌ๊ธฐ์์ pointLights ๋ฐฐ์ด์ ์ฒซ ๋ฒ์งธ PointLight struct๋ฅผ ์ธ๋ฑ์ฑํ์ฌ constant ๋ณ์์ location์ ์ป๊ณ ์๋ค. ์ด๋ 4๊ฐ์ ๊ฐ light์ ๋ํ ๋ชจ๋ uniform์ ์ผ์ผ์ด ์ค์ ํด์ฃผ์ด์ผ ํ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค. ์ด๋ 28๋ฒ์ uniform ํธ์ถ์ ๋ฐ์์ํจ๋ค.
๋ํ ์ฐ๋ฆฌ๋ Point Light๋ค์ ์์น ๋ฒกํฐ๋ฅผ ์ ์ํด์ผ scene ์ฃผ์์ ๊ทธ๋ค์ ๋ฐฐ์นํ ์ ์๋ค. Point Light์ ์์น๋ค์ ๊ฐ์ง๊ณ ์๋ ๋๋ค๋ฅธ glm::vec3 ๋ฐฐ์ด์ ์ ์ํ๋ค.
glm::vec3 pointLightPositions[] = {
glm::vec3( 0.7f, 0.2f, 2.0f),
glm::vec3( 2.3f, -3.3f, -4.0f),
glm::vec3(-4.0f, 2.0f, -12.0f),
glm::vec3( 0.0f, 0.0f, -3.0f)
};
๊ทธ ๋ค์ pointLights ๋ฐฐ์ด์ ํด๋น PointLight struct๋ฅผ ์ธ๋ฑ์ฑํ์ฌ position ์์ฑ์ ๋ฐฉ๊ธ ์ ์ํ ์์น ์ค ํ๋๋ก ์ค์ ํ๋ค. ๋ํ ํ๋๊ฐ ์๋ 4๊ฐ์ light ํ๋ธ(๊ด์)๋ฅผ ๊ทธ๋ ค์ผ ํ๋ค. ์ปจํ
์ด๋๋ค์ ์ฌ๋ฌ ๊ฐ ๊ทธ๋ฆฐ ๊ฒ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๊ฐ๋จํ ๊ฐ light ์ค๋ธ์ ํธ์ ๋ํ ์๋ก ๋ค๋ฅธ model ํ๋ ฌ์ ์์ฑํด์ผ ํ๋ค.
โ ๊ฒฐ๊ณผ

โ ์์ค ์ฝ๋
- 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>
#include <string>
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
};
// world space positions of our cubes
glm::vec3 cubePositions[] = {
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(2.0f, 5.0f, -15.0f),
glm::vec3(-1.5f, -2.2f, -2.5f),
glm::vec3(-3.8f, -2.0f, -12.3f),
glm::vec3(2.4f, -0.4f, -3.5f),
glm::vec3(-1.7f, 3.0f, -7.5f),
glm::vec3(1.3f, -2.0f, -2.5f),
glm::vec3(1.5f, 2.0f, -2.5f),
glm::vec3(1.5f, 0.2f, -1.5f),
glm::vec3(-1.3f, 1.0f, -1.5f)
};
// positions of the point lights
glm::vec3 pointLightPositions[] = {
glm::vec3(0.7f, 0.2f, 2.0f),
glm::vec3(2.3f, -3.3f, -4.0f),
glm::vec3(-4.0f, 2.0f, -12.0f),
glm::vec3(0.0f, 0.0f, -3.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]);
// ๋จธํฐ๋ฆฌ์ผ ์์ฑ
glUniform1f(glGetUniformLocation(lightingShader.ID, "material.shininess"), 32.0f);
// Directional Light
glUniform3f(glGetUniformLocation(lightingShader.ID, "dirLight.direction"), -0.2f, -1.0f, -0.3f);
glUniform3f(glGetUniformLocation(lightingShader.ID, "dirLight.ambient"), 0.05f, 0.05f, 0.05f);
glUniform3f(glGetUniformLocation(lightingShader.ID, "dirLight.diffuse"), 0.4f, 0.4f, 0.4f);
glUniform3f(glGetUniformLocation(lightingShader.ID, "dirLight.specular"), 0.5f, 0.5f, 0.5f);
// Point Lights
for (int i = 0; i < 4; i++)
{
std::string index = std::to_string(i);
glUniform3fv(glGetUniformLocation(lightingShader.ID, ("pointLights[" + index + "].position").c_str()), 1, &pointLightPositions[i][0]);
glUniform3f(glGetUniformLocation(lightingShader.ID, ("pointLights[" + index + "].ambient").c_str()), 0.05f, 0.05f, 0.05f);
glUniform3f(glGetUniformLocation(lightingShader.ID, ("pointLights[" + index + "].diffuse").c_str()), 0.8f, 0.8f, 0.8f);
glUniform3f(glGetUniformLocation(lightingShader.ID, ("pointLights[" + index + "].specular").c_str()), 1.0f, 1.0f, 1.0f);
glUniform1f(glGetUniformLocation(lightingShader.ID, ("pointLights[" + index + "].constant").c_str()), 1.0f);
glUniform1f(glGetUniformLocation(lightingShader.ID, ("pointLights[" + index + "].linear").c_str()), 0.09f);
glUniform1f(glGetUniformLocation(lightingShader.ID, ("pointLights[" + index + "].quadratic").c_str()), 0.032f);
}
// SpotLight
lightingShader.setVec3("spotLight.position", camera.Position);
lightingShader.setVec3("spotLight.direction", camera.Front);
lightingShader.setVec3("spotLight.ambient", 0.0f, 0.0f, 0.0f);
lightingShader.setVec3("spotLight.diffuse", 1.0f, 1.0f, 1.0f);
lightingShader.setVec3("spotLight.specular", 1.0f, 1.0f, 1.0f);
lightingShader.setFloat("spotLight.constant", 1.0f);
lightingShader.setFloat("spotLight.linear", 0.09f);
lightingShader.setFloat("spotLight.quadratic", 0.032f);
lightingShader.setFloat("spotLight.cutOff", glm::cos(glm::radians(12.5f)));
lightingShader.setFloat("spotLight.outerCutOff", glm::cos(glm::radians(15.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);
// render boxes
glBindVertexArray(cubeVAO);
for (unsigned int i = 0; i < 10; i++)
{
// calculate the model matrix for each object and pass it to shader before drawing
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, cubePositions[i]);
float angle = 20.0f * i;
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
glUniformMatrix4fv(glGetUniformLocation(lightingShader.ID, "model"), 1, GL_FALSE, glm::value_ptr(model));
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));
// we now draw as many light bulbs as we have point lights.
glBindVertexArray(lightCubeVAO);
for (unsigned int i = 0; i < 4; i++)
{
model = glm::mat4(1.0f);
model = glm::translate(model, pointLightPositions[i]);
model = glm::scale(model, glm::vec3(0.2f)); // Make it a smaller cube
lightCubeShader.setMat4("model", model);
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 direction;
float cutOff;
float outerCutOff;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;
float linear;
float quadratic;
};
struct DirLight
{
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
struct PointLight
{
vec3 position;
float constant;
float linear;
float quadratic;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
struct SpotLight
{
vec3 position;
vec3 direction;
float cutOff;
float outerCutOff;
float constant;
float linear;
float quadratic;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
in vec3 Normal;
in vec3 FragPos;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform Material material;
uniform Light light;
uniform DirLight dirLight;
uniform PointLight pointLights[4];
uniform SpotLight spotLight;
// function prototypes
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir);
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
void main()
{
// properties
vec3 norm = normalize(Normal);
vec3 viewDir = normalize(viewPos - FragPos);
// phase 1: directional lighting
vec3 result = CalcDirLight(dirLight, norm, viewDir);
// phase 2: point lights
for(int i = 0; i < 4; i++)
{
result += CalcPointLight(pointLights[i], norm, FragPos, viewDir);
}
// phase 3: spot light
result += CalcSpotLight(spotLight, norm, FragPos, viewDir);
FragColor = vec4(result, 1.0);
}
// Directional Light ๊ณ์ฐ ํจ์
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir)
{
vec3 lightDir = normalize(-light.direction);
// diffuse
float diff = max(dot(normal, lightDir), 0.0);
// specular
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// ์ต์ข
๊ฒฐ๊ณผ
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));
return (ambient + diffuse + specular);
}
// Point Light ๊ณ์ฐ ํจ์
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 lightDir = normalize(light.position - fragPos);
// diffuse
float diff = max(dot(normal, lightDir), 0.0);
// specular
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(light.position - fragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
// ์ต์ข
๊ฒฐ๊ณผ
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));
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
return (ambient + diffuse + specular);
}
// Spotlight ๊ณ์ฐ ํจ์
vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 lightDir = normalize(light.position - fragPos);
// diffuse
float diff = max(dot(normal, lightDir), 0.0);
// specular
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(light.position - fragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
// spotlight (๋ถ๋๋ฌ์ด ์ธ๊ณฝ์ )
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.cutOff - light.outerCutOff;
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
// ์ต์ข
๊ฒฐ๊ณผ
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));
ambient *= attenuation * intensity;
diffuse *= attenuation * intensity;
specular *= attenuation * intensity;
return (ambient + diffuse + specular);
}
- ๋งํฌ
https://learnopengl.com/code_viewer_gh.php?code=src/2.lighting/6.multiple_lights/multiple_lights.cpp
'๐จ Graphics > ๐ต OpenGL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [OpenGL] Lighting Caster (0) | 2024.08.15 |
|---|---|
| [OpenGL] Lighting Maps (0) | 2024.08.15 |
| [OpenGL] ๋จธํฐ๋ฆฌ์ผ (Material) (0) | 2024.08.12 |
| [OpenGL] Phong ์กฐ๋ช ๋ชจ๋ธ (0) | 2024.08.12 |
| [OpenGL] ์นด๋ฉ๋ผ ์ค์ ๋ฐ ๋ณํ (์ด๋, ํ์ ) (0) | 2024.08.08 |