포스트

[ Opengl ] (solution) Obj File 임포트 구현

문제



기존 msh 파일만 읽어 오는 임포트 코드를 OBJ 파일을 읽어올 수 있게 코드 수정 시도

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# cube.obj
mtllib cube.mtl
o cube

v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 -0.500000

vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000

vn 0.000000 0.000000 1.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000

g cube
usemtl cube
s 1
f 1/1/1 2/2/1 3/3/1
f 3/3/1 2/2/1 4/4/1
s 2
f 3/1/2 4/2/2 5/3/2
f 5/3/2 4/2/2 6/4/2
s 3
f 5/4/3 6/3/3 7/2/3
f 7/2/3 6/3/3 8/1/3
s 4
f 7/1/4 8/2/4 1/3/4
f 1/3/4 8/2/4 2/4/4
s 5
f 2/1/5 8/2/5 4/3/5
f 4/3/5 8/2/5 6/4/5
s 6
f 7/1/6 1/2/6 5/3/6
f 5/3/6 1/2/6 3/4/6


obj 파일 파싱을 통한 임포트 수도 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

void Object::readOBJFile(char* pFileName)
{
	//읽을 목적의 파일 선언
	ifstream readFile(pFileName);
	
	//파일이 열렸는지 확인
	if (readFile.is_open())
	{
		//파일 끝까지 읽었는지 확인
		while (!readFile.eof())
		{
			readFile.getline(text, 256);
			line.push_back(text);
		}
		
		//한줄씩 읽어오기
		for (int i = 0; i < line.size(); i++)
		{
			if(문장이 'v'라면)
			{
				 번째 ->m_vertex[vertexNum][0];
				 번째 ->m_vertex[vertexNum][1];
				 번째 ->m_vertex[vertexNum][2];
				vertexNum++;
			}
			
			else if(문장이 'vt'라면)
			{
				 번째 ->m_texture[textureNum][0];
				 번째 ->m_texture[textureNum][1];
				 번째 ->m_texture[textureNum][2];
				textureNum++;
			}
			
			else if(문장이 'vn'라면)
			{
				 번째 ->m_vertexNormal[normalNum][0];
				 번째 ->m_vertexNormal[normalNum][1];
				 번째 ->m_vertexNormal[normalNum][2];
				normalNum++;
			}
			
			else if(문장이 'f'라면)
			{
				if('/'포함)
				{
					 번째 ->m_face[faceNum][0];
					 번째 ->m_face_texture[faceNum][0];
					 번째 ->m_face_normal[faceNum][0];
					
					 번째 ->m_face[faceNum][1];
					 번째 ->m_face_texture[faceNum][1];
					 번째 ->m_face_normal[faceNum][1];
					
					 번째 ->m_face[faceNum][2];
					 번째 ->m_face_texture[faceNum][2];
					 번째 ->m_face_normal[faceNum][2];
					faceNum++;
				}
			
				else
				{
					 번째 ->m_face[faceNum][0];
					 번째 ->m_face[faceNum][1];
					 번째 ->m_face[faceNum][2];
					faceNum++;
				}
			}
		}

	}
	readFile.close();
}




그러나 OBJ File Loader의 face 중 4개 이상의 vertex들을 가진 face의 경우 임포트 에러 발생, 구체 등의 물체는 하나의 face가 3개 이상을 가진 경우가 많으므로 코드 수정


해결


하나의 face를 여러 삼각형으로 나눈다.

코드 구현



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
void Object::readOBJFile(char* pFileName)
{
	//ifstream readFile("dodecahedron.txt");

	ifstream readFile(pFileName);
	int faceVertex[20];
	int UV;
	int nomal;
	char text[256];
	vector<string>line;



	if (readFile.is_open())
	{
		while (!readFile.eof())
		{
			readFile.getline(text, 256);
			line.push_back(text);
		}

		for (int i = 0; i < line.size(); i++)
		{
			if (line[i][0] == 'v' && line[i][1] == ' ')
			{
				sscanf_s(line[i].c_str(), "v %f %f %f", &m_vertex[m_nNumVertex][0], &m_vertex[m_nNumVertex][1], &m_vertex[m_nNumVertex][2]);
				m_nNumVertex++;
			}

			else if (line[i][0] == 'v' && line[i][1] == 't')
			{
				sscanf_s(line[i].c_str(), "vt %f %f", &m_uv[m_nNumTexture][0], &m_uv[m_nNumTexture][1]);
				m_nNumTexture++;
				haveUV = true;
			}

			else if (line[i][0] == 'v' && line[i][1] == 'n')
			{
				sscanf_s(line[i].c_str(), "vn %f %f %f", &m_vertexNormal[m_nNumNormal][0], &m_vertexNormal[m_nNumNormal][1], &m_vertexNormal[m_nNumNormal][2]);
				m_nNumNormal++;
				haveNormal = true;
			}

			else if (i < line.size() && line[i][0] == 'f')
			{
				int j = 0, numVertex = 0;

				for (; j < line[i].size(); j++)
				{
					if (line[i][j] == ' ')
					{
						numVertex++;
					}
				}

				if (line[i][j - 1] == ' ')
				{
					numVertex--;
				}

				m_face[m_nNumFace].m_nNumVertex = numVertex;
				int faceVerNum = 0, faceVerNorNum = 0, faceUVNum = 0;

				if (line[i][1] == ' ' && haveUV && haveNormal)
				{

					for (int j = 1; j < line[i].size(); j++)
					{
						if (line[i][j] == ' ') {
							sscanf_s(&line[i][j + 1], "%d/%d/%d", &faceVertex[faceVerNum], &m_uv, &m_faceNormal);
							faceVerNum++;
						}
					}
					for (int j = 0; j < m_face[m_nNumFace].m_nNumVertex; j++)
					{
						m_face[m_nNumFace].m_vertex[j] = faceVertex[j];
					}
				}

				else if (line[i][1] == ' ' && !haveUV && haveNormal)
				{
					for (int j = 1; j < line[i].size(); j++)
					{
						if (line[i][j] == ' ')
						{
							sscanf_s(&line[i][j + 1], "%d//%d", &faceVertex[faceVerNum], &m_faceNormal);
							faceVerNum++;
						}
					}
					for (int j = 0; j < m_face[m_nNumFace].m_nNumVertex; j++)
					{
						m_face[m_nNumFace].m_vertex[j] = faceVertex[j];
					}
				}

				else
				{
					for (int j = 1; j < line[i].size(); j++)
					{
						if (line[i][j] == ' ')
						{
							sscanf_s(&line[i][j + 1], "%d", &faceVertex[faceVerNum]);
							faceVerNum++;
						}
					}
					for (int j = 0; j < m_face[m_nNumFace].m_nNumVertex; j++)
					{
						m_face[m_nNumFace].m_vertex[j] = faceVertex[j];
					}
				}

				m_nNumFace++;
			}

		}

	}
	readFile.close();
}



이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.