[Open GL] v/vt/vn 형식 OBJ 읽어오기
온라인에서 쉽게 다운받을 수 있는 OBJ 파일의 f값들은 대게 v v v형식이 아니라 v/vt/vn 형식으로 이루어져있다. 그것도 3개의 v/vt/vn로 구성되어 있는 것이 아니라 v/vt/vn이 3개일수도 4개일수도 있다.
일반적인 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 가 되는 것이다.
//2021-12-13
내용 추가
line[strlen(line) - 1] = '\0';
을 통해 읽어온 라인의 개행문자를 지우고 비교를 하는게 더욱 낫다.
Butterfly.obj 파일은 f 라인 끝에 공백이 있어 ' '로 split을 할때 개행문자가 나누져 size가 5, 또는 6으로 잡히지만
다른 obj파일은 f 라인끝에 공백이 없어 ' '로 split을 하면 개행문자가 data에 들어가지 않게 된다.
따라서 위에 언급한 코드를 통해 개행문자를 문자열에서 지워서
size를 4또는 5로 비교하는 것이 올바르다.