// sb6.h 헤더 파일을 포함시킨다.
#include <sb7.h>
#include <vmath.h>
#include <shader.h>
#include <vector>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
// sb6::application을 상속받는다.
class my_application : public sb7::application
{
public:
// 쉐이더 컴파일한다.
GLuint compile_shader(const char* vs_filename, const char* fs_filename)
{
// 버텍스 쉐이더를 생성하고 컴파일한다.
GLuint vertex_shader = sb7::shader::load(vs_filename, GL_VERTEX_SHADER);
// 프래그먼트 쉐이더를 생성하고 컴파일한다.
GLuint fragment_shader = sb7::shader::load(fs_filename, GL_FRAGMENT_SHADER);
// 프로그램을 생성하고 쉐이더를 Attach시키고 링크한다.
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
// 이제 프로그램이 쉐이더를 소유하므로 쉐이더를 삭제한다.
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return program;
}
// 애플리케이션 초기화 수행한다.
virtual void startup()
{
// 쉐이더 프로그램 컴파일 및 연결
shader_programs[1] = compile_shader("multiple_lights_vs.glsl", "multiple_lights_fs.glsl");
shader_programs[2] = compile_shader("simple_color_vs.glsl", "simple_color_fs.glsl");
// VAO, VBO, EBO, texture 생성
glGenVertexArrays(3, VAOs);
glGenBuffers(3, VBOs);
glGenBuffers(2, EBOs);
glGenTextures(3, textures);
stbi_set_flip_vertically_on_load(true);
// 텍스처 이미지 로드하기
int width, height, nrChannels;
// 두 번째 객체 정의 : 박스 --------------------------------------------------
glBindVertexArray(VAOs[1]);
// 박스 점들의 위치와 컬러, 텍스처 좌표를 정의한다.
float box_s = 1.0f, box_t = 1.0f;
GLfloat box_vertices[] = {
// 뒷면
-0.25f, 0.5f, -0.25f, 1.0f, 0.0f, 0.0f, box_s, box_t, 0.0f, 0.0f, -1.0f,
0.25f, 0.0f, -0.25f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f,
-0.25f, 0.0f, -0.25f, 1.0f, 0.0f, 0.0f, box_s, 0.0f, 0.0f, 0.0f, -1.0f,
0.25f, 0.0f, -0.25f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f,
-0.25f, 0.5f, -0.25f, 1.0f, 0.0f, 0.0f, box_s, box_t, 0.0f, 0.0f, -1.0f,
0.25f, 0.5f, -0.25f, 1.0f, 0.0f, 0.0f, 0.0f, box_t, 0.0f, 0.0f, -1.0f,
// 우측면
0.25f, 0.0f, -0.25f, 0.0f, 1.0f, 0.0f, box_s, 0.0f, 1.0f, 0.0f, 0.0f,
0.25f, 0.5f, -0.25f, 0.0f, 1.0f, 0.0f, box_s, box_t, 1.0f, 0.0f, 0.0f,
0.25f, 0.0f, 0.25f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.25f, 0.0f, 0.25f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.25f, 0.5f, -0.25f, 0.0f, 1.0f, 0.0f, box_s, box_t, 1.0f, 0.0f, 0.0f,
0.25f, 0.5f, 0.25f, 0.0f, 1.0f, 0.0f, 0.0f, box_t, 1.0f, 0.0f, 0.0f,
// 정면
0.25f, 0.0f, 0.25f, 0.0f, 0.0f, 1.0f, box_s, 0.0f, 0.0f, 0.0f, 1.0f,
0.25f, 0.5f, 0.25f, 0.0f, 0.0f, 1.0f, box_s, box_t, 0.0f, 0.0f, 1.0f,
-0.25f, 0.0f, 0.25f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.25f, 0.0f, 0.25f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.25f, 0.5f, 0.25f, 0.0f, 0.0f, 1.0f, box_s, box_t, 0.0f, 0.0f, 1.0f,
-0.25f, 0.5f, 0.25f, 0.0f, 0.0f, 1.0f, 0.0f, box_t, 0.0f, 0.0f, 1.0f,
// 좌측면
-0.25f, 0.0f, 0.25f, 1.0f, 0.0f, 1.0f, box_s, 0.0f, -1.0f, 0.0f, 0.0f,
-0.25f, 0.5f, 0.25f, 1.0f, 0.0f, 1.0f, box_s, box_t, -1.0f, 0.0f, 0.0f,
-0.25f, 0.0f, -0.25f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.25f, 0.0f, -0.25f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.25f, 0.5f, 0.25f, 1.0f, 0.0f, 1.0f, box_s, box_t, -1.0f, 0.0f, 0.0f,
-0.25f, 0.5f, -0.25f, 1.0f, 0.0f, 1.0f, 0.0f, box_t, -1.0f, 0.0f, 0.0f,
// 바닥면
-0.25f, 0.0f, 0.25f, 1.0f, 1.0f, 0.0f, box_s, 0.0f, 0.0f, -1.0f, 0.0f,
0.25f, 0.0f, -0.25f, 1.0f, 1.0f, 0.0f, 0.0f, box_t, 0.0f, -1.0f, 0.0f,
0.25f, 0.0f, 0.25f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f,
0.25f, 0.0f, -0.25f, 1.0f, 1.0f, 0.0f, 0.0f, box_t, 0.0f, -1.0f, 0.0f,
-0.25f, 0.0f, 0.25f, 1.0f, 1.0f, 0.0f, box_s, 0.0, 0.0f, -1.0f, 0.0f,
-0.25f, 0.0f, -0.25f, 1.0f, 1.0f, 0.0f, box_s, box_t, 0.0f, -1.0f, 0.0f,
// 윗면
-0.25f, 0.5f, -0.25f, 0.0f, 1.0f, 1.0f, 0.0f, box_t, 0.0f, 1.0f, 0.0f,
0.25f, 0.5f, 0.25f, 0.0f, 1.0f, 1.0f, box_s, 0.0f, 0.0f, 1.0f, 0.0f,
0.25f, 0.5f, -0.25f, 0.0f, 1.0f, 1.0f, box_s, box_t, 0.0f, 1.0f, 0.0f,
0.25f, 0.5f, 0.25f, 0.0f, 1.0f, 1.0f, box_s, 0.0f, 0.0f, 1.0f, 0.0f,
-0.25f, 0.5f, -0.25f, 0.0f, 1.0f, 1.0f, 0.0f, box_t, 0.0f, 1.0f, 0.0f,
-0.25f, 0.5f, 0.25f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f
};
boxPositions.push_back(vmath::vec3(0.0f, 0.0f, 0.0f));
boxPositions.push_back(vmath::vec3(2.0f, 5.0f, -15.0f));
boxPositions.push_back(vmath::vec3(-1.5f, -2.2f, -2.5f));
boxPositions.push_back(vmath::vec3(-3.8f, -2.0f, -12.3f));
boxPositions.push_back(vmath::vec3(2.4f, -0.4f, -3.5f));
boxPositions.push_back(vmath::vec3(-1.7f, 3.0f, -7.5f));
boxPositions.push_back(vmath::vec3(1.3f, -2.0f, -2.5f));
boxPositions.push_back(vmath::vec3(1.5f, 2.0f, -2.5f));
boxPositions.push_back(vmath::vec3(1.5f, 0.2f, -1.5f));
boxPositions.push_back(vmath::vec3(-1.3f, 1.0f, -1.5f));
// VBO를 생성하여 vertices 값들을 복사
glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(box_vertices), box_vertices, GL_STATIC_DRAW);
// VBO를 나누어서 각 버텍스 속성으로 연결
// 위치 속성 (location = 0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 컬러 속성 (location = 1)
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// 텍스처 좌표 속성 (location = 2)
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
// 노멀 속성 (location = 3)
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(8 * sizeof(float)));
glEnableVertexAttribArray(3);
// VBO 및 버텍스 속성을 다 했으니 VBO와 VAO를 unbind한다.
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// Diffuse Map 이미지 로드 및 설정
glBindTexture(GL_TEXTURE_2D, textures[1]);
width, height, nrChannels;
unsigned char* data = stbi_load("container2.png", &width, &height, &nrChannels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
stbi_image_free(data);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Specular Map 이미지 로드 및 설정
glBindTexture(GL_TEXTURE_2D, textures[2]);
width, height, nrChannels;
data = stbi_load("container2_specular.png", &width, &height, &nrChannels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
stbi_image_free(data);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// 세 번째 객체 정의 : 피라미드 --------------------------------------------------
glBindVertexArray(VAOs[2]);
// 피라미드 점들의 위치와 컬러, 텍스처 좌표를 정의한다.
GLfloat pyramid_vertices[] = {
1.0f, 0.0f, -1.0f, // 우측 상단
-1.0f, 0.0f, -1.0f, // 좌측 상단
-1.0f, 0.0f, 1.0f, // 좌측 하단
1.0f, 0.0f, 1.0f, // 우측 하단
0.0f, 1.0f, 0.0f, // 상단 꼭지점
0.0f, -1.0f, 0.0f, // 하단 꼭지점
};
// 삼각형으로 그릴 인덱스를 정의한다.
GLuint pyramid_indices[] = {
4, 0, 1,
4, 1, 2,
4, 2, 3,
4, 3, 0,
5, 1, 0,
5, 2, 1,
5, 3, 2,
5, 0, 3,
};
// VBO를 생성하여 vertices 값들을 복사
glBindBuffer(GL_ARRAY_BUFFER, VBOs[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(pyramid_vertices), pyramid_vertices, GL_STATIC_DRAW);
// VBO를 나누어서 각 버텍스 속성으로 연결
// 위치 속성 (location = 0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// EBO를 생성하고 indices 값들을 복사
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(pyramid_indices), pyramid_indices, GL_STATIC_DRAW);
// VBO 및 버텍스 속성을 다 했으니 VBO와 VAO를 unbind한다.
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
// 애플리케이션 끝날 때 호출된다.
virtual void shutdown()
{
glDeleteTextures(3, textures);
glDeleteBuffers(2, EBOs);
glDeleteBuffers(3, VBOs);
glDeleteVertexArrays(3, VAOs);
glDeleteProgram(shader_programs[0]);
glDeleteProgram(shader_programs[1]);
}
// 렌더링 virtual 함수를 작성해서 오버라이딩한다.
virtual void render(double currentTime)
{
const GLfloat black[] = { 0.0f, 0.0f, 0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, black);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glViewport(0, 0, info.windowWidth, info.windowHeight);
GLint uniform_transform1 = glGetUniformLocation(shader_programs[0], "transform");
GLint uniform_transform2 = glGetUniformLocation(shader_programs[1], "transform");
// 카메라 매트릭스 계산
float distance = 5.f;
vmath::vec3 eye(0.0f, 1.0f, distance);
vmath::vec3 center(0.0, 0.0, 0.0);
vmath::vec3 up(0.0, 1.0, 0.0);
vmath::mat4 lookAt = vmath::lookat(eye, center, up);
float fov = 50.f;// (float)cos(currentTime)*20.f + 50.0f;
vmath::mat4 projM = vmath::perspective(fov, (float)info.windowWidth / (float)info.windowHeight, 0.1f, 1000.0f);
// 라이팅 설정 ---------------------------------------
vmath::vec3 pointLightPos[] = { vmath::vec3((float)sin(currentTime * 0.5f), 0.25f, (float)cos(currentTime * 0.5f) * 0.7f),
vmath::vec3(0.25f, (float)sin(currentTime * 1.f), (float)cos(currentTime * 1.f) * 0.7f),
vmath::vec3((float)sin(currentTime * 1.f), (float)cos(currentTime * 1.f), (float)sin(currentTime * 1.f) * 0.7f) };
vmath::vec3 lightColor(0.0f, 1.0f, 0.0f);
vmath::vec3 lightColor2(1.0f, 0.0f, 0.0f);
vmath::vec3 lightColor3(0.0f, 0.0f, 1.0f);
vmath::vec3 viewPos = eye;
// 박스 그리기 ---------------------------------------
vmath::mat4 transM = vmath::translate(vmath::vec3((float)sin(currentTime * 0.5f), 0.0f, (float)cos(currentTime * 0.5f) * 0.7f));
float angle = currentTime * 100;
vmath::mat4 rotateM = vmath::rotate(angle, 0.0f, 1.0f, 0.0f);
glUseProgram(shader_programs[1]);
glUniformMatrix4fv(glGetUniformLocation(shader_programs[1], "projection"), 1, GL_FALSE, projM);
glUniformMatrix4fv(glGetUniformLocation(shader_programs[1], "view"), 1, GL_FALSE, lookAt);
glUniform3fv(glGetUniformLocation(shader_programs[1], "viewPos"), 1, viewPos);
float shininess = 32.f;
glUniform1f(glGetUniformLocation(shader_programs[1], "material.shininess"), shininess);
glUniform1i(glGetUniformLocation(shader_programs[1], "material.diffuse"), 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glUniform1i(glGetUniformLocation(shader_programs[1], "material.specular"), 1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[2]);
//연두
glUniform3fv(glGetUniformLocation(shader_programs[1], "pointLights[0].position"), 1, pointLightPos[0]);
glUniform3f(glGetUniformLocation(shader_programs[1], "pointLights[0].ambient"), 0.05f, 1.0f, 0.05f);
glUniform3f(glGetUniformLocation(shader_programs[1], "pointLights[0].diffuse"), 0.1f, 1.0f, 0.1f);
glUniform3f(glGetUniformLocation(shader_programs[1], "pointLights[0].specular"), 0.0f, 1.0f, 0.0f);
glUniform1f(glGetUniformLocation(shader_programs[1], "pointLights[0].c1"), 0.5f);
glUniform1f(glGetUniformLocation(shader_programs[1], "pointLights[0].c2"), 0.2f);
//빨강
glUniform3fv(glGetUniformLocation(shader_programs[1], "pointLights[1].position"), 1, pointLightPos[1]);
glUniform3f(glGetUniformLocation(shader_programs[1], "pointLights[1].ambient"), 1.0f, 0.05f, 0.05f);
glUniform3f(glGetUniformLocation(shader_programs[1], "pointLights[1].diffuse"), 1.0f, 0.1f, 0.1f);
glUniform3f(glGetUniformLocation(shader_programs[1], "pointLights[1].specular"), 1.0f, 0.0f, 0.0f);
glUniform1f(glGetUniformLocation(shader_programs[1], "pointLights[1].c1"), 0.5f);
glUniform1f(glGetUniformLocation(shader_programs[1], "pointLights[1].c2"), 0.2f);
//파랑
glUniform3fv(glGetUniformLocation(shader_programs[1], "pointLights[2].position"), 1, pointLightPos[2]);
glUniform3f(glGetUniformLocation(shader_programs[1], "pointLights[2].ambient"), 0.05f, 0.05f, 1.0f);
glUniform3f(glGetUniformLocation(shader_programs[1], "pointLights[2].diffuse"), 0.1f, 0.1f, 1.0f);
glUniform3f(glGetUniformLocation(shader_programs[1], "pointLights[2].specular"), 0.0f, 0.0f, 1.0f);
glUniform1f(glGetUniformLocation(shader_programs[1], "pointLights[2].c1"), 0.5f);
glUniform1f(glGetUniformLocation(shader_programs[1], "pointLights[2].c2"), 0.2f);
//카메라에서 바라보는 빛
glUniform3fv(glGetUniformLocation(shader_programs[1], "spotLight.position"), 1, eye);
glUniform3fv(glGetUniformLocation(shader_programs[1], "spotLight.direction"), 1, center - eye);
glUniform1f(glGetUniformLocation(shader_programs[1], "spotLight.cutOff"), (float)cos(vmath::radians(12.5)));
glUniform1f(glGetUniformLocation(shader_programs[1], "spotLight.outerCutOff"), (float)cos(vmath::radians(15.5)));
glUniform1f(glGetUniformLocation(shader_programs[1], "spotLight.c1"), 0.09f);
glUniform1f(glGetUniformLocation(shader_programs[1], "spotLight.c2"), 0.032f);
glUniform3f(glGetUniformLocation(shader_programs[1], "spotLight.ambient"), 0.0f, 0.0f, 0.0f);
glUniform3f(glGetUniformLocation(shader_programs[1], "spotLight.diffuse"), 0.2f, 0.2f, 0.2f);
glUniform3f(glGetUniformLocation(shader_programs[1], "spotLight.specular"), 0.2f, 0.2f, 0.2f);
glBindVertexArray(VAOs[1]);
for (int i = 0; i < boxPositions.size(); i++)
{
float angle = 20.f * i;
vmath::mat4 model = vmath::translate(boxPositions[i]) *
vmath::rotate(angle, 1.0f, 0.3f, 0.5f) *
vmath::scale(1.0f);
glUniformMatrix4fv(glGetUniformLocation(shader_programs[1], "model"), 1, GL_FALSE, model);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
// 피라미드 그리기 ---------------------------------------
glUseProgram(shader_programs[2]);
glUniform3fv(glGetUniformLocation(shader_programs[2], "color"), 1, lightColor);
glUniformMatrix4fv(glGetUniformLocation(shader_programs[2], "projection"), 1, GL_FALSE, projM);
glUniformMatrix4fv(glGetUniformLocation(shader_programs[2], "view"), 1, GL_FALSE, lookAt);
glBindVertexArray(VAOs[2]);
float scaleFactor = 0.05f;
vmath::mat4 transform = vmath::translate(pointLightPos[0]) *
vmath::rotate(angle * 0.5f, 0.0f, 1.0f, 0.0f) *
vmath::scale(scaleFactor, scaleFactor, scaleFactor);
glUniformMatrix4fv(glGetUniformLocation(shader_programs[2], "model"), 1, GL_FALSE, transform);
glDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_INT, 0);
//2================================
glUniform3fv(glGetUniformLocation(shader_programs[2], "color"), 1, lightColor2);
glUniformMatrix4fv(glGetUniformLocation(shader_programs[2], "projection"), 1, GL_FALSE, projM);
glUniformMatrix4fv(glGetUniformLocation(shader_programs[2], "view"), 1, GL_FALSE, lookAt);
vmath::mat4 transform1 = vmath::translate(pointLightPos[1]) *
vmath::rotate(angle * 0.5f, 0.0f, 1.0f, 0.0f) *
vmath::scale(scaleFactor, scaleFactor, scaleFactor);
glUniformMatrix4fv(glGetUniformLocation(shader_programs[2], "model"), 1, GL_FALSE, transform1);
glDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_INT, 0);
//==============3번째 빛
glUniform3fv(glGetUniformLocation(shader_programs[2], "color"), 1, lightColor3);
glUniformMatrix4fv(glGetUniformLocation(shader_programs[2], "projection"), 1, GL_FALSE, projM);
glUniformMatrix4fv(glGetUniformLocation(shader_programs[2], "view"), 1, GL_FALSE, lookAt);
vmath::mat4 transform2 = vmath::translate(pointLightPos[2]) *
vmath::rotate(angle * 0.5f, 0.0f, 1.0f, 0.0f) *
vmath::scale(scaleFactor, scaleFactor, scaleFactor);
glUniformMatrix4fv(glGetUniformLocation(shader_programs[2], "model"), 1, GL_FALSE, transform2);
glDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_INT, 0);
}
void onResize(int w, int h)
{
sb7::application::onResize(w, h);
}
private:
GLuint shader_programs[3];
GLuint VAOs[3], VBOs[3], EBOs[2];
GLuint textures[3];
std::vector<vmath::vec3> boxPositions;
};
// DECLARE_MAIN의 하나뿐인 인스턴스
DECLARE_MAIN(my_application)
//<<multiple_lights_vs.glsl>>
#version 430 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec3 color;
layout (location = 2) in vec2 texCoord;
layout (location = 3) in vec3 normal;
out vec3 vsPos;
out vec3 vsNormal;
out vec2 vsTexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
vsPos = vec3(model * vec4(pos, 1.0));
vsNormal = mat3(transpose(inverse(model))) * normal;
vsTexCoord = texCoord;
gl_Position = projection * view * vec4(vsPos, 1.0);
}
//<<multiple_lights_fs.glsl>>
#version 430 core
in vec3 vsNormal;
in vec3 vsPos;
in vec2 vsTexCoord;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct DirLight {
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
struct PointLight {
vec3 position;
float c1;
float c2;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
struct SpotLight {
vec3 position;
vec3 direction;
float cutOff;
float outerCutOff;
float c1;
float c2;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
#define NUM_POINT_LIGHTS 3
uniform Material material;
uniform vec3 viewPos;
uniform DirLight dirLight;
uniform PointLight pointLights[NUM_POINT_LIGHTS];
uniform SpotLight spotLight;
out vec4 fragColor;
// 광원별 컬러 계산 함수 정의
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(vsNormal);
vec3 viewDir = normalize(viewPos - vsPos);
for(int i = 0; i < NUM_POINT_LIGHTS; i++)
{
result += CalcPointLight(pointLights[i], norm, vsPos, viewDir);
}
result += CalcSpotLight(spotLight, norm, vsPos, viewDir);
fragColor = vec4(result, 1.0);
}
// directional light
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir)
{
vec3 lightDir = normalize(-light.direction);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// combine results
vec3 ambient = light.ambient * vec3(texture(material.diffuse, vsTexCoord));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, vsTexCoord));
vec3 specular = light.specular * spec * vec3(texture(material.specular, vsTexCoord));
return (ambient + diffuse + specular);
}
// point light
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 lightDir = normalize(light.position - fragPos);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
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 / (1.0 + light.c1 * distance + light.c2 * (distance * distance));
// combine results
vec3 ambient = light.ambient * vec3(texture(material.diffuse, vsTexCoord));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, vsTexCoord));
vec3 specular = light.specular * spec * vec3(texture(material.specular, vsTexCoord));
return (ambient + diffuse + specular) * attenuation;
}
// spot light
vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 lightDir = normalize(light.position - fragPos);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// Soft edge spotlight intensity
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.cutOff - light.outerCutOff;
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
// attenuation
float distance = length(light.position - fragPos);
float attenuation = 1.0 / (1.0 + light.c1 * distance + light.c2 * (distance * distance));
// combine results
vec3 ambient = light.ambient * vec3(texture(material.diffuse, vsTexCoord));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, vsTexCoord));
vec3 specular = light.specular * spec * vec3(texture(material.specular, vsTexCoord));
ambient *= attenuation * intensity;
diffuse *= attenuation * intensity;
specular *= attenuation * intensity;
return (ambient + diffuse + specular);
}
포인트 라이트
스팟 라이트
'opengl' 카테고리의 다른 글
opengl 라이팅 Phong모델 (0) | 2023.01.05 |
---|---|
opengl 텍스처 겹치기 / 컴파일 쉐이더, 텍스처로드 함수화 (0) | 2023.01.05 |
opengl 텍스처 (0) | 2023.01.04 |
opengl 시점변환 원근투영 - opengl라이브러리 (0) | 2022.09.06 |
opengl 시점변환 원근투영 - 하드코딩 (0) | 2022.09.06 |