2019년 5월 6일 월요일

3D Model Loading

버텍스, UV, 인덱스 정보를 담고있는 3D Model을 로드하여 화면에 그리고자 한다.
OBJ파일을 읽고 분류하여 데이터화 한다.

먼저, OBJ 파일을 자바의 FileReader 객체를 이용하여 Load하고, Line by Line으로 처리한다.


OBJ 파일로 3D Model Loading을 하기 위해서, Vertex, Texture(UV), Normal, Index 배열을 만든다. List를 사용하여 데이터를 구성하고 추후 Array 형태로 리턴한다.


OBJ 파일은 데이터가 Line 별로 구분되어 있으며, 각 라인의 Header에 따라 데이터를 분류할 수 있다. 각 라인의 데이터는 공백 문자로 구분되어 있으므로, 공백 문자로 Split하여 배열로 만든다.

v로 시작하는 라인은 Vertex 데이터로써, 3개의 좌표값으로 구성되어 있고 각각 x, y, z를 나타낸다.
vt는 Texture(UV)로써, 2개의 좌표값으로 구성되어 있고 각각 텍스쳐의 x, y 좌표를 나타낸다.
vn으로 시작하는 라인은 Normal 데이터로써, 3개의 좌표값으로 구성되어 있고 각각 x, y, z를 나타낸다. 각 버텍스에서의 법선 벡터를 나타낸다. 법선 데이터가 없어도 렌더링이 가능하지만, Light를 사용하는 경우 빛의 자연스러운 반사를 위해 법선 데이터가 필요하다.
f는 Face로, (v/vt/vn)의 순으로 위의 데이터의 Index를 나타낸다. Face 데이터의 경우 아래에서 분리하여 처리하기 위해 배열을 만들고 다음으로 넘긴다.



Face 데이터 또한 Space를 구분자로 사용하여 배열로 만든다.
각각의 배열은 면을 구성하는 3개의 버텍스에 대한 v, vt, vn의 인덱스를 담고 있으며, (v/vt/vn) 형태로 이루어져 있으므로 추가적으로 Slash를 구분자로 사용하여 다시 한번 배열로 분리한다.
분리한 버텍스 데이터는 processVertex() 함수를 호출하여 처리한다.



processVertex() 함수에서는 파싱한 버텍스 인덱스 데이터와 List, Array의 레퍼런스를 파라미터로 받는다.
버텍스의 인덱스 데이터는 (버텍스 인덱스, 텍스쳐 인덱스, 법선 인덱스) 순으로 전달된다.



처리할 버텍스 인덱스를 currentVertexPointer 변수에 저장한다. OBJ 파일에서의 인덱스는 1에서부터 시작하므로, 0부터 시작하는 기존 시스템에 적용하기 위해 인덱스 데이터에서 1을 뺀다. 버텍스 인덱스는 Indices List에 넣는다.


Texture(UV)를 처리할 차례이다. OBJ 파일에서 UV 값들을 파싱하여 추가했던 Textures List에서 인덱스 값을 활용하여 UV 데이터를 읽고 Vector2f 변수로 저장한다.
저장한 변수는 텍스쳐 배열에 저장하며, Serialize하게 저장하기 위해 버텍스 인덱스 포인터에 2를 곱한 위치에 x 값을, 이로부터 1 증가한 위치에 y값을 저장한다.

이 때, 1에서 y 값을 뺀 수를 배열에 저장하는데, 이는 3D Object를 만든 Blender에서 사용하는 좌표계와 OpenGL에서 사용하는 좌표계가 다르기에 이를 보정하기 위해 필요한 과정이다.
Blender는 일반적인 좌표계인 Bottom-Left 부터 시작하며 1사분면 영역으로 생각할 수 있다. OpenGL은 Top-Left 부터 시작하며, 4사분면 영역으로 생각할 수 있다. 위 좌표계는 x축 대칭이다.


위와 동일하게, 법선 데이터를 처리한다.


다시 loadObjModel() 함수로 돌아와서, 남은 Vertex, Index 배열에 데이터를 담는 작업을 진행한다. 아래와 같이 배열을 선언하고, List를 읽어 배열로 전환하여 저장한다.
배열로 전환이 완료되면 Loader의 loadToVao() 함수를 호출하여 VAO에 저장한다.

기존의 Static 데이터를 제거하고, 위에서 만든 loadObjMode()함수를 호출하여, OBJ 파일을 RawModel 객체로 변환한다. 텍스쳐를 로딩하고 Entity 객체로 만든다. Entity의 위치를 조정하고, 매 Loop 마다 Rotation의 y 값을 증가하여 y축 회전하도록 한다.

댓글 없음:

댓글 쓰기