OpenGL을 프로젝트에서 보다 사용하기 편하게 클래스를 이용해 추상화하는 과정에 대해 살펴보자.
전반적으로 크게 어려운 내용은 없다. 그냥 OpenGL에서 제공되는 함수들을 역할 별로 클래스로 감싸 보다 사용하기 쉽게 만드는 과정이다.
그 후 렌더러 클래스를 제작함으로써 이렇게 추상화한 다른 클래스들을 렌더러라는 하나의 파이프라인으로 묶어 렌더러.Draw()로 한 번에 렌더링할 수 있게 할 것이다. 이렇게 하면 무언가를 렌더링(Draw Call)할 때 추상화한 이 클래스 저 클래스 왔다갔다 하면서 복잡하게 함수를 호출할 필요 없이 렌더러라는 하나의 클래스로만 렌더링 통제가 가능해진다.

코드 구조를 살펴보면 기존 openGL에서 제공하던 오브젝트들을 다음과 같이 클래스로 나누었다.
IndexBuffer, Shader, Vertex Array, Vertex Buffer, VertexBufferLayout
(이 중 VertexBufferLayout은 코드가 길지 않아 헤더에 구현도 같이 들어있어서 .cpp가 따로 없다)
그리고 화면에 DrawCall을 하는 것과 관련된 내용들을 처리하는 Renderer 라는 클래스를 만들었다.
분량 상 세부적인 코드까지는 일일히 다루지 않으나, 기존에 사용하던 OpenGL 함수들을 클래스와 메소드로 묶어 추상화했다고 이해하면 된다.
이렇게 추상화한 클래스를 실제로 사용하는 부분인 Application.cpp는 다음과 같다.
// Include GLEW
#include <GL/glew.h>
// Include GLFW
#include <GLFW/glfw3.h>
#include <iostream>
#include "VertexBuffer.h"
#include "VertexArray.h"
#include "IndexBuffer.h"
#include "Shader.h"
#include "Renderer.h"
GLFWwindow* InitWindow()
{
// Initialise GLFW
if( !glfwInit() )
{
fprintf( stderr, "Failed to initialize GLFW\n" );
getchar();
return nullptr;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Open a window and create its OpenGL context
GLFWwindow* window = glfwCreateWindow( 1024, 768, "Tutorial 02 - Red triangle", NULL, NULL);
if( window == NULL ){
fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" );
getchar();
glfwTerminate();
return nullptr;
}
glfwMakeContextCurrent(window);
// Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
getchar();
glfwTerminate();
return nullptr;
}
std::cout << "Using GL Version: " << glGetString(GL_VERSION) << std::endl;
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
return window;
}
int main( void )
{
GLFWwindow* window = InitWindow();
if (!window)
return -1;
float positions[] = {
-0.5f, -0.5f, // 0
0.5f, -0.5f, // 1
0.5f, 0.5f, // 2
-0.5f, 0.5f // 3
};
unsigned int indices[] = {
0, 1, 2,
2, 3, 0
};
{
VertexArray va;
VertexBuffer vb(positions, 4 * 2 * sizeof(float));
IndexBuffer ib(indices, 6);
VertexBufferLayout layout;
layout.AddFloat(2);
va.AddBuffer(vb, layout);
Shader shader("res/shaders/Basic.shader");
shader.Bind();
float red = 0.0f;
float step = 0.05f;
Renderer renderer;
do {
renderer.Clear();
/*
지금 구조는 매 DrawCall 루프마다 shader의 색상 uniform을 변경해주고
다시 binding해주는 방식으로 색을 매 루프마다 변화시키고 있으며,
때문에 renderer.Draw()의 인자로 shader 또한 넘겨주고 있는데,
앞으로 매터리얼을 배우면 당연히 색상 변화는 셰이더를 직접 수정하는 것 대신
매터리얼만 변경해주는 형태로 구현할 것이며, 그렇게 되면 Draw()에 셰이더를 넘겨줄 필요도 없게 된다.
*/
shader.Bind();
shader.SetUniform4f("u_Color", red, 0.3, 0.8, 1.0);
renderer.Draw(va, ib, shader);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
// increment red
if (red < 0.0f || red > 1.0f)
step *= -1.0;
red += step;
} // Check if the ESC key was pressed or the window was closed
while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0 );
}
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
}
렌더러 클래스의 내부는 다음과 같다.
헤더
#pragma once
#include <GL/glew.h>
#include "Debug.h"
#include "VertexArray.h"
#include "IndexBuffer.h"
#include "Shader.h"
class Renderer
{
public:
void Clear() const;
void Draw(const VertexArray& va, const IndexBuffer& ib, const Shader& shader) const;
};
cpp
#include "Renderer.h"
#include <iostream>
void Renderer::Clear() const
{
GLCall( glClear( GL_COLOR_BUFFER_BIT ) );
}
void Renderer::Draw(const VertexArray& va, const IndexBuffer& ib, const Shader& shader) const
{
shader.Bind();
va.Bind();
ib.Bind();
GLCall( glDrawElements(GL_TRIANGLES, ib.GetCount(), GL_UNSIGNED_INT, nullptr) );
}
'computer graphics > OpenGL' 카테고리의 다른 글
[OpenGL] 10. Blending (0) | 2022.04.16 |
---|---|
[OpenGL] 9. Textures (0) | 2022.04.09 |
[OpenGL] 7. Vertex Array Object (VAO) (0) | 2022.03.01 |
[OpenGL] 6. Uniform (0) | 2022.02.27 |
[OpenGL] 5. Error Handling (1) (0) | 2022.02.24 |