■ Object Viewer 구현하기 (1)
안녕하세요.
오늘은 지난시간까지 배운 내용을 바탕으로 간단한 viewer를 함께 구현해봅시다 ㅎㅎ
obj viewer라고 하니 뭔가 어려워보일수도 있는데요.
전혀 새로운 것이 아닌 매우 간단한 프로그램입니다.
object파일 형식으로 된 obj파일을 입력받아 view해주는 간단한 프로그램이에요.
이번 포스팅은 2번에 나뉘어 진행하고자 합니다.
첫 번째는 obj란 무엇인지와 프로그램의 목차, 그리고 view하는 것에 대한 것이고요.
두 번째는 viewer에 띄운 오브젝트를 좀 더 이쁘게(?) 만드는 것에 대한 내용입니다
그럼 함께 시작해보겠습니다.
1. Obj File Format이란
obj는 가장 오래되고, 기본적으로 사용되는 3차원 모델 표현 파일입니다.
이는 3차원 오브젝트의 좌표를 기록하고, 각 점의 정보를 가지고 있습니다.
앞서 우리가 코드 내에 직접 입력했던 좌표 및 정보를 가지고 있는 하나의
파일이라고 생각하시면됩니다.
유명하고 잘 만들어진 obj파일은 인터넷에서 쉽게 구할 수 있어요.
그렇기때문에 obj파일을 이용한다면 여러 객체에 우리가 만든 효과를 적용시켜 볼 수
있다는 장점이 있습니다.
특히, 3D Max등으로 직접 제작한 객체를 obj file로 export할 수도 있어요.
그렇기 때문에 obj viewer가 있다면, 이러한 모든 객체를 볼 수가 있죠
예를 들어 cube.obj파일을 한 번 볼까요. cube.obj는 다음과 같이 생겼습니다.
여기서 V는 vertex를 의미합니다. 각 v의 순서대로 x,y,z 좌표 값을 뜻합니다.
f는 face(면 = 삼각형)을 의미합니다. 각 순서대로 삼각형을 구성하는 인덱스입니다.
즉, f 1 7 5 는 1번째, 7번째, 5번째 vertex로 구성된 삼각형을 의미합니다.
마찬가지로 다른 obj객체들도 이러한 방식으로 구성되어 있습니다.
2. Obj File 읽기
그렇다면 이러한 Obj 파일을 어떻게 읽어서 우리 프로그램에 보이게 할 수 있을까요
간단한 단 3가지 단계를 거치면, 우리의 화면에서 원하는 객체를 볼 수 있습니다.
1. 전체 vertex 갯수 및 삼각형 갯수를 Count
2. 해당 Count만큼 메모리 할당
3. 할당된 메모리에 각 vertex 및 face정보 입력
매우 간단한 3단계이죠? 이렇게 하면 바로 view가 완성됩니다.
그럼 각 단계별로 간단하게 코드를 살펴보겠습니다.
1. 전체 vertex 갯수 및 삼각형 갯수를 count
char count[100]; int vertexNum = 0; int faceNum = 0; while (!feof (s)) { fscanf (s, "%s", count); if (count[0] == 'v' && count[1] =='\0') vertexNum += 1; else if (count[0] == 'f' && count[1] =='\0') faceNum += 1; memset(count, '\0', sizeof (count)); } |
간단하죠? 파일이 끝날때까지 while문을 돌면서 한 줄씩 scanf합니다.
그리고 맨 앞이 v일 경우 vertexNum, f일 경우 faceNum에 count합니다.
그리고 다음줄로 넘어갈 때 배열은 매번 초기화를 합니다.
한 번의 while문이 모두 수행된 후에는 두 번째 단계로 넘어갑니다.
2. 해당 Count만큼 메모리 할당
vec4 *vertex; vec4 *face; vertex = (vec4 *)malloc (sizeof (vec4) * vertexNum); face = (vec4 *)malloc (sizeof (vec4) * faceNum); |
첫 번째 과정보다 더 간단합니다.
첫 번째 과정에서 count한 만큼 메모리를 동적할당 해줍니다.
3. 할당된 메모리에 각 vertex 및 face정보 입력
while (!feof (s)) { fscanf (s, "%s", bind); if (bind[0] == 'v' && bind[1] == '\0') { fscanf (s, "%f %f %f", &vertex[vertIndex].x, &vertex[vertIndex].y, &vertex[vertIndex].z); if(vertex[vertIndex].x > maxX) maxX=vertex[vertIndex].x; if(vertex[vertIndex].y > maxY) maxY=vertex[vertIndex].y; if(vertex[vertIndex].z > maxZ) maxZ=vertex[vertIndex].z; if(vertex[vertIndex].x < minX) minX=vertex[vertIndex].x; if(vertex[vertIndex].y < minY) minY=vertex[vertIndex].y; if(vertex[vertIndex].z < minZ) minZ=vertex[vertIndex].z; sumX += vertex[vertIndex].x; sumY += vertex[vertIndex].y; sumZ += vertex[vertIndex].z; vertIndex ++; } else if (bind[0] == 'f' && bind[1] == '\0') { fscanf (s, "%f %f %f", &face[faceIndex].x, &face[faceIndex].y, &face[faceIndex].z); faceIndex ++; } avgX = sumX / vertexNum; avgY = sumY / vertexNum; avgZ = sumZ / vertexNum;
scaleX = (1.0-maxX)*10 + 1; scaleY = (1.0-maxY)*10 + 1; scaleZ = (1.0-maxZ)*10 + 1; if(scaleX > scaleY) { if(scaleY > scaleZ) scaleAll = scaleZ; else scaleAll = scaleY; } else if(scaleX <scaleY) { if(scaleX < scaleZ) scaleAll = scaleX; else scaleAll = scaleZ; } } |
세 번째 과정은 좀 복잡해보이나요?
하지만 핵심은 검정색으로 굵게 표기된 부분입니다.
나머지는 좀 더 이쁘게하기 위한 작업들이죠!
색깔별로 설명해보겠습니다.
■ 검정색
먼저 1, 2단계를 통해 메모리 할당까지 완료하였습니다.
이제 단순히 할당된 메모리에 값을 입력하는 것입니다. 단순히 조건문을 통해 값을 입력!
v이면 vertex에 f이면 face에 해당 x,y,z 값을 fscanf를 해줍니다.
■ 초록색
초록색 부분은 뒤에 파란색, 노란색 부분의 코드를 처리하기 위한 부분이라고 생각하세요
간단하게 최대, 최소를 구하고 전체 x,y,z의 합을 구하는 부분입니다.
어떻게 사용되는지는 아래에서 설명할게요.
■ 파란색
파란색 부분은 위에서 구한 sumX, sumY, sumZ를 바탕으로 각 평균값을 구합니다.
이 평균 값은 어디서 사용할까요? 바로 객체의 Position을 정하는데 사용됩니다
obj파일을 통해 읽어오는 각 객체는 크기도 다르고 모양도 다르고 다 다릅니다.
그렇기에 객체를 최대한 화면의 중앙에 위치시키기 위해서 위의 값을 사용합니다.
mat4 translateCenter = Translate(-avgX, -avgY, -avgZ);
위와 같은 형식으로 사용됩니다.
■ 노란색
마지막 노란색 부분입니다. 노란색 부분은 객체의 크기를 조절하는데 사용됩니다.
위에서 설명한 바와 같이 어떤 객체는 너무 크고, 어떤 객체는 너무 작아요.
그렇기 때문에 모든 객체가 적당히 한 화면에 뿌려지도록 스케일링을 해줍니다.
scaleX, scaleY, scaleZ 값을 각각 구하고, 가장 작은 값으로 모두 scale해줍니다.
이렇게 obj파일의 로드가 모두 끝났습니다.
위에서 로드한 정보를 활용해 단순히 view하면 모든 객체를 볼 수 있습니다.
다음 포스팅에서는 이렇게 띄운 객체를 더욱 이쁘게 바꾸어 보겠습니다.
지금까지 포스팅한 내용을 바탕으로 조면 및 surface 등등을 조정해볼까합니다.
그럼 이만 오늘은 포스팅을 마칠게요. 긴 글 읽어주셔서 감사합니다.
'OpenGL' 카테고리의 다른 글
[OpenGL-11] object Viewer 구현하기 (3) (0) | 2017.05.27 |
---|---|
[OpenGL-10] object viewer 구현하기 (2) (0) | 2017.05.17 |
[OpenGL-8] Lighting (0) | 2017.03.16 |
[OpenGL-7] Projection Matix (0) | 2016.12.31 |
[OpenGL-6] Model View Matrix (2) | 2016.11.13 |