C++

[Open GL] v/vt/vn 형식 OBJ 읽어오기

돼지표 2021. 12. 5. 01:47

온라인에서 쉽게 다운받을 수 있는 OBJ 파일의 f값들은 대게 v v v형식이 아니라 v/vt/vn 형식으로 이루어져있다. 그것도 3개의 v/vt/vn로 구성되어 있는 것이 아니라  v/vt/vn이 3개일수도 4개일수도 있다.

 

Butterfly.obj

일반적인 OBJ파일은 위와 같은 형태로 OBJ의 face들이 3개 또는 4개의 v/vt/vn 형태로 구성되어 있는데

각각 v = vertex의 인덱스, vt = 텍스쳐, vn = 노말 정점 인덱스로 구성되어 있으며

오늘 알아볼 내용은 v/vt/vn 중 v값만을 사용하여 OpenGL에서 OBJ파일을 읽는 방법에 대해 알아보자

 

while (fgets(line, 256, fp) != NULL) {
		if (line[0] == 'f') {
			string line_s(line);
			vector<string> data = split(line_s, ' ');
			if (data.size() == 5) {
				auto *v0 = vertices[stoi(split(data[1], '/')[0]) - 1];
				auto *v1 = vertices[stoi(split(data[2], '/')[0]) - 1];
				auto *v2 = vertices[stoi(split(data[3], '/')[0]) - 1];
				faces.push_back(new Face(index++, v0, v1, v2));
			}
			else if (data.size() == 6) {
				auto *v0 = vertices[stoi(split(data[1], '/')[0]) - 1];
				auto *v1 = vertices[stoi(split(data[2], '/')[0]) - 1];
				auto *v2 = vertices[stoi(split(data[3], '/')[0]) - 1];
				auto *v3 = vertices[stoi(split(data[4], '/')[0]) - 1];
				faces.push_back(new Face(index, v0, v1, v2));
				faces.push_back(new Face(index++, v0, v2, v3));
			}
		}
	}

코드는 간단하다. file을 한줄마다 읽어 line에 저장하고 맨 앞글자가 'f' 일시 해당 라인이 f 라는 것이니 string의 split을 이용하여 나누어 준뒤 data의 수가 5이면 f값이 3개이고 6이면 4개이니 개수에 맞추어 v값만 추출하여 저장하면 된다.

 

여기서 data.size()를 왜 5와 6으로 비교하는 이유는

f v/vt/vn v/vt/vn v/vt/vn를 공백(' ')을 기준으로 split 하면

f, v/vt/vn, v/vt/vn, v/vt/vn로 나누어져서 data.size()가 4가 된다고 생각할 것이다.

하지만 file을 읽을 때 fgets로 line을 읽으면 line의 문자열 마지막에 개행문자가 들어가게 된다.

따라서 f, v/vt/vn, v/vt/vn, v/vt/vn로 나누어지는게 아니라 f, v/vt/vn, v/vt/vn, v/vt/vn, \n이 되어서 

data.size() = 5 가 되는 것이다.

 

읽어온 Butterfly.obj

 

 

//2021-12-13

내용 추가

line[strlen(line) - 1] = '\0';

을 통해 읽어온 라인의 개행문자를 지우고 비교를 하는게 더욱 낫다.

Butterfly.obj 파일은 f 라인 끝에 공백이 있어 ' '로 split을 할때 개행문자가 나누져 size가 5, 또는 6으로 잡히지만

다른 obj파일은 f 라인끝에 공백이 없어 ' '로 split을 하면 개행문자가 data에 들어가지 않게 된다.

따라서 위에 언급한 코드를 통해 개행문자를 문자열에서 지워서 

size를 4또는 5로 비교하는 것이 올바르다.