- 로봇 그리기
- 육면체를 사용하여 무대를 그리고, 키보드를 누르면 무대의 앞면이 위로 슬라이딩하여 열린다.
- 무대는 육면을 가지고 있다. 각각 다른색으로 구현한다.
- 육면은 각각 사각형으로 그려져 있고, 뒷면 제거를 적용한다 (GL_CULL_FACE)
- o/O: 앞면이 올라간다.
- 무대 위에는 로봇이 팔을 흔들며 걷고 있다.
- 로봇은 머리, 몸통, 양 팔, 양 다리가 있고 팔, 다리를 흔들며 걷는다.
- 머리의 앞면에 코를 붙이고(앞뒤 구분), 양팔과 양 다리는 다른색을 사용한다.(방향 구분)
- 키보드 명령어를 사용하여 좌우로 이동 방향을 움직인다.
- w/a/s/d: 로봇이 앞/뒤/좌/우 방향으로 이동 방향을 바꿔서 걷는다. 가장자리에 도달하면 반대방향으로 방향을 바꿔 걷는다.
- j/J: 로봇이 제자리에서 점프한다.
- i/I: 모든 변환을 리셋하고 다시 시작
- q/Q: 프로그램 종료
- 카메라 설정: 키보드 명령으로 카메라 이동
- z/Z: 앞뒤로 이동
- y/Y: 카메라 기준 y축에 대하여 자전
- r/R: 카메라가 화면의 중심 y축을 기준으로 공전
월드 좌표계를 유저의 시점인 view space로 변환한다.
뷰잉변환함수
glm::mat4 glm::lookAt (vec3 const &cameraPos, vec3 const &cameraDirection, vec3 const &cameraUp);
객체가 놓이는 공간 설정을 설정한다.
원근투영함수
glm:: mat4 glm::perspective (float fovy, float aspect, float near, float far);
#version 330 core
layout (location = 0) in vec3 vPos;
layout (location = 1) in vec3 vColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec3 passColor;
void main()
{
gl_Position = projection * view * model * vec4(vPos, 1.0);
passColor = vColor;
}
ShaderManger
클래스
// 세이더 파일 코드를 버퍼에 저장한다.
char* File_To_Buf(const char* file);
// 세이더 프로그램을 생성한다.
bool Init_Program(GLuint& shader_program_ID);
Shape
클래스
// 오브젝트를 색칠한다.
virtual void Color();
// 오브젝트의 색상 데이터를 수정한다.
virtual void Set_Colors(vector<glm::vec3> colors);
// 오브젝트 파일의 버텍스 속성정보를 버퍼에 저장한다.
bool loadOBJ(const char* path);
// VAO와 VBO를 설정한다.
virtual bool Init_VAO(GLuint shader_program_ID);
Cube
클래스(Shape
클래스를 상속함)
// 오브젝트를 색칠한다.(오버라이딩)
virtual void Color();
Stage
클래스(Shape
클래스를 상속함)
//Stage를 제작하고 화면에 그린다.
void Init_And_Render(int model)
// 오브젝트를 색칠한다.(오버라이딩)
virtual void Color();
Face
클래스(Shape
클래스를 상속함)
//Face를 제작하고 화면에 그린다.
void Init_And_Render(int model)
// VAO와 VBO를 설정한다.(오버라이딩)
virtual bool Init_VAO(GLuint shader_program_ID);
Robot
클래스
//Robot을 제작하고 화면에 그린다.
void Init_And_Render(int model)
//왼쪽 다리을 제작하고 화면에 그린다.
Init_And_Render_Left_Leg(model);
//오른쪽 다리을 제작하고 화면에 그린다.
Init_And_Render_Right_Leg(model);
//몸통을 제작하고 화면에 그린다.
Init_And_Render_Torso(model);
//왼쪽 팔을 제작하고 화면에 그린다.
Init_And_Render_Left_Arm(model);
//오른쪽 팔을 제작하고 화면에 그린다.
Init_And_Render_Right_Arm(model);
//머리을 제작하고 화면에 그린다.
Init_And_Render_Head(model);
//코를 제작하고 화면에 그린다.
Init_And_Render_Nose(model);
Camera
클래스
//뷰잉 행렬을 설정한다.
void Init_View(GLuint shader_program_ID)
//투영 행렬을 설정한다.
void Init_Projection(GLuint shader_program_ID)
Stage
클래스의 Init_And_Render
함수
void Init_And_Render(int model) {
glm::mat4 m_transform = glm::mat4(1.0f);
//이동 변환
m_transform = glm::translate(m_transform, glm::vec3(0.0, 0.0, 0.0));
//스케일 변환
m_transform = glm::scale(m_transform, glm::vec3(5.0, 5.0, 5.0));
// uniform 변수에 모델링변환 행렬 주소를 저장한다.
glUniformMatrix4fv(model, 1, GL_FALSE, glm::value_ptr(m_transform));
glBindVertexArray(VAO_ID);
//렌더링
glDrawArrays(GL_TRIANGLES, 0, NUMOF_VERTICES);
}
Camera
클래스의 Init_View
함수
void Init_View(GLuint shader_program_ID) {
//뷰 행렬 설정
v_transform = glm::lookAt(cameraPos, cameraDirection, cameraUp);
//회전 변환(카메라 공전)
v_transform = glm::rotate(v_transform, glm::radians(rotation), glm::vec3(0.0, 1.0, 0.0));
//이동 변환
v_transform = glm::translate(v_transform, glm::vec3(0.0, 0.0, -10.0f + z_move));
//회전 변환(카메라 자전)
v_transform = glm::rotate(v_transform, glm::radians(revolution), glm::vec3(0.0, 1.0, 0.0));
// 프로그램에서 uniform 변수의 위치를 가져온다
int view = glGetUniformLocation(shader_program_ID, "view");
// uniform 변수에 뷰잉변환 행렬 주소를 저장한다.
glUniformMatrix4fv(view, 1, GL_FALSE, glm::value_ptr(v_transform));
}
main.cpp
#include "stdafx.h"
#include "Shape.h"
#include "ShaderManager.h"
#include "Stage.h"
#include "Face.h"
#include "Camera.h"
#include "Robot.h"
GLvoid drawScene(GLvoid);
GLvoid Reshape(int w, int h);
GLvoid Keyboard(unsigned char key, int x, int y);
GLvoid TimerFunction1(int value);
GLvoid TimerFunction2(int value);
GLvoid TimerFunction3(int value);
GLvoid Mouse(int button, int state, int x, int y);
GLfloat mx = 0.0f;
GLfloat my = 0.0f;
GLuint shader_program_ID;
Stage stage;
Face face;
ShaderManager sm;
Camera cam;
Robot robot;
bool isTimer1On = false;
bool isTimer2On = false;
bool isTimer3On = false;
bool isAllStop = false;
GLvoid drawScene() //--- 콜백 함수: 그리기 콜백 함수
{
//--- 변경된 배경색 설정
glClearColor(1.0f, 1.0f, 1.0f, 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);
cam.Init_View(shader_program_ID);
cam.Init_Projection(shader_program_ID);
int model = glGetUniformLocation(shader_program_ID, "model");
stage.Init_And_Render(model);
face.Init_And_Render(model);
robot.Init_And_Render(model);
glutSwapBuffers();
isAllStop = false;
}
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 'o': case 'O':
if(!isTimer1On)
glutTimerFunc(100, TimerFunction1, 1);
isTimer1On = true;
break;
case 'w':
robot.dir = FRONT;
robot.y_rotate = 0.0f;
if (!isTimer2On)
glutTimerFunc(100, TimerFunction2, 1);
isTimer2On = true;
break;
case 'a':
robot.dir = LEFT;
robot.y_rotate = -90.0f;
if (!isTimer2On)
glutTimerFunc(100, TimerFunction2, 1);
isTimer2On = true;
break;
case 's':
robot.dir = BACK;
robot.y_rotate = 180.0f;
if (!isTimer2On)
glutTimerFunc(100, TimerFunction2, 1);
isTimer2On = true;
break;
case 'd':
robot.dir = RIGHT;
robot.y_rotate = 90.0f;
if (!isTimer2On)
glutTimerFunc(100, TimerFunction2, 1);
isTimer2On = true;
break;
case 'j': case 'J':
if (robot.jump == LAND)
robot.jump = UP;
if (!isTimer3On)
glutTimerFunc(100, TimerFunction3, 1);
isTimer3On = true;
break;
case 'i': case 'I':
face.y_move = 0.0;
robot.x_move = 0.0;
robot.y_move = 0.0;
robot.z_move = 0.0;
robot.dir = STOP;
isAllStop = true;
isTimer1On = false;
isTimer2On = false;
isTimer3On = false;
break;
case 'q':
exit(1);
break;
case 'z':
//카메라 전진
cam.z_move += 0.1f;
break;
case 'Z':
//카메라 후진
cam.z_move -= 0.1f;
break;
case 'y': case 'Y':
//카메라 자전
cam.rotation += 5.0f;
break;
case 'r': case 'R':
//카메라 공전
cam.revolution += 5.0f;
break;
}
glutPostRedisplay(); //--- 배경색이 바뀔때마다 출력 콜백함수를 호출하여 화면을 refresh 한다
}
//앞면이 올라가고 로봇이 팔다리를 흔듦
GLvoid TimerFunction1(int value)
{
if (isAllStop) {
face.y_move -= face.move_rate;
return;
}
if (face.y_move < 5.0)
face.y_move += face.move_rate;
if (robot.x_rotate > 30.0f or robot.x_rotate < -30.0f)
robot.is_forward ^= 1;
if (robot.is_forward)
robot.x_rotate += robot.rotate_rate;
else
robot.x_rotate -= robot.rotate_rate;
glutPostRedisplay(); // 화면 재 출력
if (isTimer1On)
glutTimerFunc(100, TimerFunction1, 1);
}
//앞뒤좌우로 걷는다.
GLvoid TimerFunction2(int value)
{
if (robot.dir == FRONT) {
if (robot.z_move < 2.3)
robot.z_move += robot.move_rate;
else {
robot.dir = BACK;
robot.y_rotate = 180.0f;
}
}
else if (robot.dir == BACK) {
if (robot.z_move > -2.3)
robot.z_move -= robot.move_rate;
else {
robot.dir = FRONT;
robot.y_rotate = 0.0f;
}
}
else if (robot.dir == LEFT) {
if (robot.x_move > -2.2)
robot.x_move -= robot.move_rate;
else {
robot.dir = RIGHT;
robot.y_rotate = 90.0f;
}
}
else if (robot.dir == RIGHT) {
if (robot.x_move < 2.2)
robot.x_move += robot.move_rate;
else {
robot.dir = LEFT;
robot.y_rotate = -90.0f;
}
}
glutPostRedisplay(); // 화면 재 출력
if (!isAllStop && isTimer2On)
glutTimerFunc(100, TimerFunction2, 1);
}
//점프
GLvoid TimerFunction3(int value)
{
if (robot.jump == UP) {
if (robot.y_move < 0.4)
robot.y_move += robot.move_rate;
else
robot.jump = DOWN;
}
if (robot.jump == DOWN) {
if (robot.y_move >= 0.1)
robot.y_move -= robot.move_rate;
else
robot.jump = LAND;
}
glutPostRedisplay(); // 화면 재 출력
if (!isAllStop && isTimer3On)
glutTimerFunc(100, TimerFunction3, 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 (!sm.Init_Program(shader_program_ID)) {
cerr << "Error: Shader Program 생성 실패" << endl;
std::exit(EXIT_FAILURE);
}
stage.Color();
if (!stage.Init_VAO(shader_program_ID)) {
cerr << "Error: stage 생성 실패" << endl;
std::exit(EXIT_FAILURE);
}
if (!face.Init_VAO(shader_program_ID)) {
cerr << "Error: 앞면 생성 실패" << endl;
std::exit(EXIT_FAILURE);
}
for (size_t i = 0; i < Robot::MAX_BODIES; i++)
{
robot.bodies[i].Color();
if (!robot.bodies[i].Init_VAO(shader_program_ID)) {
cerr << "Error: 큐브 생성 실패" << endl;
std::exit(EXIT_FAILURE);
}
}
glutDisplayFunc(drawScene); // 출력 함수의 지정
glutReshapeFunc(Reshape); // 다시 그리기 함수 지정
glutKeyboardFunc(Keyboard);
glutMouseFunc(Mouse);
glutMainLoop(); // 이벤트 처리 시작
}