이번 시간에는 오픈지엘에서 여러가지 도형을 화면에 그려보는 시간을 가지겠다.
지난 시간에 작성한 세이더 프로그램을 이용하여 도형을 그리기 위해서는 다음 개념이 필요하다.
● Vertex Array Object (VAO)
● Vertex Buffer Objects (VBO)
VBO란 정점 데이터를 저장하기 위한 메모리 버퍼로 속성 값으로 Position, Normal, Color 등을 저장한다.
VAO는 한 개 이상의 VBO를 포함한 객체의 정보를 저장하는 메모리 버퍼이다.
즉, 어떤 오브젝트를 그릴 때 오브젝트가 갖고 있는 속성(위치, 색상 등)의 정보를 담고 있는 버퍼가 VBO이고
그 속성들의 정보값의 위치를 갖고 있는 버퍼가 VAO이다.
개념은 이해했으니 실제로 VAO와 VBO를 이용하여 간단한 삼각형을 그려보자.
오픈지엘에서 삼각형을 그리는 과정은 다음과 같다.
01. 버퍼 생성
// VAO, VBO
GLuint VAO, VBO[2]
GLvoid InitBuffer()
{
glGenVertexArrays(1, &VAO);
glGenBuffers(2, VBO);
}
우선, 그릴 도형의 위치, 색상 속성값을 저장할 VBO 2개와 VAO 1개를 생성한다.
02. 오브젝트 배열 생성
void DrawTriangle()
{
// 삼각형 위치
const float vertexPosition[] =
{
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
// 삼각형 색상
const float vertexColor[] =
{
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0
};
...
}
03. VAO, VBO 버퍼 바인드 및 속성 값 저장하고 각각 세이더에 전달하기
void DrawTriangle()
{
...
// VAO 바인드
glBindVertexArray(vao);
// 삼각형 위치 버퍼 바인드
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, BYTE_SIZE_TRIANGLE * 1, vertexPosition, 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, BYTE_SIZE_TRIANGLE * 1, vertexColor, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glEnableVertexAttribArray(1);
...
}
glBufferData 함수와 glVertexAtrribPointer 함수의 매개변수 값은 다음과 같다.
● glBufferData
glBufferData | GLenum target | GLsizeiptr size | const void * data | GLenum usage |
사용 버퍼 종류 | 버퍼 사이즈 | 버퍼 | 사용 패턴 |
- target으로 대표적으로 쓰이는 버퍼
GL_ARRAY_BUFFER | Vertex attributes |
GL_ELEMENT_ARRAY_BUFFER | Vertex array indices (EBO 이용) |
● glVertexAtrribPointer
glVertexAtrribPointer | GLuint index | GLint size | GLenum type | GLboolean normalized | GLsizei stride | const void * pointer |
설정할 vertex 속성 인덱스 | vertex 크기 | 데이터 타입 | 정규화 여부 | vertex 사이 공백 크기 | 데이터 시작 위치 값(초기 0) |
glVertexAtrribPointer을 사용하여 위치 속성을 0번 인덱스 색상 속성을 1번 인덱스에 설정해야한다.
우리는 이전에 세이더 코드에 layout (location = index)을 이용하여 설정한 것을 알 수 있다.
#version 330 core
layout (location = 0) in vec3 in_Position; <-- 0번 인덱스로 position 정보를 받겠다.
layout (location = 1) in vec3 in_Color; <-- 1번 인덱스로 color 정보를 받겠다.
out vec3 out_Color;
void main(void)
{
gl_Position = vec4 (in_Position.x, in_Position.y, in_Position.z, 1.0);
out_Color = in_Color;
}
04. 도형 그리기
void DrawTriangle()
{
...
// 삼각형 그리기
glDrawArrays(GL_TRIANGLES, 0, 3 * 1);
}
● glDrawArrays
glDrawArrays | GLenum mode | GLint first | GLsizei count |
프리미티브 render 종류 | 버퍼 시작 위치 | 그릴 정점 개수 |
- mode로 대표적으로 쓰이는 값
GL_POINTS | 포인트로 그리기 |
GL_LINES | 라인으로 그리기 |
GL_LINE_LOOP |
라인으로 끊지 않고 계속해서 그리기 |
GL_TRIANGLES | 삼각형으로 그리기 |
전체코드
#include <iostream>
#include <gl/glew.h>
#include <gl/freeglut.h>
#include <gl/freeglut_ext.h>
#pragma comment(lib, "glew32.lib")
#pragma comment(lib, "freeglut.lib")
#define _CRT_SECURE_NO_WARNINGS
#define WIDTH 800
#define HEIGHT 600
#define BYTE_SIZE_TRIANGLE 36
using namespace std;
// 콜벡 함수
GLvoid Render(GLvoid);
GLvoid Reshape(int w, int h);
// VAO, VBO
GLuint vao, vbo[2];
// 삼각형 그리기 함수
void DrawTriangle();
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 Triangle");
//--- GLEW 초기화하기
glewExperimental = GL_TRUE;
glewInit();
InitBuffer();
CreateShaderProgram();
glutDisplayFunc(Render);
glutMainLoop();
}
GLvoid Render()
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
DrawTriangle();
glutSwapBuffers();
}
GLvoid Reshape(int w, int h)
{
// 뷰포트 기본 WIDTH HEIGHT로 설정
glViewport(0, 0, w, h);
}
GLvoid InitBuffer()
{
glGenVertexArrays(1, &vao);
glGenBuffers(2, vbo);
}
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 DrawTriangle()
{
// 삼각형 버퍼 생성
const float vertexPosition[] =
{
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
const float vertexColor[] =
{
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0
};
// VAO 바인드
glBindVertexArray(vao);
// 삼각형 위치 버퍼 바인드
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, BYTE_SIZE_TRIANGLE * 1, vertexPosition, 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, BYTE_SIZE_TRIANGLE * 1, vertexColor, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glEnableVertexAttribArray(1);
// 삼각형 그리기
glDrawArrays(GL_TRIANGLES, 0, 3 * 1);
}
| Reference
https://registry.khronos.org/OpenGL-Refpages/gl4/html/glBufferData.xhtml
https://registry.khronos.org/OpenGL-Refpages/gl4/html/glVertexAttribPointer.xhtml
https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDrawArrays.xhtml
'프로그래밍 > OpenGL' 카테고리의 다른 글
[OpenGL] 오픈지엘 EBO를 이용한 2차원 도형 그리기 및 응용 (0) | 2024.02.09 |
---|---|
[OpenGL] 오픈지엘 EBO를 이용한 사각형 그리기 (0) | 2024.02.08 |
[OpenGL] 오픈지엘 GLSL 쉐이더 적용 (0) | 2024.02.05 |
[OpenGL] 오픈지엘 그래픽스 파이프라인 (0) | 2024.02.04 |
[OpenGL] 오픈지엘 콜벡 함수 (0) | 2024.02.03 |