티스토리 뷰
OPENGL
본 포스팅은 Sanjay Madhav
가 집필한 Game Programming in C++ (2018)
의 내용을 정리한 글입니다
그 중에서도 5장 OPENGL
의 내용을 다룹니다
Overview
본 장에서는 아래와 같은 내용을 배울 수 있습니다
- Initializing OpenGL
- OpenGL을 사용하기 위해 초기화하는 방법
- Triangle Basics
- 3D 그래픽스 구현을 위한 폴리곤과 좌표계
- Shaders
- 화면의 각 픽셀에 별도의 연산을 수행하는 방법
- Transformation Basics
- 물체의 좌표계에서 확대 축소 회전 이동을 적용하는 방법
- Matrices and Transformations
- 물체의 좌표계에서 게임의 좌표계로 변경하는 방법
- Texture Mapping
- OpenGL에서 텍스처를 사용하는 방법
Initializing OpenGL
기존에 사용하던 SDL 라이브러리는 2D까지만 지원하기 때문에 3D 그래픽을 구현할 수 없다
따라서 구축해둔 프레임워크에서 렌더링 부분은 OpenGL로 대체하기로 한다
- Profile Type
Core
- 데스크탑 어플리케이션을 개발할 때 사용한다
Compatibility
- 더 이상 지원하지않는 기능들을 이용해야할 때 사용한다
ES
- 모바일 어플리케이션을 개발할 때 사용한다
- openGL Extension Wrangler library
GLEW
- OpenGL을 사용함에 있어 작성해야하는 복잡한 코드들을 캡슐화한 라이브러리이다
GLEW
를 사용해 간접적으로 OpenGL을 초기화시킨다
- Initialization Order
SDL_GL_SetAttribute()
의 매개변수로 원하는 설정값들을 넘긴다- 생성하기 전에 OpenGL Context가 어떤 속성을 가질지 결정한다
SDL_CreateWindow()
의 매개변수로SDL_WINDOW_OPENGL
을 넘긴다- OpenGL을 사용하는 윈도우를 생성하도록 한다
SDL_GL_CreateContext()
의 매개변수로 윈도우를 넘긴다- 해당 윈도우에 대한 OpenGL Context를 생성한다
glewInit()
으로 OpenGL을 초기화한다- 현재 OpenGL Context가 사용할 수 있는 모든 기능들을 초기화한다
Triangle Basics
오늘날의 컴퓨터는 과거와 달리 2D 그래픽스뿐만 아니라 3D 그래픽스도 지원해야한다
3D 그래픽스를 어떤 방식으로 지원하는 지에 대해 알아본다
- Blitting
- 일정한 크기의 메모리를
Color Buffer
에 복사하는 기법 NES
시절에는 2D 게임들이 대부분이었기 때문에 이 기법으로도 충분했다- 하지만 이 기법으로는 3D 게임을 개발할 수 없다 →
Polygon Rendering
채택
※ 오늘날의 그래픽스 하드웨어들은Polygon Rendering
에 특화된 구조를 갖는다
※ 따라서 2D 그래픽스에 대해서도Polygon Rendering
을 사용한다
- 일정한 크기의 메모리를
- Polygon Rendering
- 3D 그래픽스를 구현하는 알고리듬들 중 하나이다
- 각 꼭지점
정점
에 벡터를 갖는 다각형폴리곤
을 이어붙여 물체를 구성 - 다각형의 표면은 색 또는 텍스처 등으로 채워질 수 있다
※ 제일 단순한 다각형인 삼각형이 주로 사용된다
- 각 꼭지점
- 필요 연산량이 비교적 적은 편이며 그래픽스 하드웨어 성능에 따라 유연하게 대처가능
- 게임 등의 실시간 렌더링을 요구하는 분야에서 자주 사용된다
- 3D 그래픽스를 구현하는 알고리듬들 중 하나이다
- Normalized Device Coordinates
NDC
- OpenGL에서 제공하는 기본 좌표계이다
- 오른손 좌표계로 각 축을 계산한다
- 엄지 → 축
- 검지 → 축
- 중지 → 축
- 화면 정중앙을 원점으로 한다 →
- 오른쪽으로 이동 →
- 위로 이동 →
- 뒤로 이동 →
- 위치지정에 정규화된 벡터값을 사용한다
- 화면 좌상단 끝 →
- 화면 우하단 끝 →
※ 는 임의의 값이란 뜻이다
※ 정규화되었기 때문에 각 축마다 올 수 있는 값은
- OpenGL에서 제공하는 기본 좌표계이다
- Vertex Buffer & Index Buffer
- 대부분의 폴리곤들은 혼자서만 사용되지않고 여러 개가 묶여 사용된다
- 따라서 각 물체마다 사용되는 폴리곤들을 배열로 묶어 저장한다
- 이 경우 중복되는 정점들이 존재하기 때문에 메모리가 낭비된다
Vertex Buffer
- 중복되지 않도록 정점들을 저장하는 배열
- 이 정점들만으로는 폴리곤을 어떻게 생성해야할지는 알 수 없음
Index Buffer
Vertex Buffer
와 함께 사용되는 배열- 각 폴리곤이
Vertex Buffer
내 몇 번째 정점으로 생성되어야하는지 정의
Vertex Array Object
- OpenGL은
Vertex Buffer + Index Buffer + Vertex Layout
를 객체단위로 관리
※Vertex Layout
은 각 정점마다 어떤 자료형이 저장되는지 등을 정의 - 그 객체가 바로
Vertex Array Object
이다
- OpenGL은
- 대부분의 폴리곤들은 혼자서만 사용되지않고 여러 개가 묶여 사용된다
Shaders
오늘날의 그래픽스 하드웨어들은 쉐이더라는 GPU 제어 프로그램을 지원한다
쉐이더 언어인 GLSL로 쉐이더 프로그램을 작성해 화면의 각 픽셀에 대한 별도의 연산을 수행한다
- Shader Programs
- GPU는 CPU에 비해 매우 많은 연산유닛
ALU
들을 가진다- GPU의 각
ALU
마다 거의 하나의 픽셀을 담당할 수 있다
- GPU의 각
- 병렬처리에 특화된 GPU를 그래픽스 연산에 활용하는 프로그램이다
- 각 픽셀마다 출력해야할 RGB값에 대한 계산을 GPU가 담당
- 각 픽셀마다 서로 다른 쉐이더 프로그램을 계산한 결과의 합이 할당된다
- 원한다면 각 픽셀마다 특별한 효과를 넣을 수 있다
- (기본적으로) 쉐이더 프로그램 총 개수는 모든 정점의 개수와 같다
- 하나의 쉐이더 프로그램은 여러 개의 쉐이더들로 이루어진다
- 그 종류로는
Vertex Shaders
또는Fragment Shaders
등이 있다
- 그 종류로는
- GPU는 CPU에 비해 매우 많은 연산유닛
- Vertex Shaders
[filename].vert
로 정의되는 쉐이더 프로그램 구성요소- 정점 속성을 입력받고 출력 픽셀의 위치를 결정하는 역할을 수행
gl_Position
에 픽셀 위치를 대입하여 결정
- 주로 여기에서
Object Space → World Space
변환을 수행
- Fragment Shaders
[filename].frag
로 정의되는 쉐이더 프로그램 구성요소- 텍스처 등을 입력받고 픽셀의 RGB값을 결정하는 역할을 수행
Color Buffer
에 부합하는 출력 변수에 대입하여 결정
※Color Buffer
의 원소가 RGBA라면vec4
를 출력 변수로 설정
- 주로 여기에서 특별한 시각적 효과를 가미한다
- 별도의 라이팅 계산 등을 수행
- Applying Shader Programs
- 어떤 종류의 쉐이더를 생성할지 결정
[shader_id] = glCreateShader([shader_type]);
- GLSL로 작성된 쉐이더 소스코드를 할당
glShaderSource([shader_id], 1, &[shader_file], nullptr);
- 쉐이더 소스코드를 컴파일
glCompileShader([shader_id]);
- 쉐이더 프로그램에 부착
glAttachShader([program_id], [shader_id]);
- 쉐이더 프로그램에 부착된 쉐이더들을 링크
glLinkProgram([program_id]);
※ 쉐이더 프로그램에 사용할 쉐이더들을 모두 부착한 후에 수행할 것
- 쉐이더 프로그램 활성화
glUseProgram([program_id]);
※ 매 프레임마다 쉐이더 프로그램을 활성화시켜줘야 한다
- 현재 활성화된 쉐이더 프로그램을 기반으로 출력
glDrawElements([polygon_type], [index_buffer_element_size], [index_type], nullptr);
- 어떤 종류의 쉐이더를 생성할지 결정
Transformation Basics
게임상의 개체들은 확대축소회전이동을 편리하게 하기 위해 각자만의 좌표계를 가진다
그리고 확대 축소 회전 이동 각 연산들로 개체들을 변형시킬 수 있다
- Object Space or
Model Space
- 각 개체가 가지는 독립적인 좌표계를 말한다
NDC
와 유사한 구조를 갖는다- 개체의 중심을 원점 으로 결정한다
- 오른손 좌표계에 따라 각 축의 값을 증감한다
- 각 정점은 비정규화된 벡터값으로 표현된다
- 화면의 원하는 위치에 출력하기 위해서는
World Space
로 변환되어야 한다
- World Space
- 화면에 출력되는 게임세계의 고유한 좌표계를 말한다
- 게임세계 → 게임의 맵 또는 UI 등에 해당한다
NDC
와 유사한 구조를 갖는다- 세계에서 임의의 위치를 원점으로 결정한다
- 오른손 좌표계에 따라 각 축의 값을 증감한다
- 각 정점은 정규화된 벡터값으로 표현된다
- 고유한
Vertex Array Object
를 사용해Object Space
를 변환한다
- 화면에 출력되는 게임세계의 고유한 좌표계를 말한다
- Transformation
Translation
- 개체가 이동되는 연산을 말한다
- 축으로 만큼, 축으로 만큼 이동할 경우
- 개체의 모든 정점에 대해 이 연산을 수행하여 이동시킬 수 있다
Scale
- 개체가 확대 또는 축소되는 연산을 말한다
- 축으로 만큼, 축으로 만큼 확대할 경우
- 개체의 모든 정점에 대해 이 연산을 수행하여 확대시킬 수 있다
※ 축소의 경우 또는 가 사이의 값이다
※ 와 가 동일한 경우Uniform Scale
이라 한다
Rotation
- 개체가 회전되는 연산을 말한다
- 반시계방향으로 만큼 회전할 경우
- 개체의 모든 정점에 대해 이 연산을 수행하여 회전시킬 수 있다
- Combination
- 위의 확대축소회전이동 연산들을 조합하여 한 번에 수행할 수 있다
- 다만 연산 순서에 따라 다른 결과값이 나올 수 있음을 주의해야한다
- 특히 이동 연산과 회전 연산은
교환 법칙
을 만족하지않는다
- 특히 이동 연산과 회전 연산은
- 의도한 대로 변형시키려면
Scale → Rotation → Translation
순서로 수행한다
Matrices and Transformations
개체들을 화면에 표현하기 위해서 화면의 좌표계로 변환할 필요가 있다
이 과정또한 일련의 행렬곱으로 표현될 수 있다
- Matrix Multiplication
- 위의
Combination
에서 언급되었던 순서를 행렬곱으로 표현할 수 있다- 변형 연산들의 행렬곱 결과를 변형 행렬 라 하자
- 정점의 위치벡터 가 변형 행렬 의 앞에 오는지 뒤에 오는지에 따라
- 가 행 열 벡터가 될지, 행 열 벡터가 될지 결정된다
- 위의
- Combination
Translation
연산은 보다 더 큰 차원을 필요로 한다- 행렬곱은 전자 행렬의 열 개수와 후자 행렬의 행 개수가 동일해야하므로
- 를 비롯한 다른 행렬들의 차원을 한 단계 늘린다 →
W Component
- 위에서 언급한 변형 행렬을
World Transform
행렬이라고 한다Scale → Rotation → Translation
순서의 행렬곱으로 구해진다
- Clip Space
World Transform
행렬과 의 곱으로 개체가World Space
상에서- 어떤 위치에 존재하는지를 알 수 있게 되었다
- 개체의
World Space
상 위치에서 화면의 픽셀 위치로 변경할 필요가 있다- 화면상의 위치들을 포함하는 좌표계를
Clip Space
라고 한다 W Component
를 가진다는 것이NDC
와Clip Space
의 차이점이다
- 화면상의 위치들을 포함하는 좌표계를
World Space → Clip Space
변환을 수행하는 행렬을View Projection
행렬이라 한다- 3D 그래픽스에서의
View Projection
행렬은 복잡한 구조를 가지지만 - 이 장에서는 2D 그래픽스를 사용하므로 간단한 구조의
View Projection
을 사용한다
※World Space
상의 하나의 단위가Clip Space
상의 하나의 단위와 동일하기 때문
- 3D 그래픽스에서의
- Applying to Shaders
- 이전에 언급했던 것처럼 쉐이더가 정점에 대한 연산을 수행할 수 있다
- 특히
Object Space → World Space → Clip Space
변환을 수행할 수 있다
- 특히
- 각 쉐이더 프로그램에
World Transform
및View Projection
행렬을 복사하기보다- 모든 쉐이더 프로그램들이 공유할 수 있는
uniform
변수로 전달한다
- 모든 쉐이더 프로그램들이 공유할 수 있는
World Transform
행렬은 게임 내 개체들이 움직임에 따라 변경될 수 있다- 따라서 화면 출력을 할 때마다
World Transform
행렬을 다시 구한다
- 따라서 화면 출력을 할 때마다
- 반대로
View Projection
행렬은 게임 초기화 이후 변경하지않는다
- 이전에 언급했던 것처럼 쉐이더가 정점에 대한 연산을 수행할 수 있다
Texture Mapping
OpenGL에서는 텍스처를 사용하기 위해 별도의 좌표계를 사용한다
또한 텍스처를 사용함에 따라 쉐이더 프로그램 등을 변경하게 된다
- Texture Coordinates or
UV Coordinates
- 텍스처를 사용하기 위해서는 각 정점에 추가적인 값을 저장해야한다
- 해당 정점이 텍스처의 어느 부분에 해당하는지를 명시해야하기 때문
- 따라서
Vertex Buffer
에 저장되는 정점의 크기가 증가한다
- 각 정점이 텍스처의 어떤 위치에 해당하는지를
UV Coordinates
로 표현한다- 2차원 좌표계로서 텍스처의 좌하단 끝을 원점 으로 한다
- 오른쪽 방향은 이고 위 방향은 에 해당한다
- 정규화되었기 때문에 각 축은 의 값을 가질 수 있다
- 각 정점마다 추가로 가지게 된
UV Coordinates
상의 좌표를Texel
이라 한다- 폴리곤마다 각 정점의
Texel
이 존재할 것이고 - 텍스처상에서 그
Texel
들을 기반으로 가상의 폴리곤을 만들 수 있을 것이다 - 텍스처의 폴리곤에 해당하는 텍스처의 일부분을 원본 폴리곤의 면에 삽입한다
- 폴리곤마다 각 정점의
- 텍스처를 사용하기 위해서는 각 정점에 추가적인 값을 저장해야한다
- Nearest Neighbor Filtering
- 폴리곤의 면적이
Texel
로 구해진 텍스처의 면적보다 클 경우- 이로 인해 빈공간이 발생하고 이를 메꿔야할 것이다
Nearest Neighbor Filtering
기법은 다음과 같은 절차로 빈공간을 메꾼다- 삽입하려는 텍스처의
Texel
들을 확대한다 Texel
들의 좌표값이 확대됨에 따라Texel
간 간격이 벌어진다- 벌어진 간극을 메꿀
Texel
로 가장 가까운Texel
의 복사본을 할당한다
- 삽입하려는 텍스처의
- 가장 간단한 방식이지만 텍스처가 확대될수록 동일한 색이 반복되는 구간이 많아진다
- 블럭 단위로 색이 나뉘어지는 현상을 볼 수 있게 된다 →
계단 현상
- 블럭 단위로 색이 나뉘어지는 현상을 볼 수 있게 된다 →
- 폴리곤의 면적이
- Bilinear Filtering
Nearest Neighbor Filtering
처럼 빈공간을 메꾸기 위해 사용한다Bilinear Filtering
기법은 다음과 같은 절차로 빈공간을 메꾼다- 삽입하려는 텍스처의
Texel
들을 확대한다 Texel
들의 좌표값이 확대됨에 따라Texel
간 간격이 벌어진다- 벌어진 간극을 메꿀
Texel
로 인접한Texel
들의 평균값을 할당한다
- 삽입하려는 텍스처의
- 연산량이 비교적 많지만 텍스처가 확대되어도 자연스러운 색변화를 보여준다
- 대신 텍스처가 뿌옇게 보이는 단점이 존재한다 →
블러 효과
- 대신 텍스처가 뿌옇게 보이는 단점이 존재한다 →
- Alpha Blending
Color Buffer
의 원소는 주로 RGBA 총 4차원의 벡터가 사용된다- 이 중 A는
Alpha Channel
로 주로 투명도를 저장하는 데에 사용된다
- 이 중 A는
Alpha Blending
은 A값을 기반으로 투명도를 임의로 결정하는 기법이다- 이 기법은 일반적으로 다음과 같은 식을 사용한다
- 위의 식을 적용하면 임의의 픽셀에 대해
- A값이 인 RGBA 가 기존 픽셀의 RGB 값을 무시하고 덮어쓴다
- A값이 인 RGBA 가 기존 픽셀의 RGB 값을 변경하지 못한다
Exercise
예제 풀이는 https://github.com/BaeMinCheon/game-programming-in-cpp 의 commits
참고
'Book' 카테고리의 다른 글
ARTIFICIAL INTELLIGENCE (0) | 2018.07.04 |
---|---|
VECTORS AND BASIC PHYSICS (0) | 2018.07.04 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- ATOM
- C/C++
- Slack
- visual-studio
- visualstudio
- PopeTV
- Python
- unreal
- Anaconda
- git
- DirectX
- dll
- CAFFE
- vscode
- Docker
- JIT
- windows
- Hashtable
- Game
- WindowAPI
- A.I.
- CUDA
- NOX
- pclaf
- unity
- cuDNN
- csharp
- tensorflow
- lib
- shader
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 29 | 30 | 31 |
글 보관함