티스토리 뷰
이 글에서는 GLFW와 GLEW를 이용하여 창을 띄워볼 것이다.
환경 셋업에 대한 것은 아래의 글을 참고.
완성된 코드를 바로 보고 싶다면 아래 repo를 참고하면 된다.
https://github.com/9ru9ru/open-gl-course/blob/ch0-ready-fixed/runtime/section01/Section01Runner.cpp
커버하는 지식 범위는 다음과 같다.
- 간단한 OpenGL의 work-flow
- 기본적인 API들
이 글을 통해 달성할 목표는 다음과 같다.
- GLFW와 GLEW의 초기화 및 환경 셋업.
- 800x600으로 빨간색 만을 출력하는 윈도우 띄우기.
1. Window를 띄우기 위한 work-flow 개략
간단하게라도 어떤 work-flow로 작업할 것인지 알아보자.
특히, 윈도우를 띄우는데 있어서 비즈니스 로직 외적으로 부가적인 기능들이 사용되기 때문에 잘 익혀두면 좋다.
윈도우 하나를 띄우기 위해 해야 하는 일들은 다음과 같다.
- GLFW 초기화 및 셋업
- GLEW 초기화 및 셋업
- 창 관련 설정
- 빨간 색 창을 띄우는 메인 루프 실행
실제 코드에서 다음과 같은 일들을 해보자.
2. 코드 작성
우선 전체 완성된 코드는 다음과 같다.
#include "Section01Runner.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
bool Section01Runner::Run()
{
// init GLFW.
if(!glfwInit())
{
printf("GLFW init fail");
glfwTerminate();
return false;
}
// Setup GLFW window properties.
// OpenGL Version.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Core profile = No Backwards Compatible.
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Allow forward compatible.
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindow* mainWindow = glfwCreateWindow(windowWidth, windowHeight, "Hello Window", NULL, NULL);
if (!mainWindow)
{
printf("glfwCreateWindow failed!");
glfwTerminate();
return false;
}
// Get Buffer Size Info.
int bufferWidth, bufferHeight;
glfwGetFramebufferSize(mainWindow, &bufferWidth, &bufferHeight);
// Set Context for GLEW to use.
glfwMakeContextCurrent(mainWindow);
// Allow modern extension feats.
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
printf("glew init failed");
glfwDestroyWindow(mainWindow); // 이 시점에서 window가 생성되었으니 지워야 한다.
glfwTerminate();
return false;
}
// Setup Viewport size.
glViewport(0, 0, bufferWidth, bufferHeight);
// loop til window closed.
while (!glfwWindowShouldClose(mainWindow))
{
// Get + handle user input events.
glfwPollEvents();
// Clear window.
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(mainWindow);
}
return true;
}
하나하나 알아볼 것이다.
2.1. GLFW 초기화 및 셋업
GLFW를 초기화 해주는 부분
// init GLFW.
if(!glfwInit())
{
printf("GLFW init fail");
glfwTerminate();
return false;
}
glfwInit()
함수를 통해 glfw를 초기화- 제대로 초기화 되지 않은 경우에는
glfwTerminate()
을 통해 종료해준다.
GLFW의 셋업 - 버전 설정 및 호환성 설정
// Setup GLFW window properties.
// OpenGL Version.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Core profile = No Backwards Compatible.
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Allow forward compatible.
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(int hint, int value)
glfw의 다음 초기화에 대한 힌트를 셋업. hint에 해당하는 값에 value 할당하는 간단한 역할.
실제 한 작업들은 다음과 같다.
- GLFW_CONTEXT_VERSION을 3.3으로 설정: 사용할 버전에 알아서 맞춰주면 된다.
- GLFW_OPENGL_PROFILE을 GLFW_OPENGL_CORE_PROFILE으로 설정: 오래된 기능인 Immediate 모드를 사용 X.
- GLFW_OPENGL_FORWARD_COMPAT를 TRUE로 설정: OpenGL context의 상위 호환성을 true로 설정하는 거다. 나중에 나올 버전과 호환 가능하도록 하는 것. 즉 다음 버전에서도 잘 작동할 수 있도록 설정하는 동작이다.
GLFW를 이용한 윈도우 생성과 프레임 버퍼 설정, Context 생성
이제 GLFW의 초기화와 설정이 끝난 단계이니 실제 작업들을 해 볼 시간이다.
GLFWwindow* mainWindow = glfwCreateWindow(windowWidth, windowHeight, "Hello Window", NULL, NULL);
if (!mainWindow)
{
printf("glfwCreateWindow failed!");
glfwTerminate();
return false;
}
// Get Buffer Size Info.
int bufferWidth, bufferHeight;
glfwGetFramebufferSize(mainWindow, &bufferWidth, &bufferHeight);
// Set Context for GLEW to use.
glfwMakeContextCurrent(mainWindow);
// Allow modern extension feats.
glewExperimental = GL_TRUE;
glfwCreateWindow(windowWidth, windowHeight, "Hello Window", NULL, NULL);
window, window와 연관된 context를 생성해주는 함수. 패러미터 목록은 아래.
- int width: 생성할 창의 width
- int height: 생성할 창의 height
- const char *title: 생성할 창의 제목
- GLFWmonitor *monitor: fullscreen 모드로 사용할 monitor. NULL로 두면 그냥 창 모드로 뜬다.
- GLFWwindow *share: context를 share할 window. NULL로 두면 그 무엇과도 share 하지 않는다.
그리고 이렇게 생성하게 되는 window의 경우 생성만 되고 current context로 설정되지 않는다.
따라서 뒷쪽에서 currrent context로 설정하게 되는 과정이 필요하다.
glfwGetFramebufferSize(mainWindow, &bufferWidth, &bufferHeight): window의 frame buffer size를 pixel 단위로 받아오는 함수.
프레임 버퍼에 대한 개념을 간단히 설명하자면 ‘화면에 그려질 전체에 대한 정보를 담는 공간’이라고 볼 수 있다. 해상도가 800600인 창인 경우 800600이 프레임 크기가 될 것이다.
실제로 여기서 800과 600으로 mainWindow를 만들고 프레임 버퍼의 크기를 찍어보면 다음과 같이 뜬다.
뒷쪽에서 해당 사이즈를 쓸 일이 생기니 우선 넘어가자.
glfwMakeContextCurrent(mainWindow)
window의 context를 current context로 지정한다.
보충 - Current ‘Context’란 무엇인가?
윗 쪽 설명에 계속 ‘context’에 대한 설명이 등장한다.
생성한 window를 current context로 지정하는 등 다양한 작업들이 이루어진다.
그렇다면 ‘context’는 무엇을 의미하는 것인가?
Context는 OpenGL API를 사용하여 그래픽을 렌더링하는 데에 필요한 모든 정보를 가지는 데이터 구조이다.
활성 셰이더 / 현재 정점 배열 / 현재 프레임 버퍼 / 현재 텍스쳐 등이다.
특징으로는 하나의 스레드는 여러 context들을 가지고 있을 수 있지만, 단 하나의 context만이 current로 지정될 수 있다는 것이다. 또한 하나의 context도 하나의 스레드에만 할당될 수 있다.
특히 위에서 만들어진 window object와 같은 경우 window와 context가 분리할 수 없이 연결되어있다. 따라서 창 오브젝트가 context handle 역할을 함께 수행하고 있다.
또한, 이런 context는 sharing할 수 있는데, 예를 들어 다음과 같이 두 번째 생성되는 창을 첫번째 창의 context에 sharing할 수 있다.
GLFWwindow* second_window = glfwCreateWindow(640, 480, "Second Window", NULL, first_window);
2.2. GLEW 초기화 및 셋업
GLEW를 초기화 해주는 부분
if (glewInit() != GLEW_OK)
{
printf("glew init failed");
glfwDestroyWindow(mainWindow); // 이 시점에서 window가 생성되었으니 지워야 한다.
glfwTerminate();
return false;
}
glewInit(): GLEW 초기화 관련 작업을 진행.
glfwDestroyWindow(mainWindow): window가 생성된 시점이므로 추가적으로 이 일을 해줘야 한다.
ViewPort의 Setup
// Setup Viewport size.
glViewport(0, 0, bufferWidth, bufferHeight);
glViewPort: VIewPort의 위치와 크기를 정하는 커맨드이다. 처음 두개가 시작점,
- 처음 두 파라미터는 viewport의 시작좌표 x,y(왼쪽아래)
- 뒤의 두 파라미터는 뷰포트의 크기 w,h다.
따라서 위의 커맨드는 viewport를 0,0에서 시작해서 화면 꽉 차게 채운다는 의미다.
window 내의 viewport는 다음과 같이 표시된다고 보면 된다.
또한 viewport의 scale을 줄이면 렌더링 객체도 똑같은 scale로 줄어든다.
예를 들어 viewport를 window와 동일한 크기로 설정하여 다음과 같이 삼각형이 뜰 때
glViewport(0, 0, bufferWidth, bufferHeight);
viewport를 절반으로 줄여보면 다음과 같이 표시된다.
glViewport(0, 0, bufferWidth/2, bufferHeight/2);
또한 이 상황에서 viewport가 화면 중앙에서 시작하도록 설정하면 다음과 같이 표시된다.
glViewport(bufferWidth/2, bufferWidth/2, bufferWidth/2, bufferWidth/2);
2.3. MainLoop
이제 창도 띄우고 viewport 설정을 끝냈으니 마침내 원하는 화면을 렌더링 해야 할 차례다.
메인 루프를 보자.
우선 기본적으로 매 프레임 꺼지면 안 되므로 while 안에 넣어 루프화 해야한다.
while (!glfwWindowShouldClose(mainWindow))
{
// Get + handle user input events.
glfwPollEvents();
// Clear window.
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(mainWindow);
}
glfwWindowShouldClose(mainWindow)
지정된 window의 close flag가 활성화 됐는지 확인한다.
x단추 등을 누르면 close flag가 활성화된다.
glfwPollEvents()
입력 관련 이벤트 프로세싱을 가능하게 해 주는 함수다.
glClearColor(1.0f, 0.0f, 0.0f, 1.0f)
color buffer가 clear 되었을 때 기본 색 값을 정한다.
간단히 생각하면 아무것도 안 뜨는 상태에서 윈도우의 배경 색을 결정하는 함수로 볼 수 있다.
glClear(GL_COLOR_BUFFER_BIT)
buffer내의 값을 지워버리는 함수다.
파라미터는 무슨 버퍼를 지울 것인지에 대해 지정한다.
color / depth / stencil 세 가지 종류가 있다.
간단하게 생각하면 화면에 띄워질 정보를 지우는 것이라 생각할 수 있겠다.
이 경우 배경색 지정 후 배경색을 보기 위해 color buffer를 날려야 하므로 이 작업을 수행한다.
glfwSwapBuffers(mainWindow)
window에서 이전 프레임에 그려졌던 Buffer와 현재 Buffer를 스왑함으로서 현재 Buffer에 있는 값을 보여지게 한다.
사실 이 루프 자체에서는 Buffer에 아무 값도 안 넣었기 때문에 큰 의미 없는 명령이 된다.
단, 그리는 값을 계속 변경해주기 위해 필요한 하나의 과정이므로 미래를 위해 일단 사용해본다.
Refs
사실 GLFW와 GLEW는 API설명이 매우 잘 되어있는 편이다.
나도 API 문서 읽는 거 싫어하긴 하는데 꽤 읽어볼 만 하다.
화이팅.
https://www.glfw.org/docs/3.3/window_guide.html
https://www.glfw.org/docs/3.3/group__context.html
https://www.glfw.org/docs/3.3/context_guide.html
https://www.glfw.org/docs/3.3/group__window.html
https://www.khronos.org/opengl/wiki/OpenGL_Context
https://www.reddit.com/r/opengl/comments/lb3ptw/what_is_context_in_opengl/
'그래픽스' 카테고리의 다른 글
[그래픽스] Rendering Pipeline 개요 (1) | 2025.02.09 |
---|---|
[그래픽스] OpenGL과 GLEW/GLFW (0) | 2025.02.03 |
[그래픽스] C++에서 OpenGL(GLEW/GLFW) 개발 환경 구축 (0) | 2025.02.01 |
- Total
- Today
- Yesterday
- rnn
- 이미지처리
- 머신 러닝
- CS
- 매트랩
- 신경망
- 영상구조
- 연속 신호
- NLP
- 밑바닥부터 시작하는 딥러닝
- 자연어 처리
- Andrew ng
- 이미지
- gradient descent
- 사진구조
- 매트랩 함수
- 인덱스 이미지
- Neural Network
- Logistic Regression
- 이산 신호
- 딥러닝
- 컴퓨터과학
- ML
- 신호 및 시스템
- RGB이미지
- 머신러닝
- CNN
- 순환 신경망
- 영상처리
- 컴퓨터 과학
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |