최초의 창
멋진 그래픽을 만들기 전에 가장 먼저 해야 할 일은 OpenGL 컨텍스트와 그림을 그릴 애플리케이션 창을 생성하는 것입니다. 하지만 이러한 작업은 운영 체제마다 다르며, OpenGL은 이러한 작업을 직접 하지 않습니다. 즉, 창을 생성하고, 컨텍스트를 정의하고, 사용자 입력을 처리하는 모든 과정을 우리가 수행해야 합니다.
다행히도 우리가 해야 할 일을 대신 해주는 라이브러리가 많으며, 그중 일부는 특히 OpenGL을 대상으로 합니다. 이러한 라이브러리를 사용하면 운영체제 관련 작업을 모두 생략하고 렌더링할 창과 OpenGL 컨텍스트를 제공받을 수 있습니다. 인기 있는 라이브러리로는 GLUT, SDL, SFML, GLFW 등이 있습니다. LearnOpenGL에서는 GLFW를 사용할 예정입니다. 다른 라이브러리를 사용하셔도 무방하며, 대부분의 설정은 GLFW와 유사합니다.
많은 경우에서 GLUT는 추천하지 않습니다. GLUT는 오래되었고, 너무 단순하고, 대신 사용할수 있는 라이브러리 많습니다. GLFW를 사용하세요.
GLFW
GLFW는 OpenGL을 위해 특별히 작성된 C 언어 라이브러리입니다. GLFW는 화면에 콘텐츠를 렌더링하는 데 필요한 기본적인 기능들을 제공합니다. OpenGL 컨텍스트를 생성하고, 창 매개변수를 정의하고, 사용자 입력을 처리할 수 있으며, 이는 우리의 목적에 충분합니다.
이 장과 다음 장의 목표는 GLFW를 실행하여 OpenGL 컨텍스트를 제대로 생성하고 간단한 창을 표시하여 테스트해 볼 수 있도록 하는 것입니다. 이 장에서는 GLFW 라이브러리를 가져오고, 빌드하고, 링크하는 과정을 단계별로 설명합니다. 이 글을 작성하는 시점을 기준으로 Microsoft Visual Studio 2019 IDE를 사용하지만, 최신 버전의 Visual Studio에서도 과정은 동일합니다. Visual Studio를 사용하지 않거나 이전 버전을 사용하는 경우에도 대부분의 다른 IDE에서 유사한 과정을 거치므로 걱정하지 않으셔도 됩니다.
GLFW 빌드하기
GLFW는 웹페이지의 다운로드 페이지에서 구할 수 있습니다. GLFW는 Visual Studio 2012부터 2019까지 사용할 수 있는 컴파일된 바이너리와 헤더 파일을 제공하지만, 실습을 위해 소스 코드에서 직접 컴파일해 보겠습니다. 모든 오픈소스 라이브러리에 컴파일된 바이너리가 제공되는 것은 아니므로, 직접 컴파일하는 과정을 경험해 보는 것이 목적입니다. 자, 그럼 소스 패키지를 다운로드해 보겠습니다.
모든 라이브러리는 64비트 바이너리로 빌드될 예정이므로, 미리 컴파일된 바이너리를 사용하는 경우 64비트 바이너리를 다운로드하시기 바랍니다.
소스 패키지를 다운로드했으면 압축을 풀고 내용을 열어보세요. 우리는 몇 가지 항목에만 관심이 있습니다.
- 컴파일 결과로 생성된 라이브러리
- include 폴더
소스 코드에서 라이브러리를 컴파일하면 결과 라이브러리가 사용자의 CPU/운영체제에 완벽하게 최적화된다는 장점이 있습니다. 미리 컴파일된 바이너리는 이러한 장점을 항상 제공하는 것은 아닙니다(때로는 시스템에 맞는 미리 컴파일된 바이너리를 구할 수 없는 경우도 있습니다). 하지만 공개된 소스코드로 빌드하는 과정에는 문제가 있습니다. 모든 사람이 동일한 IDE나 빌드 시스템을 사용하여 애플리케이션을 개발하는 것은 아니기 때문에, 제공된 프로젝트/솔루션 파일이 다른 사람의 환경과 호환되지 않을 수 있습니다. 따라서 사용자는 제공된 .c/.cpp 및 .h/.hpp 파일을 사용하여 자신만의 프로젝트/솔루션을 구성해야 하는데, 이는 번거로운 작업입니다. 바로 이러한 이유 때문에 CMake라는 도구가 존재합니다.
CMake
원문에서는 윈도우 환경에서 Visual Studio 2019를 사용하는걸 상정합니다. 저(번역가)는 리눅스를 사용하며, VSCode를 사용하므로, 리눅스에서 빌드하는 방법을 이곳에서 설명하겠습니다. 같은 이유로 아래의 Visual Studio에서 빌드하는 설명은 부실할 수 있습니다.
CMake는 미리 정의된 CMake 스크립트를 사용하여 소스 코드 파일 모음으로부터 사용자가 선택한 프로젝트/솔루션 파일(예: Visual Studio 솔루션 파일/make 파일 등)을 생성할 수 있는 도구입니다. 이를 통해 GLFW 소스 패키지에서 Visual Studio 2019 프로젝트 파일을 생성하고, 이 파일을 사용하여 라이브러리를 컴파일할 수 있습니다. 먼저 CMake를 다운로드하여 설치해야 합니다. CMake는 공식 다운로드 페이지에서 다운로드할 수 있습니다.
CMake를 설치한 후에는 CLI나 GUI를 통해 실행할 수 있습니다. 여기서는 복잡한 과정을 피하고 GUI를 사용하겠습니다. CMake는 소스 코드 폴더와 바이너리를 저장할 폴더를 필요로 합니다. 소스 코드 폴더로는 다운로드한 GLFW 소스 패키지의 루트 폴더를 선택하고, 바이너리 저장 폴더로는 'build'라는 새 디렉토리를 생성한 후 해당 디렉토리를 선택합니다.

소스 및 대상 폴더를 설정했으면 구성 버튼을 클릭하여 CMake가 필요한 설정과 소스 코드를 읽도록 합니다. 다음으로 프로젝트에 사용할 제너레이터를 선택해야 하는데, Visual Studio 2019를 사용하고 있으므로 Visual Studio 16 옵션을 선택합니다(Visual Studio 2019는 Visual Studio 16이라고도 합니다). CMake는 결과 라이브러리를 구성할 수 있는 빌드 옵션을 표시합니다. 기본값을 그대로 두고 다시 구성을 클릭하여 설정을 저장합니다. 설정이 완료되면 생성 버튼을 클릭하면 빌드 폴더에 프로젝트 파일이 생성됩니다.
컴파일
build 폴더에 GLFW.sln이라는 파일이 생성되었으며, 이를 Visual Studio 2019로 엽니다. CMake가 이미 적절한 구성 설정이 포함된 프로젝트 파일을 생성했으므로 솔루션 빌드만 하면 됩니다. CMake는 솔루션이 64비트 라이브러리로 컴파일되도록 자동으로 구성했을 것입니다. 이제 솔루션 빌드를 클릭합니다. 그러면 build/src/Debug 폴더에 glfw3.lib라는 이름의 컴파일된 라이브러리 파일이 생성됩니다.
라이브러리를 생성한 후에는 IDE가 OpenGL 프로그램에 필요한 라이브러리와 포함 파일의 위치를 알 수 있도록 해야 합니다. 이를 위한 일반적인 접근 방식은 두 가지입니다.
- IDE 또는 컴파일러의
/lib및/include폴더를 찾아서 GLFW의include폴더 내용을 IDE의/include폴더에 추가하고, 마찬가지로glfw3.lib파일을 IDE의/lib폴더에 추가합니다. 이 방법은 작동하지만 권장되는 방법은 아닙니다. 라이브러리 및 include 파일의 위치를 추적하기 어렵고, IDE/컴파일러를 새로 설치할 때마다 이 과정을 반복해야 하기 때문입니다. - 또 다른 방법(그리고 권장되는 방법)은 IDE 또는 컴파일러에서 참조할 수 있는 타사 라이브러리의 헤더 파일/라이브러리를 모두 담을 새 디렉터리 세트를 원하는 위치에 만드는 것입니다. 예를 들어, OpenGL 프로젝트에 필요한 모든 라이브러리와 헤더 파일을 각각 저장하는
Libs폴더와Include폴더가 포함된 단일 폴더를 만들 수 있습니다. 이렇게 하면 모든 타사 라이브러리가 단일 위치(여러 컴퓨터에서 공유 가능)에 정리됩니다. 단, 새 프로젝트를 만들 때마다 IDE에 해당 디렉터리의 위치를 알려줘야 한다는 점을 유의해야 합니다.
보통 2번과 같은 작업을 인클루드 파치(include path)를 추가한다고 부릅니다. 보통 소스코드(main.c 등)는 프로젝트 폴더 안의 src 폴더에 저장하고, 헤더나 라이브러리는 프로젝트 폴더 안의 include 라는 이름의 폴더에 저장합니다.
필요한 파일들을 원하는 위치에 저장했으면, 이제 첫 번째 OpenGL GLFW 프로젝트 생성을 시작할 수 있습니다.
첫 발걸음
개발자에게는 작은 한 단계일지라도, OpenGL을 처음 배우는 당신에게는 위대한 도약입니다.
먼저 Visual Studio를 열고 새 프로젝트를 생성합니다. 여러 옵션이 표시되면 C++를 선택하고 빈 프로젝트(Empty Project)를 선택합니다(프로젝트 이름을 약간 재미있게 지어보세요). 모든 작업을 64비트 환경에서 수행할 예정인데 프로젝트가 기본적으로 32비트로 설정되어 있으므로, 상단의 디버그 옆 드롭다운 메뉴에서 x86을 x64로 변경해야 합니다.

이 과정이 완료되면 이제 첫 번째 OpenGL 애플리케이션을 만들 수 있는 작업 공간이 마련되었습니다!
링킹
프로젝트에서 GLFW를 사용하려면 라이브러리를 프로젝트에 링크(link)해야 합니다. 링커 설정에서 glfw3.lib를 사용하도록 지정하면 되지만, 저희 프로젝트는 타사 라이브러리를 다른 디렉토리에 저장하기 때문에 glfw3.lib의 위치를 알지 못합니다. 따라서 먼저 해당 디렉토리를 프로젝트에 추가해야 합니다.
라이브러리 및 포함 파일을 찾을 때 IDE가 어떤 폴더를 확인하도록 설정할 수 있습니다. 솔루션 탐색기에서 프로젝트 이름을 마우스 오른쪽 버튼으로 클릭한 다음 아래 이미지와 같이 VC++ 디렉터리(VC++ Directories)로 이동합니다.

그 다음부터는 프로젝트에서 검색할 위치를 알려주기 위해 사용자 지정 디렉터리를 추가할 수 있습니다. 이는 텍스트에 직접 삽입하거나 해당 위치 문자열을 클릭하고 <편집..>(<Edit..>) 옵션을 선택하여 수행할 수 있습니다. 라이브러리 디렉터리(Library Directories)와 포함 디렉터리(Include Directories) 모두에 대해 이 작업을 수행하세요.

여기에 원하는 만큼 추가 디렉터리를 추가할 수 있으며, 추가된 디렉터리부터 IDE는 라이브러리 및 헤더 파일을 검색할 때 해당 디렉터리도 검색합니다. GLFW의 Include 폴더를 포함시키면 <GLFW/..>를 통해 GLFW의 모든 헤더 파일을 찾을 수 있습니다. 라이브러리 디렉터리에도 동일하게 적용됩니다.
VS에서 필요한 모든 파일을 찾았으므로 이제 링커(Linker) 탭으로 이동하여 입력(Input)을 선택하면 GLFW를 프로젝트에 연결할 수 있습니다.

라이브러리에 링크하려면 링커에 라이브러리 이름을 지정해야 합니다. 라이브러리 이름이 glfw3.lib이므로, 이를 추가 종속성(Additional Dependencies) 필드에 추가합니다(수동으로 또는 <편집..> 옵션 사용). 그러면 이후 컴파일 시 GLFW가 링크됩니다. GLFW 외에도 OpenGL 라이브러리에 대한 링크 항목을 추가해야 하지만, 이는 운영 체제에 따라 다를 수 있습니다.
윈도우에서의 OpenGL
Windows 환경에서는 OpenGL 라이브러리인 opengl32.lib가 Microsoft SDK에 포함되어 있으며, 이 SDK는 Visual Studio를 설치할 때 기본적으로 설치됩니다. 이 장에서는 VS 컴파일러를 사용하고 Windows 환경을 기반으로 하므로 링커 설정에 opengl32.lib를 추가합니다. 참고로, 64비트 버전의 OpenGL 라이브러리도 32비트 버전과 마찬가지로 opengl32.lib라는 이름을 가지고 있는데, 다소 아쉬운 이름입니다.
리눅스에서의 OpenGL
리눅스 시스템에서는 링커 설정에 -lGL옵션을 추가하여 libGL.so 라이브러리에 링크해야 합니다. 라이브러리를 찾을 수 없는 경우 Mesa, NVidia 또는 AMD 개발 패키지를 설치해야 할 수 있습니다.
그런 다음, 링커 설정에 GLFW와 OpenGL 라이브러리를 모두 추가했으면 다음과 같이 GLFW 헤더 파일을 포함할 수 있습니다.
#include <GLFW/glfw3.h>
Linux 사용자가 GCC 컴파일러를 사용하여 컴파일할 경우, 다음 명령줄 옵션이 프로젝트 컴파일에 도움이 될 수 있습니다. -lglfw3 -lGL -lX11 -lpthread -lXrandr -lXi -ldl. 해당 라이브러리를 올바르게 링크하지 않으면 많은 참조 오류가 발생할 수 있습니다.
이것으로 GLFW의 설정 및 구성이 완료되었습니다.
GLAD
아직도 안 끝났습니다. 할게 하나 더 남았거든요. OpenGL은 그냥 표준과 사양이기 때문에 특정 드라이버에 OpenGL을 구현하는 것은 드라이버 제조업체의 책임입니다. OpenGL 드라이버는 여러 버전이 존재하기 때문에 대부분의 함수 위치는 컴파일 시점에 알 수 없고 런타임에 조회해야 합니다. 따라서 개발자는 필요한 함수의 위치를 가져와 함수 포인터에 저장하여 나중에 사용할 수 있도록 해야 합니다. 이러한 위치를 가져오는 방법은 운영체제마다 다릅니다. Windows에서는 다음과 같은 방식입니다.
// 함수 프로토타입 정의
typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
// 함수를 찾고 찾은 함수를 함수 포인터에 할당
GL_GENBUFFERS glGenBuffers = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
// 이제서야 함수 사용 가능
unsigned int buffer;
glGenBuffers(1, &buffer);
보다시피 코드가 복잡해 보이고, 사용할 모든 함수에 일일이 이런 복잡한 작업을 하는것은 번거로운 과정입니다. 다행히 이러한 목적을 위한 라이브러리가 있으며, 그중 GLAD는 인기 있고 최신 라이브러리입니다.
GLAD 세팅하기
GLAD는 앞서 언급한 번거로운 작업을 모두 처리해주는 오픈 소스 라이브러리입니다. GLAD는 대부분의 일반적인 오픈 소스 라이브러리와는 약간 다른 설정 방식을 사용합니다. 웹 서비스를 통해 어떤 버전의 OpenGL을 정의하고, 해당 버전에 맞는 모든 관련 OpenGL 함수를 로드할지 GLAD에 알려줄 수 있습니다.
GLAD 웹 서비스에 접속하여 언어가 C++로 설정되어 있는지 확인하고, API 부분에서 OpenGL 버전(gl이라고 표시됨) 3.3 이상을 선택하세요(저희는 3.3 버전을 사용할 예정이며, 더 높은 버전도 괜찮습니다). 또한 프로필(Profile)이 Core로 설정되어 있고 "로더 생성(Generate a loader)" 옵션이 선택되어 있는지 확인하세요. 확장자는 (일단은) 무시하고 "생성(GENERATE)"을 클릭하여 라이브러리 파일을 생성합니다.
GLAD1 버전은 http://glad.dav1d.de에서 배포됩니다. 우리는 GLAD1을 사용하므로, GLAD2 버전을 사용하지 마세요.
생성을 클릭하면 include 폴더와 glad.c 파일 하나가 포함된 zip 파일이 생성될 것입니다. include 디렉토리 안의 두 include 폴더(glad와 KHR)를 우리의 프로젝트 안의 include 디렉터리에 복사하거나, 해당 폴더를 가리키는 추가 항목을 생성한 후, glad.c 파일을 프로젝트에 추가하세요.
이제 우리는 glad를 사용할 수 있습니다.
#include <glad/glad.h>
컴파일 버튼을 눌러도 오류가 나지 않아야 합니다. 모두 완료 되었다면 이제 다음 장에서 GLFW와 GLAD를 설정하고, OpenGL 컨텍스트를 만들고, 창을 띄워보겠습니다. include 디렉터리와 라이브러리 디렉터리가 모두 올바른지, 그리고 링커 설정의 라이브러리 이름이 해당 라이브러리와 일치하는지 확인하세요.
참고자료
- GLFW: Window Guide: GLFW의 공식 GLFW 가이드입니다.
- Building applications: 애플리케이션의 컴파일/링크 프로세스에 대한 유용한 정보와 발생할 수 있는 오류 목록(및 해결 방법)을 제공하는 가이드입니다.
- GLFW with Code::Blocks: Code::Blocks에서 GLFW를 설정하는 가이드입니다.
- Writing a build system under Linux: an autotools tutorial by Wouter Verholst on how to write a build system in Linux.
- Polytonic/Glitter: 필요한 모든 것이 미리 세팅된 프로젝트입니다.
- A Beginner’s Guide to Setup OpenGL in Linux (Debian): Step-by-step guide for setting up OpenGL in Ubuntu along with the installation of required libraries: GLFW and GLAD.