먼저 GLFW, glad, CMake라는 도구/라이브러리가 필요하다
https://learnopengl.com/Getting-started/Creating-a-window
위 링크를 잘 따라서 설치/빌드 추가해주자!
glad.c설치할때, 무조건 파일 add로 넣어주기!
#include <glad/glad.h>
#include <GLFW/glfw3.h>
int main()
{
constexpr int width = 1280;
constexpr int height = 720;
glfwInit();
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); //only mac
return 0;
}
먼저 이런 코드를 작성해주자
openGL을 이용해서 콘솔창에 해당되는 윈도우를 띄우려고 하는 준비과정임
glfwInit은 glfw를 생성하는 메서드glfwWindowHint는 glfw를 설정하는 메서드임https://www.glfw.org/docs/latest/window.html#window_hints
여기에서 사용가능한 enum값들 확인가능
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);은 OpenGL 3-major, 3-mionor -> 3.3버전을 사용하고
3.3버전에 맞는 CORE_PROFILE만 사용하겠다는 뜻임OpenGL의 프로필은 3가지가 존재함
Core: 최신 opengl문법만 따름,Deprecated된 문법 사용 못함
Compat: 최신, 과거 모든 opengl문법 호환 가능
any: 낮은 버전(3.2이하)의 opengl을 사용하면 사용해야할 프로필(must be used)
그 다음은 윈도우 객체를 만들어줘야함
윈도우는 여기서 창임ㅇㅇ
GLFWwindow* window = glfwCreateWindow(width, height, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
이 코드를 작성
glfwCreateWindow의 각 인자
1. 첫번째, 두번째 : 띄울 창의 크기
2. 세번째 : 띄울 창의 제목
3. 네번째 : 띄울 창의 전체화면, 창화면 설정
nullptr은 창모드glfwGetPrimaryMonitor()과 같은 함수를 넘기면 해당 모니터에 전체화면!nullptr은 자원 공유 안함성공적으로 생성되었으면 glfwMakeContextCurrent를 이용해서
해당 window객체를 컨텍스트로 지정,
현재 스레드에서 opengl의 코드가 실행되면 해당 window에서 작동하게됨
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
위 코드를 이후에 이어붙이자
glfwGetProcAddress를 통해 OS의 그래픽API를 호출해 해당 함수가 어디에 있는지 알아냄GLADloadproc은 OpenGL의 함수 주소를 GLAD에 해당되는 함수 타입으로 가져오기 위해 필요한 캐스팅 역할gladLoadGLLoader는 GLAD로 캐스팅된 함수를 체킹해서 프로그램 뻗게하든지 계속하든지 ㅇㅇvoid framebuffer_size_callback(GLFWwindow* window, int width, int height);
이런 함수 전방선언을 해주자
아니면 그냥 선언부를 main보다 일찍 배치하든지 ㅇㅇ
framebuffer_size_callback은 그냥 우리가 만든 콜백용 함수임
GLFW* window, 윈도우 width, 윈도우 height를 인자로 받아서
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
이런 glViewport에 값을 넣어주는 역할을 함
이때 glViewport함순가 OpenGL의 함수라서 glad가 제대로 프로젝트에 추가되어있지 않으면 에러가 생김
glViewport는 (-1,-1)~(1,1) 사이의 값을 인자값으로 받는 4개의 인자의 순서대로 minX,minY maxX,maxY로 매핑을 함
위의 예시를 들어 (0,0,800,600)을 했다고 가정해봄
특정 점의 위치가 -0.5,0.5라면, 전체 윈도우 크기를 기준으로 1/4,3/4에 위치를 하고 있는거임.
x: -1일때 0, 1일때 800이니, -0.5면 800의 1/4지점인 200,
y: -1일때 0, 1일때 600이니, 0.5면 600의 3/4지점은 450따라서 설정한 윈도우 기준 (200, 450)의 위치에 점이 찍힘
그 담엔
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
를 작성해주자
이제 실행해보면 창이 나타났다가 바로 꺼지거나,
에러가 나거나,
창 꺼지는 속도가 너무 빨라서 아무것도 확인 불가능할 수 있음
while(!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
while문으로 창이 종료될때까지 확인하다 종료되면 프로그램을 끝내는 코드임
glfwPollEvents는 전체적인 이벤트 처리로, 키입력, 마우스입력등에 따라 처리하는 메서드glfwSwapBuffers는 창에 새로운게 그려질때, 창을 갱신하는 메서드임화면에는 보통 2개의 buffer가 존재함
하나는 back, 하나는 front만약 창에 갱신이 필요할때 buffer를 1개만 이용하면 그 1개로 모든 창을 갱신해야하기때문에 flickering(깜빡임)이슈가 발생됨
이를 해결하기위해 2개의 버퍼를 이용해 갱신을 함
front에는 현재 창에 표시되는 화면이 그려져있음
back에는 새로 그려질 창이 그려지고,
back과 front를 바꾸는게glfwSwapBuffers메서드임
이제 창이 꺼지면 glfw도 종료를 해야하니
glfwTerminate();
return 0;
으로 main문을 종료시켜주자

창 잘뜸!
void processInput(GLFWwindow *window)
{
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
상황에 따라 키입력에 대한 인풋도 컨트롤하고 싶어질 수 있으니
위와 같은 processInput이라는 메서드를 만들고 전방선언 ㄱㄱ
esc키가 눌리면 자동으로 glfw로 생성된 창이 종료되고 while문을 빠져나가도록 할거임
따라서 while문은
while (!glfwWindowShouldClose(window))
{
processInput(window);
glfwSwapBuffers(window);
glfwPollEvents();
}
처럼 수정됨
이제 실행해보면 빈 콘솔창만 둥둥 띄워져있을거임
window는 아래처럼 동작을 할거임
while (!glfwWindowShouldClose(window))
{
//입력
processInput(window);
//렌더링
//이벤트 확인 및 버퍼 교체
glfwSwapBuffers(window);
glfwPollEvents();
}
이게 제대로 작동중인건지 확인해야함
버퍼의 색이 지워지지않고 그대로 계속해서 더해지기만 한다면
결국 검은색이 될거임
그래서 아래와 같은 코드를 while문의 렌더링 부분에 넣어볼거임
while(!glfwWindowShouldClose(window))
{
process_input(window);
//렌더링
glClearColor(1.0f, 0.6f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}
여기서 glClearColor로 버퍼 클리어 할때 무슨색상으로 초기화할지 정하고
glClear를 통해 어떤것을 클리어할지 정함
GL_COLOR_BUFFER_BIT : 색상 정보GL_COLOR_DEPTH_BIT : 물체 앞뒤 정보GL_COLOR_STENCIL_BIT : 스텐실 정보
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void process_input(GLFWwindow *window);
int main()
{
constexpr int width = 1280;
constexpr int height = 720;
//glfw init
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//make window with glfw
GLFWwindow* window = glfwCreateWindow(width, height, "HukPak", nullptr, nullptr);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
//GLAD checks gl pointer of GL-functions
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//viewport configuration with custom callback method
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
//run window
while(!glfwWindowShouldClose(window))
{
process_input(window);
glClearColor(1.0f, 0.6f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}
//stop glfw with runtime over
glfwTerminate();
return 0;
}
//viewport configuration callback method
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
//key input callback
void process_input(GLFWwindow *window)
{
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}