GLFW 설정

https://www.glfw.org/

 

An OpenGL library

GLFW project home page.

www.glfw.org

먼저 공식 홈페이지에서 glfw 압축파일을 다운로드하고

 

cmake를 사용해서 컴파일을 위한 Visual studio sln 파일을 만들 수 있다.

 

Cmake가 없다면 다운로드 한 후 다음과 같이 실행, 위에 있는 source code는 아까 다운로드한 glfw 폴더로 설정해주고,

아래 있는 configure를 두번 누르고 generate 하면,

 

build로 설정한 폴더로 관련 파일들이 생긴걸 확인할 수 있다.

 

GLFW.sln을 Visual Studio로 실행한 다음, Build Solution을 해준다.

이제 build/src/debug에 가보면 glfw3.lib 파일을 확인할 수 있다.

 

아까 다운받은 glfw 폴더에는 include가 있고, 방금 lib파일을 생성했으니 이제 프로젝트에 연결해주기만 하면 된다.

 

include와 lib를 Visual Studio에서 연결하는 건 크게 두가지가 있는데, 직접 폴더내에 있는 파일들을 Visual studio 프로젝트 폴더에 옮기는 방법과, include와 lib를 다른 폴더에 넣고, Linking을 하는 방식이 있다.

 

일반적으로는 Third party 폴더를 만들어서 여기에 include, lib, source file 등을 넣고 이를 Visual studio에 연결하는 방식을 주로 사용한다.

 

나는 C:/OpenGL에 include, lib 폴더를 만들었다.

 

Visual studio에서 프로젝트를 우클릭 후 Properties -> Configuration Properties -> VC++ Directories에 들어가면 다음과 같은 화면이 나오는데, 여기서 include directories에 들어가서 OpenGL/include를 추가하고, Library Directories에는 OpenGL/lib를 추가해주면 된다.

 

그런다음 Linker -> Input에 들어가서 Additional Dependencies에 glfw3.lib를 추가해준다.

 

이렇게 설정하고 적용을 누른후 아무 cpp파일을 만들어서

#include <GLFW/glfw3.h>

int main()
{

}

다음과 같이 입력하고 실행했을때 오류가 나지 않는다면 잘 설정된 것이다.

 

 

GLAD 설정하기

https://glad.dav1d.de/

 

https://glad.dav1d.de/

Extensions...

glad.dav1d.de

 

GLAD 홈페이지에 들어가서, 

 

 

여기서 언어는 C++, gl에서 version을 3.2~3.3이상을 사용해야 한다. Profile은 Core로 설정한다.

 

OpenGL은 3.2부터 크게 변화했다. 그래서 OpenGL 3.2보다 낮은 버전은 호환해주지 않는 프로그램이 많은 것도 그 때문이다.

OpenGL은 Profile이라는 개념을 도입해, Compatibility는 3.2보다 낮은 버전을 호환하도록, Core는 3.2 이상의 버전만 호환하도록 지원하고 있다. 일반적으로는 3.2보다 낮은 버전을 호환할 필요는 없으므로 Core로 설정하는 것이다.

 

Blender라는 3D Modeling tool도 3.3으로 개발된 만큼, 일반적으로 사용되는 버전은 3.3이다. 너무 높은 버전(4.2 등)을 사용하게 되면 그래픽 카드 버전에 따라 프로그램이 실행될 수도, 안 될수도 있어 일반적으로 3.3 버전으로 설정하는 것이 안전하다.

 

다운로드를 하게 되면 glad.zip 파일을 압축해제하고, include는 아까 만든 Third party folder(예/ C:\OpenGL) 에 넣고, glad.c는 프로젝트에 넣으면 된다.

 

한가지 팁은 glad.c를 Ctrl+C 한 다음, visual studio에 Ctrl+V 하면 파일이 실제로 복사되는 것이 아닌 참조 형식으로 실제 프로젝트에는 glad.c 파일이 직접 들어가지 않아 깔끔하게 유지할 수 있다.

 

glad.c

 

그런다음,

#include <glad/glad.h>
#include <GLFW/glfw3.h>

int main()
{
	
}

 

다음 코드가 정상적으로 실행되면 잘 설치된 것이다.

 

여기서 주의할 점은 glad.h를 먼저 include해야 한다는 점이다. GLAD는 함수 포인터를 정의하기 때문에 glfw 등 다른 include를 먼저 하게 되면 충돌이 발생하거나 중복 정의되는 문제가 생길 수 있다.

저번 Vertex processor까지 해서 물체의 Translation, Rotation, Scaling을 적용하는 Model Matrix, 카메라의 위치와 회전을 정의하는 View Matrix(역행렬) Model View Matrix = $V^{-1}TRS(x)$.

 

Clip Space로 다시 좌표계를 재정의하는 Projection Matrix도 다뤘다.

$PV^{-1}TRS(x)$, 이렇게 완성된 Matrix를 보통 PVM이라고 부르고 실제 코드에서도 이 이름으로 사용하는 경우가 있다. 이 PVM을 GPU에 넘겨주는 것까지가 Vertex Processor의 역할이다.

 

 

이제 Clipping, Primitive assembler와 Rasterizer 에 대해 다뤄보겠다. 하드웨어에서 처리하는 것도 많으므로 이전보다 배워야 할 내용이 더 적다.

 

Clipping & Primitive Assembling

Primitive Assembly는 정점 정보와 index 정보들을 모아 실제 도형을 만드는 단계인데, 이건 GPU가 알아서 해준다.

 

OpenGL을 예로 들면, vertices와 indices를 모두 설정한 후, GL_TRIANGLES로 그리라고 (glDrawElements) 정해주면 알아서 GPU가 이를 Primitive type인 도형으로 만들어주는 것이다. 

 

Clipping

Clipping이란, 쉽게 말해 화면 바깥에 있는 것들은 없애버리는 것이다. 굳이 사용자의 화면에 나오지 않는데도 색깔도 입히고, Lighting도 계산하고 할 필요가 전혀 없기 때문이다.
하지만 주의할 점은 특정 점이 화면 바깥에 있다고 해서, 그 점을 없애버리게 되면 어떤 결과가 초래될 지 모른다. 그 점이 도형의 어떤 부분을 담당하는지를 모르고, 그 도형의 일부가 Clip space안에 들어 있을 수도 있기 때문이다.

 

먼저 line clipping에 대해 알아보면, Line-Segment Clipping이 있다. 화면 밖에 있는 Vertex을 clip space안으로 들여오는 것이다. top, bottom, right, left 순으로 이루어지며, 전부 완료하게 되면, Clip space 경계선 쪽으로 Vertex가 들어오게 된다.

 

 

다음은 Polygon Clipping이다. 매커니즘은 비슷하지만 때에 따라 vertex를 추가해야 할 수도 있다.

 

Clipping또한 기본적으로는 GPU가 해준다.

이렇게 clipping을 수행하고 나면, NDC(Normal Device Coordinates)로 변환하는 과정을 거친다. 그럼 이제 카메라에 보여지는 모든 물체가 [-1, 1] 사이에 있는것을 알 수 있다.

 

Rasterization

Primitive Assembly와 clipping을 거친 후, 이제 pixel로 변환하기 이전 과정이 Rasterization이다. 3D 오브젝트를 사용자의 화면에 띄우기 위해서는 픽셀로 변환하는 과정이 반드시 필요하다.

 

 

이렇게 변환된 것을 Fragment라고 부르는데, 이 Fragment가 Fragment Shader에서 처리되면 pixel로써 화면에 보여지는 것이다.

 

변환할 때는 Fragment의 위치를 계산하고, Vertex에 있는 색상, texture coordinate 등 여러 정보들을 interpolating해서 Framgment에 저장하게 된다. Interpolation에 대해서는 조금 있다가 다루겠다.

 

 

변환하는 과정은 하드웨어가 해주므로 일단 넘어가고 자세한 내용은

https://en.wikipedia.org/wiki/Bresenham's_line_algorithm

 

Bresenham's line algorithm - Wikipedia

From Wikipedia, the free encyclopedia Line-drawing algorithm Bresenham's line algorithm is a line drawing algorithm that determines the points of an n-dimensional raster that should be selected in order to form a close approximation to a straight line betw

en.wikipedia.org

를 참고하면 된다.

 

Bilinear interpolation

중학교 수학에서 내분이라는 것을 배우는데 이 매커니즘이 그대로 사용된다.

 

먼저 선에 있는 점들부터 interpolation을 시작한다. 위 그림에서 C1과 C3사이에 C4가 있는데 C1과 C3는 Vertex이므로 Color, TextureCoordinate 같은 정보를 가지고 있지만 C4는 Rasterization을 거친 Fragment이기에 아직 위치정보만 있는 상태다.

 

여기서 C4가 C1, C3와 얼마나 가까이 있는지를 내분을 통해 Color, Texture coordinate 값을 정한다. 그렇게 모든 선에 대해서 값을 정하고 나면, 이제 그 선들을 기준으로 다시 가로로 line을 그려서 똑같은 로직을 수행한다.

 

이렇게 모든 Fragment의 색상과 Texture Coordinate값 등을 정하게 된다.

 

Hidden Surface Removal

 

Z-buffer algorithm

 

Hidden Surface Removal은 Rasterization을 수행할 때 이루어지는데, 쉽게 말해 뒤에 있는 물체는 Fragment로 설정하지 않겠다는 것과 같다.

어떤 물체가 앞에 있는지는 어떻게 알 수 있을까?

 

아까 Clipping을 끝내고 나서 지금 Rasterizer에서 처리하는 모든 물체는 [-1, 1] 안에 있다. 그 상태에서 View Port Transformation을 거치게 되면 [0, 1] 사이에 들어오게 된다.

 

이때의 z 값을 depth라고 부른다고 이전 글에서 다뤘었다.

 

depth가 0이라면 가장 가까운 것, depth가 1이라면 가장 먼 것이고, 그래서 z의 값들을 하나씩 비교해가면서 가장 작은 것만을 Fragment로 변환하면 되는것이다.

이것을 z-buffer algorithm이라고 부른다. 

 

Depth를 기록하는 Depth buffer가 있고, 특정 Fragment에 새로운 물체의 값을 채우기 전, Depth Buffer와 비교해서 채우려고 하는 Fragment의 Depth가 depth buffer에 있는 Depth보다 작다면 채우고, 크다면 버리는 것이다. 이렇게 뒤에 있는 물체를 제거할 수 있다.

 

z-buffer algorithm은 하드웨어에서 지원한다.

 

Painter's Algorithm

또 다른 알고리즘으로는 Painter's algorithm이 있다. 이번엔 그냥 그리는 순서를 다르게 하는 것이다. 맨 뒤에 있는 물체부터 그리면 자연스럽게 해결된다는 매커니즘인데, z-buffer algorithm으로는 유리와 같이 투명한 물체는 표현할 수 없기 때문이다.

 

Color는 R,G,B 이렇게 3 채널로 구성되어 있지만 alpha라고 하는 투명도를 정하고 싶을 때도 있을 것이다. 그럴때 필요한 것이 Painter's Algorithm이다. 뒤에 있는 물체부터 그리고, 앞에 그리고 있는 물체가 투명하다면 그걸 반영해서 색상값을 적절히 더하는 식으로 투명도를 구현할 수 있을 것이다.

 

polygon들을 Sorting하는 과정이 반드시 필요하다.

 

Back-face Removal

또 다른 알고리즘이다.

 

만약 큐브가 있다고 했을 때, 앞면만을 보고 있다면 뒷면, 옆면 등은 그릴 필요가 없다. Back face Removal은 화면에 투영되는 면의 vertex들이 반시계 방향이라면 그리고, 그렇지 않다면 그리지 않는 알고리즘이다. 기본적으로 OpenGL은 Face를 표현할 때 반시계 방향으로 표현하기 때문에 화면에 투영된 것이 시계방향으로 Face가 정의되어 있다면 이건 뒤에 있는 물체라고 생각할 수 있다.

'개인 공부 > 컴퓨터그래픽스' 카테고리의 다른 글

05. Vertex Processor  (1) 2025.07.18
04. Transformations  (1) 2025.07.17
03. Objects  (0) 2025.06.09
02. Camera  (1) 2025.06.07
01. Rendering Pipeline  (0) 2025.06.07

이전 챕터에서 다뤘던, 특정 좌표계에서의 물체를 다른 좌표계로 옮기는 과정은 Vertex Processor가 처리한다.

 

3D object를 디자인할 때는 일반적으로 Origin을 기준으로 물체를 만들게 된다. 그 물체를 우리가 정의한 공간에 놓고, 회전하고 스케일을 키우는 작업을 하는 것이 Model Matrix라고 이해할 수 있다. 이때 Model Matrix를 적용한 공간이 World Space라고 볼 수 있다.

 

Camera도 World Space안에서 특정 좌표를 가지고, 회전을 가지고 있다. Camera의 회전과 위치를 표현한 Matrix가 View Matrix이고, 물체에 View Matrix를 적용하기 위해서는 $V^{-1}$를 적용한다는 것까지 다뤘다. 이렇게 만들어진, $V^{-1}M(x)$ 를 Model View Matrix라고 부른다.

 

Projection Matrix

여기서 더 필요한 것은, 카메라가 물체를 보았을 때 어떻게 보이느냐는 것이다. 3D 공간을 정의하긴 했지만 이를 결국에 우리는 2D로 관찰하기 때문에 이를 위한 선행 과정이 필요하다.

 

[-1, 1]사이로 정의되어 있는 큐브로 대응시키는 과정을 거친다. 여기서 처음에 궁금했던 것은, Orthographic의 경우 문제가 안 생길 것 같지만 Perspective일 경우에는 비율이 망가지는 게 아닌가 하는 생각이 들었었다.

근데 이건 우리의 눈이 Pespective로 작동하기 때문에 이런 착각이 생기는 것이고, Perspective는 멀리 있는 물체가 작게 보이는 것인데, 카메라 뷰를 저렇게 clip space로, 큐브로 만들면 우리가 원하는 결과가 나올 것이다.

 

이제 Orthographic 부터 Perspective까지 Matrix를 정의해보겠다. 우리의 목표는 특정 오브젝트의 좌표를 저 clip space안에 정의하는 것이다.

 

Orthographic Projection Matrix

 

먼저 Orthographic부터 살펴보면, left, right, bottom, top, near, far가 있을때, 특정 점의 x좌표를 r, l의 중심을 기준으로 정의할 수 있다.

$x - \frac{r+l}{2}$

직접 그림을 그려가면서 하면 바로 직관적으로 이해할 수 있다. 이제, left, right의 중심이라면 0이고, left에 가깝다면 음수, right에 가깝다면 양수로 정의되어 있다. 이제 이걸 [-1, 1] 사이로 매핑하면 되는데 지금 우리가 보고 싶은 좌표계는 left, right안에 있는 것이므로 길이는 right-left. clip space의 한변의 길이는 2이므로 x를 $\frac{2}{r-l}$ 만큼 나눠주면 된다.

 

그래서 점의 x좌표는

$x_{changed} = (x-\frac{r+l}{2}) \times \frac{2}{r-l}$

를 적용하면 clip space로 정의할 수 있다. 당연히도 만약 점이 카메라에 들어오지 않았다면 clip space에도 [-1, 1]사이에 들어오지 않을 것이다.

 

같은 방법으로 y좌표, z좌표도 다음과 같이 정의할 수 있다. 다만 주의할 점은 z축은 -를 붙여줘야 한다는 것이다. 그래서 정리하면,

1. $x_{changed} = (x-\frac{r+l}{2}) \times \frac{2}{r-l}$

2. $y\_{changed} = (y-\frac{t+b}{2}) \times \frac{2}{t-b}$

3. $z_{changed} = (z-\frac{f+n}{2}) \times -\frac{2}{f-n}$

 

이걸 Matrix로 나타내기 위해 전개한 후 계산하면, Orthographic의 Matrix는,

 

다음과 같이 정의할 수 있다. 이 계산법은 내가 직접 계산한 방식이고, 더 쉬운 방법이 있다면 그걸로 하면 된다.

 

Perspective Projection Matrix

아까 Orthographic을 계산한것과 매우 유사하지만 Perspective에서는 멀리 있는 것이 작아지게 보여야 한다는 것이다. 멀어질 때는 비례해서 멀어진다. 이는 고대 수학자가 밝혀낸 것으로 알고 있고, 예술 작품에서도 널리 사용되고 있는 것이다.

 

이 원근 계산법을 적용한다고 하면, z축은 지금 반대로 되어 있기 때문에, z가 더 작으면 작을수록 멀리 있다고 볼 수 있다. 비례해서 멀어지는 것을 감안하면 좌표에 -z를 나눠주게 되면 -z가 큰것이 더 멀리 있으므로 아귀가 맞게 된다.

또한 -z로 나눠줬기 때문에 [-1, 1] 공간이 아니라 [z, -z] 공간으로 변하게 된다. 지금 이 Projection Matrix를 적용해서 나온 값이, [x, y, z, w] 라면 여기 w가 -z가 되고, 이 Projection Matrix를 적용한 결과로는 [-w, w]공간의 정육면체로 대응된다고 생각할 수 있다.

 

그래서 Perspective Projection Matrix는, 다음과 같이 표현할 수 있다.

 

직접 계산하고 전개하는 과정을 거친다면 저 Matrix가 어떻게 만들어졌는지 이해할 수 있을 것이다.

 

 

Field of view (FOV)

게임을 할 때 많이 들어봤을 단어다. 보통 한국어로는 '시야각'이라고 부르는데, 이는 Perspective mode에서만 사용되는 개념이다. 

 

 

다음과 같은 그림에서, 시야각이 넓어지면, 볼 수 있는 공간이 확장된다고 보면 된다. 저 카메라의 박스가 커진다고 이해하면, 아까 했던 clip space를 적용했을 때 물체는 더 작아지는 대신 볼 수 있는 것들이 많아지겠구나 하고 이해하면 된다.

 

Viewport

- A rectangular area of the display window: x, y, w, h

 

 

View port는 최종적으로 보여지는 화면이다. 3D게임을 할 때도 창 모드로 전환 후 화면 어디에든 놓을 수 있는 것처럼 카메라가 보여주는 것이 화면 어디에 어느 크기로 보여질 지도 정해줄 수 있다.

 

 

이것도 Matrix가 필요하다. 아까 Projection Matrix를 적용하면 clip space안에서 정의되는데 이제는 화면 안에서 정의되어야 한다.

이 Matrix는 Viewport Matrix, W라고 부른다.

 

이건 화면마다 다르므로 결과만 보자면, 아까 [-1, 1]로 clipping 한 것을, x, y좌표들은 $win_{x}, win_{y}$로 window안에서의 x, y 좌표로 변환되고, z좌표는 depth로 변환된다. depth는 0.0부터 1.0까지 있다. near는 0으로, far는 1로 매핑된다.

 

Aspect Ratio

이건 한 번쯤 들어봤을 것이다. 우리가 주로 사용하는 16:9나 옛날 4:3 까지.

Aspect Ratio의 정확한 정의는 width/height다. 그래서 우리가 주로 사용하는 TV나 모니터는 16:9 비율이므로 aspect ratio는 16/9가 되는 것이다.

 

Projection Matrix부터, Viewport까지, Aspect Ratio가 맞지 않다면 화면이 늘어져보이거나 짤리거나 축소되어서 왜곡될 것이다.

aspect ratio를 맞춰주는 것이 중요한데, 아까 전에 했던, right-left가 Width, top-bottom이 Height라고 보면, 이 (right-left)/(top-bottom)이 Aspect ratio고, 만일 16:9 화면으로 보여지고 싶다면 이때부터 aspect ratio를 16/9로 맞춰놓아야 하는것이다. 그래야 clip space로 찌부되더라도 다시 screen space로 넘어오면서 정상적으로 보여질 것이다.

 

 

 

 

이해를 돕기 위해 [-1, 1] clipping space라는 개념을 사용했지만, 사실 아까 Perspective Projection Matrix에서도 보듯이 아직은 [-1, 1]로 clipping된 것이 아니고, [-w, w]로 clipping된 것이다. orthographic의 경우 w=1이지만, GPU는 그런건 신경쓰지 않고 무조건 w의 값을 읽고 그를 기준으로 Clipping 등 여러 작업을 거친 후 비로소 NDC(Normalized Device Coordinates). x, y, z ∈ [-1, 1] 공간으로 바꾼다.

다음 챕터에서 더 자세히 다룰 것이다.

 

'개인 공부 > 컴퓨터그래픽스' 카테고리의 다른 글

06 Clipping, Rasterization  (1) 2025.07.19
04. Transformations  (1) 2025.07.17
03. Objects  (0) 2025.06.09
02. Camera  (1) 2025.06.07
01. Rendering Pipeline  (0) 2025.06.07

Affine Space

Affine space란 선형대수에서 벡터와 점을 표현할 때 이를 구분하기 위해 만든 개념이라고 생각하면 좋을 것 같다. 다른 내용들도 있지만, 나중에 찾아보는 걸로 했다.

Affine space는

- Scalars

- Vectors

- Points

이렇게 3가지 요소를 가지고 있다.

 일반적으로 수학에서 사용하는 좌표공간처럼 (3, 2)에서 (1, 1)로 연결된 벡터라는 식으로 표현하는 것이 아니라, 만약 (3, 2)라는 벡터가 있다면 이는 (0, 0)에서 (3, 2)로 연결된 벡터로 정의된다. 벡터는 위치를 옮겨도 같기에 항상 원점에서 시작하는 것이다. 참고로 벡터의 시작을  tail, 끝을 head라고 한다.

 벡터나 점 또한 선형대수의 벡터로 나타낼 수 있어야 한다. 이를 위해 고안된 것이 Homogeneous Coordinate이다.

다음과 같이 차원을 추가해서 점이라면 1을, 벡터라면 0을 넣는 식이다.

Linear Transformations

선형대수에 대한 지식이 있다면, Linear Transformation은 Matrix를 통해 이루어 진다는 것을 기억할 것이다.

만약 3차원 공간이고, 방금 위에서 설명한 Homogeneous Coordinate를 사용한다고 하면, 점 또는 벡터는 4차원이므로 4x4 Matrix를 사용한다면 한 점을 다른 점으로 이동시키는 Transformation이 적용될 수 있을 것이다.

그래픽스에서는 Transformation을 다음 3가지로 나누어서 분류한다. Translation, Rotation, Scaling

Translation

오브젝트를 특정 값만큼 이동시키는 것을 말한다. 모든 점을 한번에 이동시키기 때문에 회전하지 않고 그대로 움직인다.

(x’ = x + d)

3차원 공간이라면 x, y, z에 dx, dy, dz를 더하는 것을 생각해볼 수 있다. 그래서 물체는 그대로 유지된 채로 이동할 것이다.

다음과 같이 Translation Matrix를 정의할 수 있다. 만약 점을 이동시키고 싶다면 위 메트릭스와 곱하면 된다.  3번 칼럼까지는 Identity Matrix와 동일한 구조를 가지고 있기 때문에 결국 위 메트릭스는 점을 dx, dy, dz만큼 이동시키는 역할을 한다. 예시를 하나만 들어봐도 바로 직관적으로 납득할 수 있다.

Rotation

Euler Angle

 

Euler angle은 가장 쉽고 직관적으로 납득할 수 있는 회전 방법이다. x, y, z 축을 기준으로 회전이 이루어지게 된다. 일반적으로 회전을 할 때는  Right Hand Rule을 따르게 된다.

 

Euler angle의 가장 큰 문제는 Gimbal Lock 현상이다.

 

이렇게 생긴 것을 Gimbal이라고 부르는데, Euler angle을 표현할 때도 혹은 실제 계산에서도 Gimbal의 개념이 사용된다. Euler angle에서는 회전 순서가 중요하기 때문이다. x축을 기준으로 90만큼, y축을 기준으로 90만큼 회전한다고 했을때, 전자를 먼저 하느냐 후자를 먼저하느냐에 따라 결과가 달라진다. 이는 계산 복잡도를 증가시키는 요인이 되기도 하고, 위 Gimbal이 제대로 돌아갈 수 없는 상태를 만들기도 한다.

 

보통 Euler angle에서는 가장 바깥쪽 부터 z, y, x 순서대로 정의하는 경우가 많다. Unity에서도 기본으로 z, y, x 순으로 회전할 수 있도록 구현되어 있다. 근데 여기서 회전하다가 z와 y가 겹치게 되면 축 회전의 자유도가 제한된다. 이 현상을 Gimbal lock이라고 부른다.

 

Gimbal lock외에도 계산의 복잡성으로 인해 Euler angle보다는 Quaternion을 더 많이 사용하게 된다.

Gimbal Lock

Quaternion

https://eater.net/quaternions

 

Visualizing quaternions, an explorable video series

Explaining how quaternions, a four-dimensional number system, describe 3d rotation.

eater.net

직관적인 이해가 부족해서 3blue1brown 유튜브 영상과 시각 자료를 활용해서 이해해봤다.

 

Quaternion은 하나의 Real number와 3개의 허수로 이루어져 있다.

 

$a + bi + cj + kj$

 

직접 직관적으로 이해하는 것이 좋을 것이다. 위 예제를 시도해보면, 

$ q = cos(\theta ) + sin(\theta )(ai + bj + ck)$

로 로테이션을 정의할 수 있다는 것을 알 수 있다. 근데 이때 q만 적용하게 되면 물체의 크기와 위치또한 변하게 된다. 그래서 

$q^{-1}$를 추가로 곱해주게 된다. $\theta$를 두번 적용했으므로 만약 $\theta$가 45라면 실제로는 90도 회전하게 된다. 근데 어느 방향으로 회전할까? 90도를 어느 축을 기준으로 어떻게 회전하느냐 하는 의문이 생길 수 밖에 없다.

 

이는 3개의 complex number에 곱해진 값들, a, b, c에 의해 결정된다. 직관적으로 이해하기 위해서는 i를 x축, j를 y축, k를 z축으로 가정해야 한다. 또한, Quaternion을 Rotation에 사용할 때는 $a^{2} + b^{2} + c^{2} + d^{2} = 1$ 이라는 조건을 만족해야 한다. 이는 쿼터니언이 반지름이 1인 4차원 구인 초구를 가정하기 때문이다. 당연히 이는 3차원에 살고 있는 우리가 직관적으로 이해할 수는 없지만 구를 자르면 단면이 원이 되듯이, 초구를 자르면 단면이 구가 되고, 중심으로부터의 거리가 1인 점들의 집합으로 생각할 수 있다.

 

다시 돌아와서, i를 x축, j를 y축, k를 z축으로 가정하면, i가 1이고 나머지가 0이라면 x축을 기준으로 회전 - Right Hand Rule 을 적용.  j가 1이고 나머지가 0이라면 y축을 기준으로, k가 1이고 나머지가 0이라면 z축을 기준으로 회전하는 것을 확인할 수 있다.

 

직접 위 사이트에 들어가서 시도해보면 금방 감이 잡힐 것이다.

 

그래서 구체적인 식은, 점 x를 회전한 결과가 f(x)라고 할 때,

$f(x) = q * x * q^{-1}$

이 된다.

Rotation Matrix

이제 회전을 계산하는 법을 알았으니 Matrix로 표현해야 한다. 위에서 다뤘듯, 3차원 공간에서 Homogeneous Coordinate를 사용한다면 4x1 벡터로 3차원 공간에서의 벡터와 점을 표현할 수 있으므로 4 x 4 Matrix만 있으면 Linear Transformation을 표현할 수 있다.

 

먼저 Quaternion은 생각하지 않고, 어떤 벡터 혹은 점을 회전하는 Rotation Matrix를 계산한다고 하면, Roll, Pitch, Yaw 개념을 알면 편하다.

 

3차원에서 물체의 회전을 나타낼 때 사용되는 개념들이다. 지금 보면 x, y, z축이 모두 반대로 가 있다는 것을 알 수가 있다. 왜 반대로 해놨을까? 만약 x축을 기준으로 Right Hand Rule을 사용해서 회전을 한다고 하면, yz 평면안에서 회전될 것이다. 여기서 Right hand rule을 사용해서 회전한다고 하면 yz 평면을 기준으로 할 때 시계방향이 아닌 반시계 방향으로 회전하는 것을 계산해야 한다. -를 붙여서 계산할 수도 있겠지만 편의를 위해서 축들을 반대로 해 놓은 것이라고 예측할 수 있다.

 

그래서 차근차근 계산을 해 보면, 위 그림에서 Pitch를 적용하는 Matrix를 생각해보면, -x축을 기준으로 Right hand rule로 회전하는 것으로 생각할 수 있다. $\hat{j}$ 와 $\hat{k}$를 $\theta$ 만큼 회전시킨다고 생각하면 된다.

 

그래서 yaw, pitch, roll의 Matrix들을 곱해서 하나의 4x4 Matrix로 만들 수 있고, 이를 Rotation Matrix라고 한다. 유도하는 법은 어렵지 않기도 하고, 직접 찾아보면 자료가 많다.

 

그리고 Quaternion은 기존에는 Matrix가 아니라 곱셈으로 계산했었지만 결국 GPU에 데이터를 보내줄 때는 Rotation Matrix로 변환해야 하기에 Quaternion 또한 Rotation Matrix로 변환해야 한다.

 

 

Rotation Matrix는 이렇게 된다. q0는 Real number, 나머지는 Complex number이다.

 

Scaling

Scaling은 물체를 확대 축소하는 것을 말한다. x, y, z 축 방향으로만 확대축소할 수 있다고 정의한다.

 

Matrix는 간단하게,

$\begin{bmatrix}
s_{x} & 0 & 0 & 0 \\
0 & s_{y} & 0 & 0 \\
0 & 0 & 0 & 0 \\
0 & 0 & 0 s_{z} & 1 \\
\end{bmatrix}$

 

이렇게 된다. 이 Matrix를 적용하면 모든 점들이 scale factor만큼 멀어지거나 가까워 질 것이다.

 

 

Model Matrix

Translation, Rotation, Scaling에 관련한 4x4 Matrix 3개를 미리 곱해 놓은 것을 Model Matrix라고 부른다. Linear Transformation은 순서가 중요한데, Scale, Rotation, Translation 순서로 적용된다. 그럼으로 Model Matrix는

Model Matrix = TRS(x)가 되겠다. (Matrix는 오른쪽 부터 적용.)

 

View Transformation

이제 Model의 크기, 회전, 위치를 정했으니 이 모델이 카메라에 어떻게 보여질 지를 생각해야 한다.

Camera의 회전, 위치를 나타낸 Matrix를 View Matrix라고 부른다.

 

 

다음과 같이 구성되어 있으며, 위 Model Matrix를 만드는 과정에서 Rotation과 Translation의 메커니즘을 그대로 사용하게 된다. 카메라는 크기가 없으므로 Scale은 적용하지 않는다.

 

우리가 화면에서 보는 것은, 카메라가 물체를 바라보는 것과 개념적으로 동일하다. 그러므로 물체를 카메라의 입장에서 바라본다는 것을 생각해보면, View Matrix의 역행렬을 Model Matrix에 적용하게 되면, 카메라의 입장에서 바라보는 물체가 된다.

 

그래서 일반적으로 View Matrix의 역행렬을 사용하게 된다.

 

 

 

이제 Model Matrix를 적용한 후, View Matrix의 역행렬을 적용하면 카메라가 바라보는 물체를 Linear Transformation으로써 표현할 수 있다. 이 Matrix를 ModelView Matrix라고 부른다.

 

$V^{-1}TRS(x)$

 

하지만 아직 완벽하지는 않다. Orthographic, Perspective도 적용하지 않았고, 실제로 물체가 카메라의 View port 범위 안에 있는지도 알 수 없기 때문이다. 

'개인 공부 > 컴퓨터그래픽스' 카테고리의 다른 글

06 Clipping, Rasterization  (1) 2025.07.19
05. Vertex Processor  (1) 2025.07.18
03. Objects  (0) 2025.06.09
02. Camera  (1) 2025.06.07
01. Rendering Pipeline  (0) 2025.06.07

Synthetic Objects

카메라처럼 그래픽스에서 가상의 오브젝트를 Synthetic Object라고 부른다.

 

이 오브젝트들은 정점들(Vertices)와 Faces로 이루어져 있다.각 Vertex는,

position, normal, color, texture coord 등의 정보를 가지고 있고, 

Faces들은 vertex이 어떻게 연결되어 있는지를 알려주는 indicese 등의 정보를 가지고 있다.

 

생각

 

다음과 같은 모델을 어떻게 데이터로 표현해야 할까?

 

Color, Normal, texture등을 제외하고 각 Vertex가 위치 정보 (position)만 가지고 있다고 가정할 때,

 

3차원 공간이기에 각 vertex마다 x, y, z로 이루어진 3차원 벡터정보를 담고 있을 것이다.

 

근데 생각해봐야 하는 것이, 지금 면(Face)들이 사각형, 삼각형, 다각형도 있는데 이걸 어떻게 컴퓨터 구조로 표현해야 할지 고민해야 한다.

 

 

Polygon Mesh

 

먼저 첫번째로 Polygon Mesh 방식은 다음과 같이 Vertex list들을 정해놓고, 각 Face마다 Vertex의 position index 순서를 지정함으로써 그릴 수 있다. 근데 이 방법은 먼저 각 면이 삼각형인지 사각형인지 몇각형인지를 미리 알려줘야 한다는 단점을 안고 있다.

 

그리고 실제로는 권장하지 않는 방식인데, 그 이유는 GPU는 기본적으로 삼각형으로 모든 것을 처리하기 때문에, 위 구조로 디자인을 한다고 하더라도 내부적으로는 결국 모든 것이 삼각형으로 처리된다. 다각형을 삼각형으로 바꾸는 과정을 Tessellation이라고 한다.

 

 

이 방법으로 하게 되면 결국 내부적으로 계산을 한 번 더 하게 된다.

 

Triangulated Mesh

이번에는 미리 삼각형으로 분할해서 처리하는 방식이다. 위 예제와는 달리, 모든 Face를 삼각형으로 처리하면 큰 장점이 하나 있는데, 굳이 Face마다 데이터를 분할해서 나눌 필요가 없다. 어처피 삼각형이라면 3개를 단위로 읽어서 Face를 처리하면 되기 때문이다.

 

이렇게 Vertex list를 정의하지 않고 그냥 position들의 조합으로만 나타낼 수도 있다. 이렇게 하면 Face마다 사각형인지 다각형인지 삼각형인지를 고려할 필요가 없고, 그냥 3개씩 끊어서 처리하면 되니 훨씬 효율적이다.

 

위 그림에 나와있는 1, 2, 3번째 순서대로 하나의 삼각형, 그 다음 4, 5, 6번째가 또 다른 삼각형, 이런식으로 처리하게 된다.

 

하지만 이 방법은 메모리를 더 쓸 수 있다는 단점이 존재하는데, 이를 해결하기 위해서 Polygon Mesh와 연결해서,

 

 

이런식으로 구조를 변경할 수도 있다. 미리 Position list를 정의해두고, index로만 삼각형의 순서를 정해 놓는 방식이다.

 

 

참고로 OpenGL ES와 Direct X는 Triangulated Mesh 방법만 지원한다.

 

GPU 처리 과정

 

위와 같이 Vertex Array들을 정의했다면 이걸 CPU 메모리에서 GPU 메모리로 옮겨주는 과정이 필요하다.

 

 

 

CPU 메모리에서 VRAM으로 데이터를 넘기는 것은 꽤나 오랜 시간이 걸린다. 서로 독립적인 하드웨어이므로 이 과정을 최소화 해 줄 필요성이 있다.

 

이를 위해 OpenGL에서는 Buffer Object라는 것을 지원한다. 그 중 대표적으로 VBOs(Vertex Buffer Objects), IBO(Index Buffer Object)등이 있다.

 

VBOs와 IBO에 Vertex list와 index 정보를 저장하고 GPU에 한번에 넘겨주기만 하면, 다시는 오브젝트의 정보를 VRAM에 올릴 필요가 없어지게 된다.

 

OpenGL 코드는 나중에 알아볼 것이다.

'개인 공부 > 컴퓨터그래픽스' 카테고리의 다른 글

05. Vertex Processor  (1) 2025.07.18
04. Transformations  (1) 2025.07.17
02. Camera  (1) 2025.06.07
01. Rendering Pipeline  (0) 2025.06.07
00. 컴퓨터 그래픽과 OpenGL의 역사  (5) 2025.06.07

Synthetic Camera

 

그래픽스에서는 현실 세계의 눈을 대신할 가상 카메라가 있다. 이를 Synthetic Camera라고 한다.

이 Synthetic Camera는 Perspective 모드와 Othographic모드가 있다. 위 사진은 Perspective 모드의 카메라를 나타낸 것이다.

 

과정을 간단하게 살펴보면, 3D 점 P에서 COP를 통과하는 선을 지나, Image plane과 닿는 곳이 2D 위치가 되는것이다. 두 모드에 대해서 각각 다뤄보겠다.

 

Perspective Mode

 

Perspective Projection

 

 

이렇게 Object가 있을때, 각 Vertex들과 COP를 연결한 Projector들과 plane이 만나는 점을 찾는 방식이다.

 

Othographic Projection

 

Orthographic 은 오히려 더 단순하다 그냥 Object와 plane을 연결해주면 된다. 근데 이때는 어떤 기준으로 연결하는지가 궁금할 수 있다. 그건 plane의 Normal Vector를 사용하면 될 것이다. 조금만 생각해보면 바로 이해가 될 것이다.

Normal Vector of plane

 

Clipping Planes

근데 그렇다고 해서 카메라를 바라보고 있는 물체(카메라에 인식되는)를 전부 그리는 것은 때때로는 불가능하거나 매우 비효율적일 수 있다.

 

그래서 있는 것이 Clipping planes이다.

Clipping Planes

 

이렇게 Front Clipping과, Back Clipping을 설정해서 Front Clipping plane부터 Back clipping plane까지만 그리도록 하고, 여기 안에 있는 물체들만 View plane에 그려주면 된다.

 

Extrinsic Parameters

외부 파라미터로는 우선 카메라의 포지션 (x, y, z) 그리고 Orientation (pitch, yaw, roll)이 있다. Orientation은 쉽게 말해 카메라 회전이라고 보면 된다. pitch는 끄덕, yaw는 도리, roll은 갸웃으로 생각하면 되는데, Synthetic Camera는 사람의 눈을 흉내낸 것이기에 직접 자기 눈으로 실험해보면 된다. 눈을 그대로 두고, 끄덕, 도리, 갸웃을 해보면 이해가 직관적으로 될 것이다.

 

FOV - Field Of View

게임을 할 때 정말 많이 들어보는 것인데, 말 그대로 시야각이다. 실제 현실세계의 카메라는 렌즈를 통해 시야각을 조정하지만 그걸 흉내내기 위해 만든 것이다.

 

 

zoom in, zoom out을 실행하기 위해 시야각, 혹은 크기를 조절한다. 이건 트릭에 가까운데 잘 생각해 보면, 물체를 카메라가 보고 있었다고 가정해보자. 여기서 만약 FOV, 즉 시야각을 줄이게 되면 view plane에 찍히는 값은 더 적어질 것이다. 근데 결국 view plane은 사용자의 화면 크기로 바뀌어서 그려지니, 결국 확대된 효과를 보는 것이다.

 

Orthographic에서는 원근감이 없으니, 그냥 view plane의 크기를 줄이면 해결될 것이다. 결국 둘 다 view plane의 크기를 줄이는 건 똑같다고 보면 된다.

 

Camera Viewport

아까 전, View plane이 사용자의 화면에 맞게 확대된다고 했지만 사실 코딩을 할 때 그렇게 되지 않도록 하고 싶을 수도 있다. 게임에서도 창모드를 지원하게 되면 특정 영역에만 게임이 표시되는 것처럼 view plane을 화면 어디에 얼마나 그릴지를 정할 수 있는데, 이게 바로 Viewport이다. Viewport는 그래서 x, y, width, height로 구성되어 있다.

 

 

 

Aspect Ratio는, Width와 Height의 비율을 의미한다. 대부분 모니터에서는 16:9를 사용할텐데, 이는 aspect ratio 16/9로 나타낼 수 있다.

'개인 공부 > 컴퓨터그래픽스' 카테고리의 다른 글

05. Vertex Processor  (1) 2025.07.18
04. Transformations  (1) 2025.07.17
03. Objects  (0) 2025.06.09
01. Rendering Pipeline  (0) 2025.06.07
00. 컴퓨터 그래픽과 OpenGL의 역사  (5) 2025.06.07

+ Recent posts