[OpenGL] 6. 조명 생성하기

WIGWAG·2023년 3월 30일
0

OpenGL

목록 보기
7/10
post-custom-banner

버텍스 세이더 수정

전체 변환을 계산하고 월드 좌표와 노말을 프래그먼트에 넘겨준다.

#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(); // 이벤트 처리 시작 
}

실행화면

profile
윅왁의 프로그래밍 개발노트
post-custom-banner

0개의 댓글