본문 바로가기
카테고리 없음

[opengl]. GLFW 개발 환경 만들기

by 바른생활머시마 2023. 4. 9.
728x90
반응형

전에 OpenGL 개발 환경을 만드는 과정을 정리한 적이 있는데요,

https://learn-and-give.tistory.com/10

 

[opengl].[#1.Setup] Windows/VS2019/glut 기반의 셋업(2) - glut(freeglut)로 opengl 창 띄우기

예전에 짜두었던 코드를 지금 다시 VS2019에서 빌드 해 보려니 거의 대부분 실행이 안되네요. 그래서, glut 기반으로 다시 만들어봐야겠다 싶어 glut 받으러 가 봤더니... https://www.opengl.org/resources/libr

learn-and-give.tistory.com

 

Point cloud 랜더링 관련 된 조사를 하다보니 GLFW 기반으로 된 코드가 있었고, 그래서 겸사겸사  GLFW를 살펴보니~~

오호! Vulkan을 사용 할 수 있다고 하네요. 초창기에 딱 봐도 어려워보여서 아예 시작을 말아야지 했었는데 개발 환경이 많이 사용자 친화적으로 된 것 아닌가 싶네요. Vulkan SDK 제공되는 페이지들도 있고.

 

Home | Vulkan | Cross platform 3D Graphics

 

Home | Vulkan | Cross platform 3D Graphics

Vulkan is a next generation graphics and compute API that provides high-efficiency, cross-platform access to modern GPUs used in PCs, consoles, mobile phones and embedded platforms.

www.vulkan.org

요것도 언제고 한번 살펴보기는 해야겠습니다. LUNAR G라~~~

Driver

LUNAR G

 

 

다시 본론으로 돌아와서 GLFW를 살펴보겠습니다.

An OpenGL library | GLFW

https://www.glfw.org/

 

An OpenGL library

GLFW project home page.

www.glfw.org

 

설치나 리뷰를 한 블로그들이 많이 있으니, 자기가 보기에 적당한 것들 살펴보는 것이 좋겠고, 초보라면 다양한 관점의 글들 몇 개를 봐두는 것도 좋을 것 같습니다. 그나저나, GLFW를 사용하는 사람들은 현재 어떤 일을 하는 사람들일지 좀 궁금하네요. 모바일이나 웹 개발로 개발 환경이 많이 옮겨져서...참, GLFW는 모바일도 지원하는 것 같고, 그래서 널리 쓰이고 있을지도 모르겠네요.

 

 

Windows에서 GLFW 개발환경 구축

 자세한 과정은 친절한 포스트를 참고하는 것으로 하고, 저는 제가 겪은 이슈들 중심으로 정리하도록 하겠습니다.

 

 GLFW를 받아서 직접 빌드해서 쓰는 경우, 아래와 같은 소스 코드를 받게 됩니다.

 

CMake를 보면... 살짝 부담스러운 마음이 드는 것도 사실인데...ㅋㅋ 반가운 Precompiled Binary도 배포를 해주네요.

 특이한 점은 VS 버젼에 따라 binary를 제공하는데, 어쩌면 VS 버젼에 따라 사람들이 어려움을 많이 겪기 때문이 아닐까 싶습니다. CMake에서의 부담감도 그런 것과 연관이 있고... 안해보면 계속 부담감을 갖고 살아가니 언제고 그 부담을 해소하는 것도 좋을 것 같네요. 저는 VS2019를 사용 중이라 2019용을 설치하겠습니다.

 

 요걸 여러 프로젝트에서 사용 할 수 있는 위치에 둘까 했는데, 앞선 OpenGL 개발환경 구축처럼, 이것도 그 프로젝트 소스와 함께 두는 것이 향후의 활용에 도움이 될 것 같아 프로젝트 내에 폴더를 만들어 저장하겠습니다.

 

 

VS2019  New project - C++ Console project

프로젝트 형태는 늘 그렇듯, Win32 console application~

적당한 이름을 지어주고, 저는 솔루션과 프로젝트를 분리했어요. 특별한 이유가 있는 것은 아니고, 부가적인 자료는 프로젝트 밖에 두려고~~~

프로젝트 다 만들었으면 Hello, World는 한번 해줘야하니, Hello, glfw!

32비트는 이제 사용하지 않을 것이니, 64비트 Debug/ Release로 각각 실행 해 봅니다.


 프로젝트 폴더 구조

프로젝트 폴더 구조는 아래와 같이 구성 해 봤습니다. glfwLib 폴더를 만들어, 다운로드 받은 prebuilt binary를 넣어두었고, DLL을 위의 Hello, world를 실행 시킨 결과로 만들어지는 exe가 들어있는 폴더에 넣어둡니다. DLL을 시스템 폴더에 넣어두는 것은 좀 아닌 것 같아서~

그리고, 헤더파일 경로를 설정 해 주고~

헤더 파일을 잘 찾는지 확인 해 보기 위해,  include만 한번 시켜봅니다.

#include <GLFW/glfw3.h>

잘 되네요.

다음으로 라이브러리 경로도 프로젝트 설정에서 설정 해 줍니다.

경로 설정 후, 다운로드 받은 prebuild binary에 들어있는 lib들을 적어줍니다.

 

Sample code

 

Documentation | GLFW 에 들어있는 샘플을 실행 시켜 봅니다.

#include <GLFW/glfw3.h>

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

 

에러가 뜨네요.~

지금부터가 조금 중요한 부분인 것 같아요~

 

환경 설정의 오류 처리

 위 오류를 보면 glClear를 사용 할 수 없다는 에러인데요, glClear는 glfw가 아니라 opengl의 함수입니다. 즉, glfw만 추가한다고 해서 opengl을 다 사용 할 수 있는 것은 아니죠. 요것은 freeglut 기반으로 opengl 개발환경 만들 때도 동일하게 처리했던 내용입니다. 즉, opengl32.lib를 사용 할 수 있게 해줘야 하는 것이죠.

 

프로젝트 lib를 추가했던 창에 opengl32.lib도 추가하고 실행하면, 아래와 같이 잘 됩니다.

 

 그런데, 우리가 직접 opengl32.lib라는 파일을 복사한 적이 없는데 어찌 된 영문일까요??

OpenGL은 이제 보편적으로 많이 쓰이는 라이브러리이고, 다양한 개발 툴이나 런타임 패키지에서 이 파일을 배포하고 있습니다. 앞에서 만든 VS 프로젝트를 보면, 사용자가 추가한 경로 외에도 프로젝트에 기본적으로 설정 된 여러가지 경로들이 있습니다. 시스템 상에 설치되어 있는 Windows 개발용 툴들의 library 경로들이죠. OpenGL32는 아래 표시 된 경로 중 하나에 있는 것을 실제로 확인 해 볼 수 있습니다.

그런데, lib와 함께 필요한 opengl32.dll은 어디 있을까요??

검색을 해 보면, 여러 개의 opengl32.lib가 검색 되는데, 이것은 freeglut  기반 환경 설정의 내용과 동일합니다. 즉, system32 폴더 내의 opengl32.dll이 사용 되는 것이죠. WOW64가 64비트용 같은데 아니라는 것은 freegult 환경 설정에서도 이야기 했었죠? (했었나???..)

아래 블로그 포스트에 이 내용을 잘 정리 해 두셨네요. 참고~

32 bit / 64 bit System 폴더 :: 몽키의 IT개발 노트 (tistory.com)



GLFW: Getting started

좀 더 많은 내용이 담긴 아래 샘플 프로젝트도 Getting Started에서 제공이 되니 한번 돌려보겠습니다. 그러나, 쉽게 되지는 않네요.ㅋ

#include <glad/gl.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
 
#include "linmath.h"
 
#include <stdlib.h>
#include <stdio.h>
 
static const struct
{
    float x, y;
    float r, g, b;
} vertices[3] =
{
    { -0.6f, -0.4f, 1.f, 0.f, 0.f },
    {  0.6f, -0.4f, 0.f, 1.f, 0.f },
    {   0.f,  0.6f, 0.f, 0.f, 1.f }
};
 
static const char* vertex_shader_text =
"#version 110\n"
"uniform mat4 MVP;\n"
"attribute vec3 vCol;\n"
"attribute vec2 vPos;\n"
"varying vec3 color;\n"
"void main()\n"
"{\n"
"    gl_Position = MVP * vec4(vPos, 0.0, 1.0);\n"
"    color = vCol;\n"
"}\n";
 
static const char* fragment_shader_text =
"#version 110\n"
"varying vec3 color;\n"
"void main()\n"
"{\n"
"    gl_FragColor = vec4(color, 1.0);\n"
"}\n";
 
static void error_callback(int error, const char* description)
{
    fprintf(stderr, "Error: %s\n", description);
}
 
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GLFW_TRUE);
}
 
int main(void)
{
    GLFWwindow* window;
    GLuint vertex_buffer, vertex_shader, fragment_shader, program;
    GLint mvp_location, vpos_location, vcol_location;
 
    glfwSetErrorCallback(error_callback);
 
    if (!glfwInit())
        exit(EXIT_FAILURE);
 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
 
    window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }
 
    glfwSetKeyCallback(window, key_callback);
 
    glfwMakeContextCurrent(window);
    gladLoadGL(glfwGetProcAddress);
    glfwSwapInterval(1);
 
    // NOTE: OpenGL error checks have been omitted for brevity
 
    glGenBuffers(1, &vertex_buffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
 
    vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
    glCompileShader(vertex_shader);
 
    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
    glCompileShader(fragment_shader);
 
    program = glCreateProgram();
    glAttachShader(program, vertex_shader);
    glAttachShader(program, fragment_shader);
    glLinkProgram(program);
 
    mvp_location = glGetUniformLocation(program, "MVP");
    vpos_location = glGetAttribLocation(program, "vPos");
    vcol_location = glGetAttribLocation(program, "vCol");
 
    glEnableVertexAttribArray(vpos_location);
    glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE,
                          sizeof(vertices[0]), (void*) 0);
    glEnableVertexAttribArray(vcol_location);
    glVertexAttribPointer(vcol_location, 3, GL_FLOAT, GL_FALSE,
                          sizeof(vertices[0]), (void*) (sizeof(float) * 2));
 
    while (!glfwWindowShouldClose(window))
    {
        float ratio;
        int width, height;
        mat4x4 m, p, mvp;
 
        glfwGetFramebufferSize(window, &width, &height);
        ratio = width / (float) height;
 
        glViewport(0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT);
 
        mat4x4_identity(m);
        mat4x4_rotate_Z(m, m, (float) glfwGetTime());
        mat4x4_ortho(p, -ratio, ratio, -1.f, 1.f, 1.f, -1.f);
        mat4x4_mul(mvp, p, m);
 
        glUseProgram(program);
        glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp);
        glDrawArrays(GL_TRIANGLES, 0, 3);
 
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
 
    glfwDestroyWindow(window);
 
    glfwTerminate();
    exit(EXIT_SUCCESS);
}

여러 개의 에러가 뜨네요...

먼저, 

gl.h, glad.h…

glad는 prebuilt binary말고, 소스 코드가 포함 된 압축 파일에 보면 deps라는 폴더 하위에 있습니다. 이름을 보면 dependency 뭐 그런 것 아닌가 싶네요.

 

거기 있던 것을 include 폴더에 쏙~~ 집어넣어주고, 그 안에 gl.h나 glad.h도 있는 것을 볼 수 있습니다. 그런데, vulkan도 있네요.

 헤더파일이 없다는 오류는 사라졌지만 glad_XXXX 형식의 함수를 찾을 수 없다는 에러가 뜹니다. 이것은 glad_XXX라는 함수가 정의 된 lib가 필요한데, 우리는 glfw를 설치했지 glad는 만들지 않았어요. 즉, 이 샘플 코드는 소스 코드로부터 직접 만들어서 쓰는 경우에 적합한 샘플인 것 같아요.


Hello, Triangle

원래 OpenGL의 첫번째 샘플은 삼각형을 그려주는 것으로 시작해야 제맛이죠!

 처음 만들었던 샘플 코드에 삼각형을 그려주는 코드를 추가합니다.

#include <GLFW/glfw3.h>

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);


    glClearColor(1, 0, 0,1);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);



        glViewport(0, 0, 640, 480);
        glClear(GL_COLOR_BUFFER_BIT);

        glColor3f(0.f, 1.f, 0.f);
        glBegin(GL_TRIANGLES);
        glVertex3f(-0.5f, -0.5f, 0.f);
        glVertex3f( 0.5f, -0.5f, 0.f);
        glVertex3f( 0.f,   0.5f, 0.f);
        glEnd();


        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

 

결과는, 아래와 같이 잘 나옵니다.~

요걸로 무얼 할 수 있을지는 또 차근차근 알아가 보겠습니다.

728x90
반응형

댓글