출처 : learnopengl.com/
원문 : learnopengl.com/Getting-started/OpenGL/
OpenGL
OpenGL을 시작하기에 앞서서 OPenGL이 무엇인지에 대해서 정의를 해 봅시다. 보통은 OPenGL을 그래픽과 이미지를 처리할 때 사용하는 함수들의 모음 즉, API라고 생각을 합니다. 그러나 OpenGL 그 자체만 놓고 본다면, API라는 표현은 정확하지 않습니다. OPenGL은 Khronos Group에서 개발하고 유지보수하는 명세서(specification)가 더 정확한 표현입니다.
OpenGL의 명세서(specification)는 각각의 함수들의 결과값/아웃풋 이 무엇인지, 각 각의 함수들은 어떤 식으로 동작해야 하는지를 명시하고 있을 뿐, 실제 함수에 대한 내부적인 구현은 개발자에게 달려 있습니다. OpenGL의 명세표는 함수의 내부적인 구현에 대해서는 제공하지 않기 때문에, OpenGL 함수들의 내부적인 구현은 각 함수들이 동작하는 방법과 결과값이 같다면 개발하는 사람이나 단체에 따라서 세부적인 구현은 달라질 수 있습니다. 세부적인 구현은 달라도 함수들의 구현의 기준이 되는 규범이 존재하기 때문에 사용자는 OpenGL을 동일한 방식으로 사용할 수 있습니다.
일반적으로 OpenGL 라이브러리를 개발하는 사람들은 그래픽카드 제조업체들(ex. NVIDA, AMD)입니다.사람들이 구입하는 그래픽카드들(GPU)은 자신의 그래픽카드 전용으로 개발된 특정 버전의 OpenGL을 지원합니다. 예를 들어서 Apple 시스템전용 OpenGL라이브러리는 Apple 자체에서 유지보수 관리를 합니다. 그렇기 때문에 OpenGL을 사용할 때 동작이 이상하다면, 그래픽카드 제조업체나 라이브러리를 유지 및 개발을 하는 개발자의 잘못일 가능성이 큽니다.
Khronos 그룹에서는 모든 버전에 대한 OpenGL 명세서를 공개하고 있습니다. 관심이 있는 분들을 위해서 OpenGL 3.3 버전 명세서에 대한 링크를 첨부합니다. OpenGL의 세부 사항이 궁금하시다면, 첨부한 링크를 보면 됩니다. 여기서 한가지 당부하고 싶은 점은 구현 방식이 아니라 결과를 설명하는 방법에 초점을 맞춰서 읽는 것을 추천드립니다. 명세서는 특정 기능의 정확한 동작에 대한 참조를 제공하기 때문에, OpenGL에 대해서 막히는 부분이 있다면 참고하면 많은 도움이 되리라 생각합니다.
Core-profile vs Immediate mode
예전에는, OpenGL을 사용한다는 것은 immediate mode(fixed function pipeline 이라고도 합니다.)로 개발하는 것을 의미했습니다. immediate mode는 그래픽스를 사용하는데 쉬운 방식이었습니다. 대부분의 OpenGL의 기능들은 라이브러리 내부에 숨겨져 있었기 때문에, 개발자들은 OpenGL이 계산을 수행하는 방식에 대한 제어를 할 수 없었습니다. 개발자들은 OpenGL에 대한 좀 더 많은 권한을 원했고, 시간이 지남에 따라서 OpenGL의 사양은 결과적으로 좀 더 유연성을 갖추게 되었습니다. 그 결과, 개발자들은 그래픽스에 대한 더 많은 권한을 얻게 되었습니다. immediate mode는 사용하기가 쉽지만, 비효율적입니다. 이러한 이유 때문에, OpenGL의 사양은 버전3.2 부터 Immediate mode를 사용하지 않기 시작했고, 개발자들이 OpenGL의 Core-profile mode를 사용하는 것을 독려했습니다. Core-profile mode는 사용하지 않은 오래된 기능들을 제거한 OpenGL 사양입니다.
OpenGL의 Core-profile mode를 사용할 때, 개발자들이 현대적인 방식을 사용하도록 강제하고 있습니다. 그렇게 때문에, 더 이상 사용되지 않는 기능을 사용하려고 하면, 에러가 발생합니다. 현대적인 접근법(Core-profile)을 배우면, Immediate mode보다는 배우기 어렵지만, 유연성과 효율성이라는 이점을 얻을 수 있습니다. Immediate mode를 사용했을 때는, 상당히 추상화가 많이 되어 있기 때문에 배우기는 쉽지만, 실제로 OpenGL이 실제로 어떻게 동작하는지 파악하기 어려웠습니다. 현대적인 접근 방식(Core-profile mode)은 이전의 방식보다는 배우기 어렵고, OpenGL과 그래픽스 프로그래밍에 대한 이해가 필요합니다. 대신에 앞에서 서술했듯이 좀 더 많은 자율성을 얻을 수 있습니다.
OpenGL의 사용법을 익히는 것도 좋지만, 그보다 더 중요한 것은 그래픽스 프로그래밍에 대한 이해입니다.
그렇기 때문에, 여기에서는 Core-profile OpenGL 버전3.3을 기준으로 설명합니다.
오늘날에는 버전 3.3보다 더 높은 버전이 존재합니다. 왜 최신의 버전을 배우지 않는지에 대해서 의문을 가진 독자들이 있을 거라 생각합니다. 답은 간단합니다. 3.3 이후의 모든 버전들은 3.3버전에서 기능을 좀 추가하거나 좀 더 효율적인 동작을 하도록 약간씩 수정됐을 뿐, 핵심적인 동작방식은 동일합니다. 결과적으로 모든 개념과 기술들이 OpenGL 버전과 관계없이 동일합니다. 따라서, 3.3버전을 알고 있으면, OpenGL의 최선 버전의 기능들을 쉽게 사용할 수 있습니다.
몇몇의 챕터에서는아래와 같은 현대적인 기능들을 볼 수 있습니다.
Extensions(확장)
OpenGL의 가장 큰 특징 중 하나는 확장기능을 지원한다는 것입니다. 그래픽 카드 제조사들이 새로운 기술이나 대규모의 최적화 렌더링 기술을 제시했을 때, 확장된(extension implemeted) 그래픽 카드 드라이버에 구현 될 때가 있습니다. 하드웨어가 이러한 확장을 지원하는 경우, 개발자는 확장된 기능을 사용 할 수 있습니다. 그래픽스 개발자들은 OpenGL에 이러한 기능이 추가 될 때 까지 다음 버전을 기다릴 필요 없이, 그래픽 카드가 확장 기능을 지원한다면, 이러한 새로운 기술들을 바로 사용할 수 있습니다. 이러한 확장된 기능이 널리 사용되거나 유용하다면 추후에 OpenGL의 버전에 추가될 수 있습니다.
개발자는 확장된 기능을 사용하기 전에 사용할 수 있는지 확인해야 합니다.(또는, OpenGL의 확장 라이브러리를 사용).
이를 통해 개발자는 확장 기능을 사용할 수 있는지의 여부에 따라 작업을 더 효율적으로 수행할 수 있습니다.
아래는 확장된 기능 사용 확인에 대한 예시 코드입니다.
1
2
3
4
5
6
7
8
|
if(GL_ARB_extension_name) //하드웨어가 확장된 기능을 지원하는 경우
{
//하드웨어가 지원하는 확장된 기능을 사용하세요.
}
else //확장된 기능을 지원하지 않는 경우
{
//하드웨어가 확장된 기능을 지원하지 않는 경우에는 기존의 방식으로 수행
}
|
cs |
OpenGL 3.3버전에서는 확장이 거의 필요하지는 않지만, 필요한 경우에는 지침이 제공됩니다.
State machine
OpenGL 그 자체로는 큰 규모의 상태 머신 입니다. 상태머신이란 어떻게 OpenGL이 동작할 지에 대해서 사전에 정의되어 있는 변수들의 모음입니다. 일반적으로는 OpenGL context 라고 불립니다.(context를 번역하기 보다는 있는 그대로 사용하는 것이 의미전달에 더 도움이 될거라 판단되어서 원문 용어 그대로 사용했습니다. 번역하기가 참 애매한 단어입니다..). OpenGL을 사용할 때, 각종 옵션들을 설정하거나, 버퍼를 조작하거나 현재의 context를 사용해서 OpenGL의 상태를 변경합니다.
(무슨 말인지 지금 이해가 되지 않아도 괜찮습니다. 계속 공부하다보면, 이해가 되는 순간이 있을 것 입니다. 그냥 가벼운 마음으로 이런것도 있구나 하고 읽고 넘기시면 됩니다. 그럼, 계속해서 서술하겠습니다.)
언제든지 우리는 OpenGL에게 "삼각형 대신, 직선을 그려 줘"라고 이야기 할 수 있습니다.
예를 들어서, OpenGL의 context 변수를 변경해서 OpenGL이 선을 어떻게 그릴 건지 OpenGL의 상태를 변경할 수 있습니다. Context를 변경하게 되면, OpenGL은 삼각형을 그리다가 직선을 화면에 그려줍니다.
OpenGL을 사용하면서, 우리는 context와 OpenGL의 현재 상태에 기반한 수행을 하는 state-using 함수에 대한 이해를 하게 될 것입니다. OpenGL은 기본적으로 큰 규모의 상태 머신이라는 것을 유념한다면, 대부분의 OpenGL의 기능들에 대해서 더 잘 이해할 수 있을 것입니다.
Objects(객체)
OpenGL의 라이브러리들은 C로 작성되었고 여러가지 언어를 허용합니다. 하지만, 여전히 핵심이 되는 것은 C 라이브러리 입니다 . C언어의 언어 구조는 C보다 high-level인 언어들로 완벽하게 번역하기 힘들기 때문에, OpenGL은 몇가지의 추상화를 염두해 두고 개발되었습니다. 이러한 추상화들 하나는 객체(Object) 입니다.
OpenGL에서의 객체는 OpenGL의 상태들의 하위 모음(collections of option)입니다.
예를 들어서, 윈도우창을 그리는 설정을 하는 객체를 얻을 수 있습니다. 이 객체에서 우리는 윈도우 창의 크기를 설정할 수 있고, 색을 칠할 수 있도 있고, 윈도우 창과 관련된 여러가지를 설정 할 수 있습니다.
객체를 아래와 같이 C의 구조체 형식으로 시각화 할 수 있습니다.
1
2
3
4
5
|
struct object_name{
float option1; //옵션1
int option2; //옵션2
char[] name;
}
|
cs |
객체를 사용하려고 할 때마다 일반적으로 다음과 같이 보입니다.(OpenGL의 context가 큰 구조체와 같이 시각화됨.)
1
2
3
4
5
6
|
The state of OpenGL
struct OpenGL_Context{
...
object_name* object_Window_Target;
...
};
|
cs |
1
2
3
4
5
6
7
8
9
10
|
// 객체 생성
unsigned int objectId = 0;
glGenObject(1, &objectId); //Gen은 Generate의 약자입니다.
// context에 객체 할당
glBindObject(GL_WINDOW_TARGET, objectId);
// 현재 GL_WINDOW_TARGET에 객체의 옵션 설정.
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_WIDTH, 800); //윈도우 창 너비 800
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_HEIGHT, 600); //윈도우 창 높이 600
// context target을 기본으로 되돌림.
glBindObject(GL_WINDOW_TARGET, 0);
|
cs |
OpenGL에서는 객체를 객체의 id값으로 다루게 됩니다.
위의 코드를 보면, glGenObject(1, &objectId); 코드는 객체를 하나 생성해서, 객체에 대한 id 값을 objectId 라는 변수로 받고 있습니다. 생성한 객체를 id 값으로 여러가지를 할 수 있습니다.
위의 코드와 같은 흐름은 OpenGL에서 코드를 작성할 때의 큰 흐름을 보여줍니다.
우리는 첫 번째로 객체를 생성하고, id값으로 객체를 참조합니다.(실제 객체에 대한 data는 뒷 쪽에 가려져 있습니다.). 그 후에 객체를 id를 통해 context에 대해서 bind(activate) 합니다. bind는 객체를 활성화하는 거라고 생각하면 됩니다.(위의 예제 코드에서는 window object target을 GL_WINDOW_TARGET 이라는 상수로 정의하고 있습니다.). 그 다음 윈도우창의 옵션을 설정하고, 마지막으로 GL_WINDOW_TARGET의 객체 id를 0으로 설정해서 객체의 bind를 해제합니다. 결과적으로, objectId를 통해서 생성한 객체를 참조해서, 생성한 객체의 윈도우 창의 너비가800, 높이가 600으로 설정이 되었습니다.
그 후에 glBindObject(GL_WIDNOW_TARGET,0); 코드를 통해서 GL_WINDOW_TARGET이라는 context를 이전의 상태로 되돌립니다. 이전의 상태로 초기화 한 것입니다.
이러한 객체의 사용 방식의 좋은 점은 어떤 프로그램에서 둘 이상의 객체를 정의하고, 객체들의 옵션을 설정할 수 있으며, OpenGL의 상태(state)에 대한 작업을 할 때마다 원하는 설정으로 객체를 bind(활성화)할 수 있다는 점입니다.
예를 들어, 3D 모델에 대한 데이터를 저장하는 컨테이너 역할을 하는 객체가 있다고 가정해 봅시다. 우리가 여러개의 3D 모델 중에서 하나를 그리기를 원한다면, 그리고자 하는 객체를 bind하고 그리면 됩니다. 한번에 3D 모델의 데이터를 담고 있는 객체를 가질 수 있고, 언제든지 여러개의 모델 중 하나를 선택해서 그릴 수 있습니다.
객체에 대한 옵션들을 다시 설정할 필요 없이, 그저 간단하게 그리고 싶은 객체를 bind 하면 됩니다.
Let's get started
대략적으로 OpenGL의 사양과 라이브러리가 내부적으로 어떻게 동작하는지 몇가지 단계에 대해서 알아 보았습니다. 완전히 이해가 되지 않더라도 걱정하지 않으셔도 됩니다. 각 단계를 살펴보면서, OpenGL을 이해하는데 충분한 예제를 볼 수 있습니다.
<추가 자료>
- opengl.org : OpenGL의 공식 웹 사이트.
- OpenGL 레지스트리 : 모든 OpenGL 버전에 대한 OpenGL 사양 및 확장.
<개인적으로 하고 싶은 말>
안녕하세요. 이번 번역도 어떻게 무사히 잘 끝마쳤습니다.
이 글을 처음 보는 당시에는 이게 무슨 의미인지 이해가 되지 않았습니다. context가 뭔지, bind가 뭔지...
컴퓨터 그래픽스에 대해서 어느정도 공부를 하고, 이 글을 번역하면서 다시 읽어보니 이제야 무슨 의미인지 이해가 되네요. 아마, 컴퓨터 그래픽스에 대해서 처음 입문하는 분들은 위의 말들이 이해도 안되고, 어렵게 느껴질 것입니다. 크게 걱정하지 않으셔도 됩니다. 공부를 하다보면, 어느순간 이해가 되는 순간이 오더라구요. 그냥 마음 편하게, 이런게 있구나 읽어보는 것 만으로 충분합니다. 지금까지는 배경지식에 대한 이론적인 내용이었고, 다음 글부터 본격적으로 창을 띄워보는 걸 해볼 텐데, 잘 번역할 수 있을지 약간 걱정이 됩니다. 이 글을 읽는 사람이 있을진 모르겠지만, 아무튼, 다음 글에서 봐요~.
'컴퓨터 > learnopengl 번역' 카테고리의 다른 글
[Learn OpenGL 번역]Creating a Window(Getting started) (0) | 2021.05.27 |
---|---|
[Learn OpenGL 번역]OpenGL 소개(Introduction) (0) | 2021.05.05 |