이번 시간에는 EBO를 사용해 다양한 도형을 그려보고 콜벡 함수를 사용해 응용 프로그램을 만들어보도록 하겠다.
구체적으로 이번 프로젝트에서 구현할 목록은 다음과 같다.
● 점, 선, 삼각형, 사각형, 오각형, 육각형 도형 그리기
● GameObjectArray를 이용하여 도형 오브젝트 관리하는 프레임워크 구현
● 지정 번호를 눌러 도형 선택(1: 점 / 2: 선 / 3: 삼각형 / 4: 사각형 / 5: 오각형 / 6: 육각형)
● 마우스 클릭 한 위치에 지정한 도형 그리기
01. 프레임워크 구성
우선, 프로젝트를 진행하기 위한 프레임워크를 구성해야한다.
위 그림에서 각 클래스와 헤더 파일의 역할은 다음과 같다.
main | 응용 프로그램 |
pch | 미리 컴파일된 헤더 |
ObjectManager | 오브젝트를 관리할 매니저 클래스 |
Object | 오브젝트 클래스 |
Figure | 도형 정의 클래스 |
1) pch.h
#pragma once
#include <iostream>
#include <gl/glew.h>
#include <gl/freeglut.h>
#include <gl/freeglut_ext.h>
#include <gl/glm/glm.hpp>
#include <gl/glm/ext.hpp>
#include <gl/glm/gtc/matrix_transform.hpp>
#include <vector>
#pragma comment(lib, "glew32.lib")
#pragma comment(lib, "freeglut.lib")
#define _CRT_SECURE_NO_WARNINGS
#define WIDTH 800
#define HEIGHT 600
pch.h 파일은 프리컴파일 헤더(Precompiled Header)로 프로젝트에 사용할 헤더 및 define 변수들을 정의하면 된다.
헤더를 미리 컴파일하기 위해 [프로젝트] -> [속성] -> [C/C++] -> [미리 컴파일된 헤더]로 들어가서 pch.h 헤더파일을 지정해줘야 한다.
2) Figure
#pragma once
#include "pch.h"
class Figure
{
public:
// 삼각형
static GLfloat TriangleVertexs[9];
static GLfloat TriangleColors[9];
static GLint TriangleIndecies[3];
// 사각형
static GLfloat RectVertexs[12];
static GLfloat RectColors[12];
static GLint RectIndecies[6];
// 오각형
static GLfloat PentaVertexs[15];
static GLfloat PentaColors[15];
static GLint PentaIndecies[12];
// 육각형
static GLfloat HexaVertexs[18];
static GLfloat HexaColors[18];
static GLint HexaIndecies[18];
};
#include "Figure.h"
GLfloat Figure::TriangleVertexs[9] = {
0.0f, 0.1f, 0.0f,
-0.1f, -0.1f, 0.0f,
0.1f, -0.1f, 0.0f
};
GLfloat Figure::TriangleColors[9] = {
1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f
};
GLint Figure::TriangleIndecies[3] = {
0, 1, 2
};
GLfloat Figure::RectVertexs[12] = {
-0.1f, 0.1f, 0.0f,
-0.1f, -0.1f, 0.0f,
0.1f, -0.1f, 0.0f,
0.1f, 0.1f, 0.0f
};
GLfloat Figure::RectColors[12] = {
160.0f / 255.0f, 212.0f / 255.0f, 104.0f / 255.0f,
160.0f / 255.0f, 212.0f / 255.0f, 104.0f / 255.0f,
160.0f / 255.0f, 212.0f / 255.0f, 104.0f / 255.0f,
160.0f / 255.0f, 212.0f / 255.0f, 104.0f / 255.0f
};
GLint Figure::RectIndecies[6] = {
0, 1, 2,
0, 2, 3
};
GLfloat Figure::PentaColors[15] = {
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
};
GLfloat Figure::HexaColors[18] = {
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
3) Object
#pragma once
#include "pch.h"
class Object
{
private:
vec3 m_position;
vec3 m_rotate;
vec3 m_scale;
highp_vec3 m_colors;
bool m_bActive;
public:
vector<GLfloat> m_pos;
vector<GLfloat> m_col;
vector<GLint> m_index;
public:
Object();
~Object();
void SetPosition(float x, float y, float z);
void SetRotate(float x, float y, float z);
void SetScale(float x, float y, float z);
void SetActive(bool bActive);
void Move(float x, float y, float z);
void Rotate(float x, float y, float z);
void Scale(float x, float y, float z);
bool IsActive();
};
#include "Object.h"
Object::Object()
{
m_position = vec3(0.f);
m_rotate = vec3(0.f);
m_scale = vec3(1.f);
m_bActive = true;
}
Object::~Object()
{
}
void Object::SetPosition(float x, float y, float z)
{
m_position.x = x;
m_position.y = y;
m_position.z = z;
}
void Object::SetRotate(float x, float y, float z)
{
}
void Object::SetScale(float x, float y, float z)
{
}
void Object::SetActive(bool bActive)
{
m_bActive = bActive;
}
void Object::Move(float x, float y, float z)
{
}
void Object::Rotate(float x, float y, float z)
{
}
void Object::Scale(float x, float y, float z)
{
}
bool Object::IsActive()
{
return m_bActive;
}
4) ObjectManager
#pragma once
#include "pch.h"
#include "Object.h"
#include "Figure.h"
class ObjectManager
{
public:
vector<Object*> m_ObjectList;
public:
ObjectManager();
~ObjectManager();
void CreateTriangle(int* idx);
void CreateRect(int* idx);
void SetPosition(int idx, float x, float y, float z);
void Reset();
bool IsActive(int idx);
};
#include "ObjectManager.h"
ObjectManager::ObjectManager()
{
}
ObjectManager::~ObjectManager()
{
for (int i = 0; i < m_ObjectList.size(); i++)
{
delete m_ObjectList[i];
}
}
void ObjectManager::CreateTriangle(int* idx)
{
*idx += 1;
Object* object = new Object();
for (int i = 0; i < 9; i++) object->m_pos.emplace_back(Figure::TriangleVertexs[i]);
for (int i = 0; i < 9; i++) object->m_col.emplace_back( Figure::TriangleColors[i]);
for (int i = 0; i < 3; i++) object->m_index.emplace_back(Figure::TriangleIndecies[i]);
m_ObjectList.emplace_back(object);
}
void ObjectManager::CreateRect(int* idx)
{
}
void ObjectManager::SetPosition(int idx, float x, float y, float z)
{
if (m_ObjectList.empty()) return;
m_ObjectList[idx]->SetPosition(x, y, z);
}
void ObjectManager::Reset()
{
m_ObjectList.clear();
}
bool ObjectManager::IsActive(int idx)
{
return m_ObjectList[idx]->IsActive();
}
5) main
#include "pch.h"
#include "ObjectManager.h"
#define BYTE_SIZE_TRIANGLE 36
using namespace std;
// 콜벡 함수
GLvoid Render(GLvoid);
GLvoid Reshape(int w, int h);
// VAO, VBO
GLuint VAO, VBO[2], EBO;
GLchar* vertexSource, * fragmentSource; //--- 소스코드 저장 변수
GLuint vertexShader, fragmentShader; //세이더 객체
GLuint shaderProgramID; // 세이더 프로그램
GLint CreateShader(const char* file, int type);
GLvoid CreateShaderProgram();
GLvoid InitBuffer();
GLvoid InitObjects();
// 삼각형 그리기 함수
void DrawObjects(int idx);
void DrawTriangle();
// 오브젝트 리스트
ObjectManager* m_ObjectManager = new ObjectManager();
void main(int argc, char** argv)
{
// 윈도우 생성
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(0, 0);
glutInitWindowSize(WIDTH, HEIGHT);
glutCreateWindow("Draw Triangle");
//--- GLEW 초기화하기
glewExperimental = GL_TRUE;
glewInit();
InitBuffer();
CreateShaderProgram();
glutDisplayFunc(Render);
glutMainLoop();
}
GLvoid Reshape(int w, int h)
{
// 뷰포트 기본 WIDTH HEIGHT로 설정
glViewport(0, 0, w, h);
}
GLvoid InitBuffer()
{
glGenVertexArrays(1, &VAO);
glGenBuffers(2, VBO);
glGenBuffers(1, &EBO);
InitObjects();
}
GLvoid InitObjects()
{
m_ObjectManager->Reset();
int idx = 0;
m_ObjectManager->CreateTriangle(&idx);
}
char* GetBuf(const char* file)
{
FILE* fptr;
long length;
char* buf;
// 파일 읽기 형식으로 열기
fopen_s(&fptr, file, "rb");
// 예외처리
if (!fptr) return NULL;
// 파일 buf로 변환
fseek(fptr, 0, SEEK_END);
length = ftell(fptr);
buf = (char*)malloc(length + 1);
fseek(fptr, 0, SEEK_SET);
fread(buf, length, 1, fptr);
// 파일 종료
fclose(fptr);
buf[length] = 0;
return buf;
}
GLint CreateShader(const char* file, int type)
{
// glsl 파일 읽기
GLchar* source = GetBuf(file);
// 객체 생성
GLint shader = glCreateShader(type);
glShaderSource(shader, 1, (const GLchar**)&source, 0);
glCompileShader(shader);
// 컴파일 에러 체크
GLint result;
GLchar errorLog[512];
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
if (!result)
{
glGetShaderInfoLog(shader, 512, NULL, errorLog);
// std::cerr << "ERROR: 컴파일 실패\n" << errorLog << std::endl;
return 0;
}
return shader;
}
void CreateShaderProgram()
{
vertexShader = CreateShader("vertex.glsl", GL_VERTEX_SHADER);
fragmentShader = CreateShader("fragment.glsl", GL_FRAGMENT_SHADER);
// 세이더 프로그램 생성
shaderProgramID = glCreateProgram();
glAttachShader(shaderProgramID, vertexShader);
glAttachShader(shaderProgramID, fragmentShader);
glLinkProgram(shaderProgramID);
// 세이더 삭제
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// 세이더 프로그램 사용
glUseProgram(shaderProgramID);
}
GLvoid Render()
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
for (int i = 0; i < m_ObjectManager->m_ObjectList.size(); i++)
{
if (m_ObjectManager->m_ObjectList[i]->IsActive())
{
DrawObjects(i);
}
}
glutSwapBuffers();
}
void DrawObjects(int idx)
{
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, m_ObjectManager->m_ObjectList[idx]->m_pos.size() * 4, &m_ObjectManager->m_ObjectList[idx]->m_pos[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_ObjectManager->m_ObjectList[idx]->m_index.size() * 4, &m_ObjectManager->m_ObjectList[idx]->m_index[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, m_ObjectManager->m_ObjectList[idx]->m_col.size() * 4, &m_ObjectManager->m_ObjectList[idx]->m_col[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glDrawElements(GL_TRIANGLES, m_ObjectManager->m_ObjectList[idx]->m_index.size(), GL_UNSIGNED_INT, 0);
}
'프로그래밍 > OpenGL' 카테고리의 다른 글
[OpenGL] 오픈지엘 EBO를 이용한 3차원 도형 그리기 (0) | 2024.02.13 |
---|---|
[OpenGL] 오픈지엘 3차원 큐브 그리기 (1) | 2024.02.09 |
[OpenGL] 오픈지엘 EBO를 이용한 사각형 그리기 (0) | 2024.02.08 |
[OpenGL] 오픈지엘 VAO와 VBO를 이용한 삼각형 그리기 (0) | 2024.02.06 |
[OpenGL] 오픈지엘 GLSL 쉐이더 적용 (0) | 2024.02.05 |