OpenGL

OpenGL 공부하기 #1 - 윈도우 생성

NAEU 2025. 6. 24. 01:36

그래픽스 파이프라인과 3D 공간에 대해 이해하는 것을 우선으로 진행하는 시리즈입니다.

첫번째 목표는 "FBX 로더 구현해보기"입니다.

다뤄지는 내용은 대부분 https://learnopengl.com/ 을 기반으로 학습합니다.

OpenGL은 거대한 스테이트 머신

따라서 Context가 존재
Context는 렌더링을 위한 모든 정보를 담고 있는 데이터 구조
Context는 여러개 생성하여 병렬로 사용 가능

OpenGL을 사용하기 위한 세팅

2개의 라이브러리가 필요함
glfw: 기본적인 윈도우와 이벤트에 대한 것
glad: opengl함수를 사용할 수 있도록하는 것

glfw 함수

glfwinit();

glfw를 초기화하는 함수
초기화 이후에만 사용 가능

glfwWindowHint(int hint, int value);

window와 context에 적용될 설정을 미리 지정

glfwCreateWindow(int width, int height, const char *title, GLFWmonitor *monitor, GLFWwindow *share);

대입한 크기의 윈도우 창을 생성

glfwMakeContextCurrent(GLFWwindow* window);

opengl의 context를 대입한 윈도우에 바인딩함
해당 윈도우의 컨텍스트를 현재 스레드에 활성화(현재 컨텍스트로 설정)

glfwTerminate();

glfw를 종료

glfwWindowShouldClose(GLFWwindow* window);

glfw가 종료되는지 확인함
종료 지시받을시 true

glfwPollEvents();

입력 신호 (키보드 및 마우스)를 감지하고 참 상태를 업데이트함

glfwSwapBuffers(GLFWwindow* window);

화면 버퍼를 전환함

glfwGetProcAddress (GLADloadproc로 cast하여 glad에서 사용)

각 OS별로 OpenGL의 함수의 위치가 다르기 때문에 해당 위치를 반환함

glad 함수

gladLoadGLLoader(GLADloadproc load);

불러온 OpenGL의 함수 포인터들을 런타임에서 동적으로 로드함
OpenGL 함수 포인터들을 시스템에서 가져와서 사용할 수 있게 만듬

glViewport(GLint x, GLint y, GLsizei width, GLsizei height);

GLint와 GLsizei는 모두 int임
좌측 상단을 (0, 0) 기준으로 하여 OpenGL이 렌더링될 영역을 지정
실제 glfw로 지정한 윈도우 창의 크기보다 작게하여 일부 부분만 렌더링 영역으로 지정 가능

glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);

화면(컬러 버퍼)을 지울 때 사용할 배경 색상을 설정

glClear(GLbitfield mask);

현재 설정된 색상(또는 깊이 등)으로 버퍼를 실제로 지움

  • GL_COLOR_BUFFER_BIT 컬러 버퍼 지움
  • GL_DEPTH_BUFFER_BIT 깊이 버퍼 지움 (3D에서 Z 정렬용)
  • GL_STENCIL_BUFFER_BIT 스텐실 버퍼 지움
    clear한다는 것은 설정한 색으로 전체를 칠한다는 것과 같음

Swap Buffer

모니터에 연산된 결과를 출력할 때 단일 버퍼를 사용한다면 이미지들은 즉시 모든 픽셀에 그려지지 않고 한 픽셀씩 지나가면서 그려짐
따라 이를 감추고 한번에 보여주기 위해 2개의 버퍼를 사용하는 Double Buffer 방식을 사용
보통 백 버퍼(Back Buffer)와 앞 버퍼(Front Buffer)로 불림
백 버퍼에서 화면에 출력될 이미지를 전부 그리면 버퍼의 포인터를 앞 버퍼와 교체하여 모니터에 한번에 이미지가 보여지게 됨
또한 백 버퍼와 교체된 앞 버퍼는 이제 백 버퍼의 역할이 되어 다음 프레임에 그려질 이미지를 로드함
만약 glClear();를 호출한다면 백 버퍼에 적용됨
그 후, 백 버퍼에 도형들을 그리는 순서이기에 clear를 호출하지 않는다면 새로 그리지 않는 부분에는 이전 프레임의 잔상이 남을 수 있음

 

#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>

void processInput(GLFWwindow* window)
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
	{
		glfwSetWindowShouldClose(window, true);
	}
}

int main()
{
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	GLFWwindow* m_window = glfwCreateWindow(800, 800, "title", NULL, NULL);
	if (m_window == NULL)
	{
		std::cout << "Fail to create window" << std::endl;
		glfwTerminate();
		return -1;
	}

	glfwMakeContextCurrent(m_window);

	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Fail to initialize GLAD" << std::endl;
		return -1;
	}

	glViewport(0, 0, 800, 800);

	while (!glfwWindowShouldClose(m_window))
	{
		// input
		processInput(m_window);

		// render
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		// check and call event and swap
		glfwPollEvents();
		glfwSwapBuffers(m_window);
	}

	glfwTerminate();

	return 0;
}

출력된 윈도우 창