서론
시리즈 C 스타트업의 iOS 개발자로 첫 커리어를 시작하게 되었습니다.
지원 당시 채용공고에서 Metal과 같은 저수준 GPU API를 사용하게 될 것이라 명시되어있었습니다.
이와 관련해서 나온 컴퓨터 그래픽스 관련 기술면접 질문은 답변하지 못하여 아쉬웠습니다.
관련 경험이 없었지만 포기하지 않고 iOS에서의 렌더링 사이클과 UIkit과 SwiftUI의 더티영역에 대한 처리 과정 등에 대해 공부했던 내용을 말씀드렸던 기억이 납니다 ㅎㅎ.
그래픽스 관련해서 OpenGL을 먼저 참고해보는 게 좋을 것이라는 면접관님의 조언에 따라 첫 출근전에 이론부터 공부해보고자 합니다.
구립도서관을 열심히 서칭했지만 그래픽스 관련 서적은 찾기가 쉽지 않았습니다. 결국 학교 도서관까지 가게 되었습니다 ㅠㅠ.
3차원 컴퓨터 그래픽스의 정의
3차원으로 표현된 물체를 입력으로 받아서 2차원 영상으로 출력하는 작업.
2차원 영상을 프레임이라고도 함.
프레임이 얼마나 빠르게 만들어지느냐에 따라서 Real time Graphics와 Non Real time Graphics로 나뉨
Real time Graphics
- 보통 30 Frames per second 이상(FPS)
- Games, Virtual/Augmented Reality, interacive user Interfaces
Non Real time Graphics
그래픽스 제작 5단계
Modeling, Rigging, Animation은 보통 Graphic Artist, Designer들이 오프라인에서 수행함.
최종적으로 애니메이션이 생성되면 실시간으로 재생하고 렌더링을 수행하고 필요에 따라 Post - Processing을 수행하며 이것은 런타임에 이루어지며 프로그램이 자동적으로 실행함.

Graphics API
Modeling, Rigging, Animation은 오프라인에서 그래픽 아티스트가 수행함.
그렇게 만들어진 애니메이션을 재생하고 Rendering하고 후처리하는 것은 프로그램이 수행함.
게임과 같은 경우 앱 프로그램을 만드는 데 게임엔진이라고 하는 개발 툴을 많이 사용함(유니티, 언리얼)
그러한 기능들 중에 Animation 재생 , Rendering, Post-Processing 작업들이 포함됨.
게임 엔진 아래에는 그래픽스 인터페이스(API)가 있음.
대표적으로 Direct3D, OpenGL(Khronos 그룹의 표준화 작업을 걸쳐 만듬), OpenGL ES(모바일의 경우 OpenGL의 일부를 따서 만든 API)
그 밑에는 GPU 하드웨어가 있음. (그래픽스 프로세스 유닛)
OpenGL ES는 GPU에 대한 소프트웨어 인터페이스다라고 이해하면 됨.
앞으로 OpenGL ES를 이용해서 그래픽스 애플리케이션이 필요로하는 기본적인 알고리즘을 공부할것임.
Game Program (App) |
Game Engine |
Graphics API |
GPU |
모델링
- 모델이란?
- 컴퓨터가 이해하고 처리할 수 있는 형태로 물체를 표현한 것.
- 모델링
- 모델을 만들어 내는 작업.
- 대게, 실시간 그래픽스의 경우 Polygon Meshes 방법 사용.
- 삼각형 매쉬가 쉽게 쓰임.
- Mesh에 입혀질 텍스쳐를 만들어 냄.
Polygon Mesh
그래픽스에서 렌더링할 물체를 만들어내는 것 → 모델링
구는 어떻게 정의할까?
구의 중점과 반지름을 가지고 다음과 같은 음함수를 정의할 수 있을 것임.

하지만 GPU가 이러한 음함수를 처리하기에 적합하게 설계되지않았다고 한다.
따라서 이러한 표현대신 부드러운 표면의 점들을 샘플하게 되는데 그럼 일정한 개수의 꼭짓점, 정점들이 나오게됨. 조밀조밀하게 다각형으로 이어두면 그것이 Polygon Mesh임.
물론 GPU는 Polygon Mesh를 처리하는데 최적화되어있음.

Polygon 중에 가장 간단한 것이 Triangle이며
Triangle로만 구성된 Mesh를 Triangle Mesh라고 부름.
Triangle Mesh가 주어졌을 때, 대체로 꼭짓점 개수의 두배정도 되는 삼각형이 있음.
왜? -> 추후 오일러 공식 증명 예정...
실제 모델링 단계에서 사각형 Mesh를 쓰는 게 더 유리함
사각형을 삼각형으로 만드는 건 아주 간단함.

사각형이던 삼각형이던 정점의 개수를 어느정도로 할것인가가 중요함.
픽셀개수를 resolution(해상도)라고 하듯이 마찬가지로 Polygon Mesh의 정점의 개수를 해상도 or Level of Detail (LOD)라고 함.
Polygon Mesh가 부드러운 표면을 샘플해서 근사적으로 표현한 것이기 때문에 resolution이 높아질수록 당연히 원래 주어진 부드러운 표면에 가깝게 모델링 됨. 처리량은 많아지므로 트레이드 오프임.
화면에서 작게 나온다면 해상도를 높게 하지않아도 될것임.
해상도를 높이는 것은 Refinement
해상도를 줄이는 것은 Simplification라고 함.
이러한 LOD Control은 그래픽스의 중요한 주제 중 하나임.

Polygon Mesh가 주어졌을 때 컴퓨터에서 어떤식으로 표현이 될까?
아래 그림에서 2차원 Mesh에서 삼각형이 3개가 있고 삼각형은 각 세개의 정점으로 정의가 되어있다고 하자.
t1같은 경우 (0,0), (1,0), (0,1) 세 점을 가짐. 세점을 배열에 담아둠.
t2, t3도 마찬가지로 정점을 배열에 담고 3개씩 끊어서 읽으면 삼각형 정보를 얻을 수 있게됨.
이 정보를 나열한 공간을 vertex array라고 함.
하지만 지금은 중복된 데이터가 많은 상태임.
(1,0)이 세번 중복되므로 좋지않기 때문.

그렇다면 정점을 중복없이 나열하는 방법은?
vertex Array에는 존재하는 정점을 그대로 배정함.
해당 정점의 index를 활용하여 index Array의 정보를 통해 삼각형의 정점을 확인할 수 있게 됨.
실제 3차원 공간에서는 한 정점을 표현할 때 x,y,z 원소를 실수로 나타내야할 것이고 그 밖의 여러가지 정보가 들어가게 될 것이다. 따라서 vertex array의 데이터를 중복없이 2B, 4B정도의 메모리인 index 하나로 나타내는 것은 효율적이다.

그렇다면 x,y,z Position 정보 외에 들어가는 정보는 무엇이 있을까?
Surface Normals
Normal은 기하와 벡터 시간에 법선벡터로 알고 있었다
Polygon Mesh를 구성하는 각각의 삼각형마다 Normal을 계산하는 방법은?
P1, P2, P3 꼭짓점으로 이루어진 삼각형은 하나의 평면이고 평면에 수직인 것이 법선벡터다.
이것을 계산하는 방법은
우선 꼭짓점을 이어서 두 벡터를 정의한다.
P1 → P2 벡터 = V1
P1 → P3 벡터 = V2
두 벡터를 Cross Product를 수행한 값을 Unit Vector로 Normalization하여 구할 수 있다.
이때, 삼각형의 정점인 P1, P2, P3는 순서가 시계 반대방향으로 나열되어서 주어진 것을 볼 수 있음. Counter - Clockwise(CCW)

그런데 삼각형의 꼭짓점이 P1 P2 P3가 아니라 P1 P3 P2로 주어졌다고 해보자. 시계방향으로 주어진 것이다.
앞에서 보았던 원칙을 그대로 적용하면 Normal의 방향은 정반대가 된다. 물체 안쪽을 파고드는 Normal이 정의가 된다.
컴퓨터 그래픽스에서 Normal은 물체의 밖을 향하도록 하는 것이 기본적인 관례다.
따라서 시계방향이 아닌 반시계방향으로 정점을 나열해야한다.

더 중요한 것은 정점 Normal임.
Vertex Normals
삼각형과 달리 정점마다 Normal을 할당한다?
이는 직관적으로 와닿지않을 수 있다. 한 점에 할당될 수 있는 벡터는 무한하지 않나?
앞에서 원래 부드러운 물체가 있을때 표면을 샘플하여 얻어진 것이 Polygon mesh라고 배웠다. 어떤 꼭짓점이 하나 있다고 하면 원래 부드러운 평면의 점을 샘플한 것이다.
부드러운 평면에서는 tangent plane이라는 것을 수학적으로 정의할 수 있다.
이때 tangent plane의 수직인 벡터가 Normal이고 정점마다 할당할 수 있게 된다.
문제는 정점마다 Normal을 할당하기 위해서는 부드러운 곡면이 항상 필요할 것 같다고 느낄 수 있을 것이다. 하지만 각 정점은 여러개의 삼각형에 의해 공유되며 이 삼각형 Normal들을 계산하여 평균을 내는 방식으로 정점 Normal을 구할 수 있다.
Max와 같은 프로그램이 다 자동으로 해주는 부분이다.
지금까지 정점의 Position, Normal을 배웠다.
다시 말해 Vertex Normal도 마찬가지로 vertex Array에 포함되어야하는 정보다.


그래픽 디자이너가 캐릭터 Mesh를 만든다면 우리는 OpenGL ES로 렌더링하기 위해서 데이터를 끌어와야한다.
export와 import를 거쳐야할 것이다.
디자이너가 Max를 사용하였고 우리는 유니티를 사용한다고 가정하면, Max로 만든 Mesh를 파일의 형태로 export하고 파일을 읽어들이기 위해 import해야한다.
max같은 경우 max script라는 언어를 가지고 있다. 그것을 이용해 간단한 exporter를 짤 수 있다고도 한다. 신경 쓸 부분은 아니다.
만들어진 파일의 포맷은 다양하게 지원하지만 흔한 것은 obj파일이다.

간단한 구를 예시로 한 obj파일 구성은 다음과 같다.
구는 26개의 Vertex와 48개의 Triangle로 구성되었다.
v로 시작되는 줄이 나오는데 v는 vertex의 첫글자다. 그 뒤의 세개의 숫자는 x,y,z좌표이며 이러한 방식으로 정점 26개를 나열하게 된다.
다음으로 오는 Vn은 Vertex Normal을 나타낸다.
정점 Normal도 26개가 되어야할까? 구는 그렇겠지만 다른 position의 점이더라도 직육면체에서 같은 면의 Vertex들이라면 Vertex Normal이 같을 것이기 때문에 이러한 경우 Normal을 따로 저장하는 것이 아닌 하나만 저장하게 될 것이다.
다음으로 오는 f는 실제 면의 정보인 face를 나타낸다.
삼각형 Mesh라면 각 꼭짓점의 정보를 알려줘야한다.(vertex Position, vertex Normal)
max가 이러한 obj파일을 export한다면 유니티나 OpenGL에서 imort하게 되는데 이 안에서는 Vertex Array와 index Array가 형성이 될 것이다.

Vertex Array에 Position정보와 Normal정보를 할당한다.
obj 파일을 읽어나가면서 런타임 프로그램이 사용할 Vertex Array와 Index Array를 채워나가는 것이다.

참고
opengl es를 이용한 3차원 컴퓨터 그래픽스 입문
'Computer Graphics' 카테고리의 다른 글
컴퓨터 그래픽스 - Rasterizer(2), ViewPort (1) | 2024.01.16 |
---|---|
컴퓨터 그래픽스 - Rasterizer(1) (0) | 2024.01.13 |
컴퓨터 그래픽스(4) - World Transform (1) | 2024.01.10 |
컴퓨터 그래픽스(3) - Affine Transform (1) | 2024.01.07 |
컴퓨터 그래픽스(2) - Transform composition (0) | 2024.01.07 |
댓글