본문 바로가기

프로그래밍/OpenGL

[OpenGL] 오픈지엘 3차원 큐브 그리기

이번 시간에는 3차원 도형 큐브를 그려보겠다.

 

전체코드

 

| vertex.glsl

#version 330 core

layout(location=0) in vec3 vPos;
layout(location=1) in vec3 vColor;
out vec3 outColor;

uniform mat4 trans;

void main()
{
	gl_Position = trans * vec4(vPos,1.0);
	outColor=vColor;
}

 

| fragment.glsl

#version 330 core

out vec4 Fragcolor;
in vec3 outColor;

void main()
{
	Fragcolor = vec4(outColor.r, outColor.g, outColor.b, 1.0);
}

 

| main.cpp

#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>

#pragma comment(lib, "glew32.lib")
#pragma comment(lib, "freeglut.lib")

#define _CRT_SECURE_NO_WARNINGS

#define WIDTH 800
#define HEIGHT 600

#define BYTE_SIZE_RECT 48

using namespace std;

// 콜벡 함수
GLvoid Render(GLvoid);
GLvoid Reshape(int w, int h);

// VAO, VBO
GLuint VAO, VBO[2], EBO;

void DrawCube();

GLchar* vertexSource, * fragmentSource; // 소스코드 저장 변수
GLuint vertexShader, fragmentShader; //세이더 객체
GLuint shaderProgramID; // 세이더 프로그램

GLint CreateShader(const char* file, int type);
GLvoid CreateShaderProgram();

GLvoid InitBuffer();

void main(int argc, char** argv)
{
	// 윈도우 생성
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(0, 0);
	glutInitWindowSize(WIDTH, HEIGHT);
	glutCreateWindow("Draw Rect by using EBO");

	// GLEW 초기화하기
	glewExperimental = GL_TRUE;
	glewInit();

	InitBuffer();
	CreateShaderProgram();

	glutDisplayFunc(Render);

	glutMainLoop();
}

GLvoid Render()
{
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glUseProgram(shaderProgramID);

	DrawCube();
	glutSwapBuffers();
}

GLvoid Reshape(int w, int h)
{
	// 뷰포트 기본 WIDTH HEIGHT로 설정
	glViewport(0, 0, w, h);
}

GLvoid InitBuffer()
{
	glGenVertexArrays(1, &VAO);
	glGenBuffers(2, VBO);
	glGenBuffers(1, &EBO);
}

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);
}

void DrawCube()
{
	GLfloat CubeVertexs[24] = {
			-0.5f, 0.5f, -0.5f,  //0번점
			-0.5f, 0.5f, 0.5f,  //1번점
			0.5f, 0.5f, 0.5f,  //2번점
			0.5f, 0.5f, -0.5f,  //3번점

			-0.5f, -0.5f, -0.5f,  //4번점
			-0.5f, -0.5f, 0.5f,  //5번점
			0.5f, -0.5f, 0.5f,  //6번점
			0.5f, -0.5f, -0.5f,  //7번점
	};

	GLfloat CubeColors[24] = {
				0.0f, 1.0f, 0.0f,  //0번점
				0.0f, 1.0f, 1.0f,  //1번점
				0.0f, 1.0f, 0.0f,  //2번점
				1.0f, 1.0f, 0.0f,  //3번점

				1.0f, 0.0f, 1.0f,  //4번점
				0.0f, 0.0f, 1.0f,  //5번점
				0.0f, 0.0f, 0.0f,  //6번점
				1.0f, 0.0f, 0.0f,  //7번점
	};

	GLint CubeIndexs[36] =
	{
		0,1,2,
		0,2,3,  //윗면

		1,5,6,
		1,6,2, //앞면

		2,6,7,
		2,7,3, //우측면

		0,4,5,
		0,5,1, //좌측면

		5,4,6,
		4,7,6,// 밑면

		0,7,4, //뒷면
		0,3,7
	};

	// VAO 바인드
	glBindVertexArray(VAO);

	// 큐브 위치 버퍼 바인드
	glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(CubeVertexs), CubeVertexs, GL_STATIC_DRAW);

	// 큐브 인덱스 버퍼 바인드
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(CubeIndexs), CubeIndexs, GL_STATIC_DRAW);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
	glEnableVertexAttribArray(0);

	// 큐브 색상 버퍼 바인드
	glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(CubeColors), CubeColors, GL_STATIC_DRAW);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
	glEnableVertexAttribArray(1);

	// 모델 location 인덱스 저장
	unsigned int modelLocation = glGetUniformLocation(shaderProgramID, "trans");

	// 모델 및 변환 변수 초기화
	glm::mat4 model = glm::mat4(1.0f);
	glm::mat4 scale = glm::mat4(1.0f);
	glm::mat4 rot = glm::mat4(1.0f);
	glm::mat4 move = glm::mat4(1.0f);

	// 변환
	scale = glm::scale(scale, glm::vec3(0.5f, 0.6f, 0.5f));
	move = glm::translate(move, glm::vec3(0.0f, 0.0f, 0.0f));
	rot = glm::rotate(rot, glm::radians(30.0f), glm::vec3(1.0f, 0.0f, 0.0f));
	rot = glm::rotate(rot, glm::radians(30.0f), glm::vec3(0.0f, 1.0f, 0.0f));

	// 변환 과정 처리
	model = model * scale * move * rot;

	// 모델 변환 적용
	glUniformMatrix4fv(modelLocation, 1, GL_FALSE, glm::value_ptr(model));	

	// 큐브 그리기
	glDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_INT, 0);

	// 버퍼 해제
	glDisableVertexAttribArray(0);
	glDisableVertexAttribArray(1);
}

 

3차원 큐브 그리기 성공