Scop 구현기 1편: 윈도우 하나 띄우는 게 뭐라고 (Object Viewer)

2025. 4. 9. 15:10·Dev/Grapics
앞선 지식들을 구현하며 공부하느라 많이 정리를 하지 못했습니다.
구현했던 순서대로 작성을 해보겠습니다!

 

윈도우를 만들기 위한 전체 코드

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <OpenGL/gl.h>
#include <iostream>

int main(void)
{
	if (!glfwInit())
	{
		std::cerr << "GFLW Init Failed" << std::endl;
		return (-1);
	}

	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

	GLFWwindow* window = glfwCreateWindow(500, 500, "scop", NULL, NULL);

	glfwMakeContextCurrent(window);
	int framebuffer_w, framebuffer_h;
	glfwGetFramebufferSize(window, &framebuffer_w, &framebuffer_h);
	glViewport(0, 0, framebuffer_w , framebuffer_h);

	if (glewInit() != GLEW_OK)
	{
		std::cerr << "GLEW Init Failed" << std::endl;
		glfwTerminate();
		return (-1);
	}

	while (!glfwWindowShouldClose(window))
	{
		glClearColor(0, 0, 0, 1);
		glClear(GL_COLOR_BUFFER_BIT);

		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	glfwTerminate();
	return (0);
}

1. OpenGL 프로젝트의 시작은 항상 창 만들기부터!

OpenGL은 "그래픽"만 담당합니다. 운영체제 창은 만들어주지 않죠.

그래서 우리는 GLFW 같은 라이브러리를 써야 해요. GLFW는 "운영체제에 독립적인 윈도우 생성 및 입력 처리"를 담당합니다.

#include <GLFW/glfw3.h>헤더를 포함한 뒤 glfw 함수를 사용하기 위해 초기화해야 합니다.

if (!glfwInit()) {
	std::cerr << "GFLW Init Failed" << std::endl;
	return (-1);
}

 

glfwInit() 은 GLFW를 사용하기 위해 라이브러리 초기화 함수입니다.

초기화가 성공하면 GLFW_TRUE(1)를 오류가 발생하면 GLFW_FALSE(0)가 반환됩니다.

실패하면 OpenGL을 시작도 못 하게 됩니다. 그래서 항상 체크해 주는 게 기본 중 기본입니다.

🧠 참고로 glfwInit은 내부적으로 OS에 맞는 초기화 루틴을 실행합니다.
예: 윈도우에서는 WinAPI 초기화, 맥에서는 Cocoa 세팅 등!

GLFW 사용이 끝나면, 일반적으로 프로그램이 종료되기 직전에 GLFW를 종료해야 합니다.

glfwTerminate ();

 

이렇게 하면 남아 있는 모든 윈도우가 삭제되고 GLFW가 할당한 다른 리소스도 해제됩니다.

이 함수를 호출한 후에는 GLFW를 다시 초기화해야 해당 리소스를 필요로 하는 GLFW함수를 사용할 수 있습니다.


2. OpenGL 3.3 Core Profile로 세팅하기

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

 

이건 뭐냐고요? 간단히 말하면,

"나는 2000년대 OpenGL 말고, 최신 방식만 쓸 거야!" 선언입니다.

  • GLFW_CONTEXT_VERSION_MAJOR, MINOR -> OpenGL 버전 지정(3.3은 안정적 + 최소 셰이더 기반 버전)
  • GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE -> 구형 API 제거, VAO/VBO 안 쓰면 에러 발생!
  • GLFW_OPENGL_FORWARD_COMPAT -> 더 이상 안 쓰는 기능 무시 (Mac에선 필수!)
이걸 안 하면 VAO 없이도 그려지는 이상한(?) 상태가 발생될 수 있어요.

 

왜 GLFW_OPENGL_CORE_PROFILE이 중요한가?

VAO 없이도 그려지는 이상한(?) 상태의 정체

glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

 

위 설정을 하지 않으면 기본적으로 Compatibility Profile로 실행될 수 있습니다.
그러면 OpenGL의 예전 방식, 예를 들면 glBegin, glVertex, glEnd와 같은 함수들이 여전히 살아있죠. 그뿐만 아니라, VAO (Vertex Array Object) 없이도 버퍼를 쓰는 게 “되는 것처럼 보이는” 상황이 발생합니다.

 

이게 왜 문제냐고요?

 

\Core Profile에서는 VAO 없이 그리면 명백하게 에러가 납니다. VAO가 없으면 GPU는 “어떤 버퍼에서, 어떤 방식으로 정점 데이터를 읽을지”를 알 수 없기 때문이죠.

하지만 Compatibility Profile에선 자동으로 기본 VAO 상태가 세팅되어 있는 것처럼 작동합니다. 그래서 실수로 VAO를 안 만들었는데도 삼각형이 그려지거나, 버퍼가 먹히는 일이 생깁니다.

이 상태가 바로 "이상한(?) 상태"입니다. 코드가 돌아가긴 하는데, 실제로는 명확하지도, 이식성도 없고, 최신 OpenGL 문법에도 어긋납니다.


3. GLFW 윈도우 생성과 컨텍스트 설정

GLFWwindow* window = glfwCreateWindow(500, 500, "scop", NULL, NULL);
glfwMakeContextCurrent(window);

 

드디어 창을 생성했습니다! 🎉🎉🎉

glfwCreateWindow()는 너비, 높이, 창 이름을 받고 윈도우를 만들어줘요

 

근데 만든다고 바로 쓰는 건 아닙니다.

OpenGL은 렌더링 컨텍스트라는 걸 만들어야만 함수들이 제대로 작동해요.

그래서 glfwMakeContextCurrent(window)로 이 창을 "현재 쓰는 컨텍스트"로 등록합니다.

참고: "컨텍스트"는 OpenGL 상태 저장소라고 보면 됩니다, OpenGL 함수들은 모두 이 상태에 종속되며.
프레임버퍼 객체에 그리지 않을 때 렌더링 명령이 그릴 (잠재적으로 보이는) 기본 프레임 버퍼를 나타냅니다.

4. Viewport 설정 - 너의 픽셀 범위는 어디니?

int framebuffer_w, framebuffer_h;
glfwGetFramebufferSize(window, &framebuffer_w, &framebuffer_h);
glViewport(0, 0, framebuffer_w , framebuffer_h);

 

여기서 창이 생겼다고 GPU가 그릴 공간이 자동으로 지정되는 건 아닙니다.

glViewport는 말 그래도 이 화면에서 실제로 그릴 픽셀 영역을 정해줘요.

  • (0, 0)은 좌측 하단의 시작점
  • (w, h)는 그릴 영역 크기
💡 고해상도 모니터 (예: Retina)에서는 실제 프레임버퍼 크기가 창 사이즈보다 클 수 있어서
     glfwGetFramebufferSize로 정확하게 받아와야 합니다.

5. GLEW로 OpenGL 함수 포인터 초기화

if (glewInit() != GLEW_OK) {
	std::cerr << "GLEW Init Failed" << std::endl;
	glfwTerminate();
	return (-1);
}

 

OpenGL 함수는 마법처럼 다 쓸 수 있는 게 아닙니다.

OS는 기본적으로 OpenGL의 정의만 알려주고, 실제 포인터 주소는 우리가 직접 가져와야 해요.

그래서 GLEW를 써서 모든 OpenGL 확장 함수 포인터를 초기화합니다.

  • GLEW는 Extension Wrangler의 약자
  • glGenBuffers, glCreateShader 등등.. 다 여기서 초기화됨

실패했을 때 위에서 glfw를 생성했기 때문에 glfwTerminate를 호출한 뒤 나가는 게 중요 포인트!

GLEW를 쓰지 않는다면? glX, wgl처럼 OS별 API로 직접 불러와야 하는 복잡한 세상에 빠집니다.

6. 루프: 그리기, 버퍼 교체, 이벤트 처리

while (!glfwWindowShouldClose(window)) {
	glClearColor(0, 0, 0, 1);
	glClear(GL_COLOR_BUFFER_BIT);

	glfwSwapBuffers(window);
	glfwPollEvents();
}

 

드디어 메인 루프!

창을 열고 계속해서 프레임을 갱신합니다.

  • glClearColor와 glClear로 매 프레임 배경색을 초기화
  • glfwSwapBuffers: 백 버퍼를 프론트로 교체 (더블 버퍼링)
  • glfwPollEvents: 마우스, 키도브, 창 크기 등 이벤트 확인

이 루프 안에서 드로잉, 물리 연산, 애니메이션 등 모든 게 돌아갑니다.

OpenGL Window

 


7. 종료 처리 - 메모리는 우리가 책임져야죠

glfwTerminate();
return (0);

 

마지막엔 GLFW가 사용한 자원을 해제해줘야 해요.

안 그러면 OS에 리소스가 남아 이상한 버그의 원인이 되기도 하죠.


다음 글 예고

지금까지는 정말 "창만 띄운" 코드였죠.

하지만 여기서부터가 진짜 시작입니다. 앞으로 우리는

  • VAO, VBO를 만들고
  • 셰이더를 로딩하고
  • 3D 모델을 로딩하고
  • 마우스로 회전까지!

Scop 구현기 2편: VAO와 VBO의 세계

'Dev > Grapics' 카테고리의 다른 글

Scop 구현기 3편: 셰이더 클래스를 만들기로 했다  (0) 2025.04.11
Scop 구현기 2편: VAO와 VBO의 세계  (0) 2025.04.09
Rasterization vs Ray Tracing  (0) 2025.04.09
셰이더는 그낭 함수일까?  (0) 2025.04.08
OpenGL의 좌표계, 진짜로 이해하기  (1) 2025.04.08
'Dev/Grapics' 카테고리의 다른 글
  • Scop 구현기 3편: 셰이더 클래스를 만들기로 했다
  • Scop 구현기 2편: VAO와 VBO의 세계
  • Rasterization vs Ray Tracing
  • 셰이더는 그낭 함수일까?
onepaperhoon
onepaperhoon
한장훈님의 블로그 입니다.
  • onepaperhoon
    OnePaperHoon Blog
    onepaperhoon
  • 전체
    오늘
    어제
    • 분류 전체보기 (14)
      • Dev (14)
        • System Programming (2)
        • Linux (0)
        • CS (0)
        • Network, Protocol (0)
        • Grapics (11)
        • Web, App (0)
        • Design Pattern (1)
      • Projects (0)
      • TIL (0)
      • Life (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • GitHub
  • 공지사항

  • 인기 글

  • 태그

    IPC
    그래픽스
    cpp
    Process
    Vertex Shader
    glfw
    Game
    graphics
    3d
    c++
    디자인 패턴
    C언어
    공유 메모리
    named pipe
    graphicapi
    shared memory
    OpenGL
    Pipe
    싱글톤 패턴
    shader
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
onepaperhoon
Scop 구현기 1편: 윈도우 하나 띄우는 게 뭐라고 (Object Viewer)
상단으로

티스토리툴바