전체 변환을 계산하고 월드 좌표와 노말을 프래그먼트에 넘겨준다.
#version 330
layout (location = 0) in vec3 in_position;
layout (location = 1) in vec3 in_normal;
layout (location = 2) in vec2 in_uv;
out vec3 frag_normal;
out vec3 frag_worldPos;
uniform mat4 g_model;
uniform mat4 g_view;
uniform mat4 g_projection;
void main(void)
{
vec4 worldPos = g_model * vec4(in_position, 1.0);
gl_Position = g_projection * g_view * worldPos;
frag_normal = in_normal;
frag_worldPos = vec3(worldPos);
}
주변 조명(ambient), 산란 반사 조명(diffuse), 거울 반사 조명(specular) 값을 계산한다.
#version 330 core
in vec3 frag_normal;
in vec3 frag_worldPos;
out vec4 out_color;
uniform vec3 g_lightAmbient;
uniform vec3 g_lightPos;
uniform vec3 g_lightColor;
uniform vec3 g_objectColor;
uniform vec3 g_cameraPos;
void main(void)
{
vec3 ambient = g_lightAmbient * g_lightColor;
vec3 normalVector = normalize(frag_normal);
vec3 lightDir = normalize(g_lightPos - frag_worldPos);
float diffuseLight = max(dot(normalVector, lightDir), 0.0);
vec3 diffuse = diffuseLight * g_lightColor;
int shininess = 128;
vec3 viewDir = normalize(g_cameraPos - frag_worldPos);
vec3 reflectDir = reflect(-lightDir, normalVector);
float specularLight = max(dot(viewDir, reflectDir), 0.0);
specularLight = pow(specularLight, shininess);
vec3 specular = specularLight * g_lightColor;
vec3 result = (ambient + diffuse + specular) * g_objectColor;
out_color = vec4(result, 1.0);
}
Mapping 함수
void ShaderManager::Mapping()
{
model_loc = glGetUniformLocation(shader_program_ID, "g_model");
view_loc = glGetUniformLocation(shader_program_ID, "g_view");
proj_loc = glGetUniformLocation(shader_program_ID, "g_projection");
lightAmbi_loc = glGetUniformLocation(shader_program_ID, "g_lightAmbient");
lightPos_loc = glGetUniformLocation(shader_program_ID, "g_lightPos");
lightColor_loc = glGetUniformLocation(shader_program_ID, "g_lightColor");
objColor_loc = glGetUniformLocation(shader_program_ID, "g_objectColor");
cameraPos_loc = glGetUniformLocation(shader_program_ID, "g_cameraPos");
}
Light클래스
#pragma once
#include "stdafx.h"
#define OBJECT_COLOR glm::vec3(1.0, 1.0, 1.0)
#define LIGHT_AMBIENT glm::vec3(0.1, 0.1, 0.1)
#define LIGHT_POS glm::vec3(0.0, 0.0, 3.0)
#define LIGHT_COLOR glm::vec3(1.0, 1.0, 1.0)
class Light
{
public:
void Init() {
glm::vec3 lightAmbient = LIGHT_AMBIENT;
glUniform3fv(lightAmbient_loc, 1, (float*)&lightAmbient);
glm::vec3 lightPos = glm::vec3(3 * cos(yRotate_light), 0.0, 3 * sin(yRotate_light));
glUniform3fv(lightPos_loc, 1, (float*)&lightPos);
glm::vec3 lightColor = LIGHT_COLOR;
glUniform3fv(lightColor_loc, 1, (float*)&lightColor);
glm::vec3 objColor = OBJECT_COLOR;
glm::vec3 objColor1 = glm::vec3(1.0, 0.0, 0.0);
glm::vec3 objColor2 = glm::vec3(0.0, 1.0, 0.0);
glm::vec3 objColor3 = glm::vec3(0.0, 0.0, 1.0);
glUniform3fv(objColor_loc, 1, (float*)&objColor1);
}
GLuint lightAmbient_loc;
GLuint lightPos_loc;
GLuint lightColor_loc;
GLuint objColor_loc;
double yRotate_light = 0.0;
float yRotate_lightbox = 0.0f;
bool isPlus_light = true;
};
main.cpp
#include "stdafx.h"
#include "Shape.h"
#include "ShaderManager.h"
#include "Camera.h"
#include "Sphere.h"
#include "Light.h"
GLvoid drawScene(GLvoid);
GLvoid Reshape(int w, int h);
GLvoid Keyboard(unsigned char key, int x, int y);
GLvoid TimerFunction1(int value);
GLvoid Mouse(int button, int state, int x, int y);
GLfloat mx = 0.0f;
GLfloat my = 0.0f;
GLuint shader_program_ID;
ShaderManager shader_manager;
Camera cam;
Sphere sphere;
Light light;
bool isTimer1On = false;
bool isAllStop = false;
GLvoid drawScene() //--- 콜백 함수: 그리기 콜백 함수
{
//--- 변경된 배경색 설정
glClearColor(background_color.r, background_color.g, background_color.b, 1.0f); // 바탕색을 변경
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 설정된 색으로 전체를 칠하기
glFrontFace(GL_CCW);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glUseProgram(shader_program_ID);
shader_manager.Mapping();
light.lightAmbient_loc = shader_manager.lightAmbi_loc;
light.lightPos_loc = shader_manager.lightPos_loc;
light.lightColor_loc = shader_manager.lightColor_loc;
light.objColor_loc = shader_manager.objColor_loc;
light.Init();
cam.view_loc = shader_manager.view_loc;
cam.cameraPos_loc = shader_manager.cameraPos_loc;
cam.proj_loc = shader_manager.proj_loc;
cam.Init();
sphere.Init_And_Render(shader_manager.model_loc);
glutSwapBuffers();
isAllStop = false;
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
}
GLvoid Reshape(int w, int h) //--- 콜백 함수: 다시 그리기 콜백 함수
{
WIN_W = (float)w;
WIN_H = (float)h;
glViewport(0, 0, w, h);
}
GLvoid Keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'r': case 'R':
light.isPlus_light = true;
if (!isTimer1On)
glutTimerFunc(100, TimerFunction1, 1);
isTimer1On = true;
break;
}
glutPostRedisplay(); //--- 배경색이 바뀔때마다 출력 콜백함수를 호출하여 화면을 refresh 한다
}
//앞면이 올라가고 로봇이 팔다리를 흔듦
GLvoid TimerFunction1(int value)
{
if (light.isPlus_light) {
light.yRotate_light -= 1.0 / 58.0;
light.yRotate_lightbox += 1.0f;
}
else if (!light.isPlus_light) {
light.yRotate_light += 1.0 / 58.0;
light.yRotate_lightbox -= 1.0f;
}
glutPostRedisplay(); // 화면 재 출력
if (isTimer1On)
glutTimerFunc(100, TimerFunction1, 1);
}
GLvoid Mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
}
glutPostRedisplay();
}
int main(int argc, char** argv) //--- 윈도우 출력하고 콜백함수 설정
{ //--- 윈도우 생성하기
glutInit(&argc, argv); // glut 초기화
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); // 디스플레이 모드 설정
glutInitWindowPosition(WIN_X, WIN_Y); // 윈도우의 위치 지정
glutInitWindowSize((int)WIN_W, (int)WIN_H); // 윈도우의 크기 지정
glutCreateWindow("Example1"); // 윈도우 생성 (윈도우 이름)
//--- GLEW 초기화하기
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) // glew 초기화
{
std::cerr << "Unable to initialize GLEW" << std::endl;
exit(EXIT_FAILURE);
}
else
std::cout << "GLEW Initialized\n";
if (!shader_manager.Init_Program()) {
cerr << "Error: Shader Program 생성 실패" << endl;
std::exit(EXIT_FAILURE);
}
shader_program_ID = shader_manager.shader_program_ID;
if (!sphere.Init_VAO(shader_program_ID)) {
cerr << "Error: 구 생성 실패" << endl;
std::exit(EXIT_FAILURE);
}
glutDisplayFunc(drawScene); // 출력 함수의 지정
glutReshapeFunc(Reshape); // 다시 그리기 함수 지정
glutKeyboardFunc(Keyboard);
glutMouseFunc(Mouse);
glutMainLoop(); // 이벤트 처리 시작
}
실행화면