obj 模型加载


obj 模型加载

wavefront obj

今天不想写数学了,来学习一下obj的文件格式。将来有机会在游戏引擎中构建自己的objloader

obj 文件格式

obj是文本,obj文件不需要文件头,obj可以使用#进行注释,每一行以关键字开头说明改行的数据的的含义,以 \符号 放在行末连接两行。

关键字

  1. v 几何体顶点
  2. vt 贴图坐标点
  3. vn 顶点法线
  4. f 面 数据为组成面的三个顶点 顶点索引/uv点索引/法线索引
  5. mtllib 指明存放材质库的文件
  6. usemtl 指明只用材质库中哪一个材质
  7. s 指定光滑组,在一个组内的所有面需要对其光照进行光滑处理
  8. o 对象名称 对一个大的模型可以使用 o 分解为几个不同的对象。

未完

mtl 文件格式

mtl时obj文件的附属文件,用来描述几何体的表面描影属性。

mtl文件包含多个材质,newmtl声明一个材质

  1. newmtl 声明一个材质
  2. Ka ambient color
  3. Kd diffuse color
  4. Ks specular color
  5. Ns 高光系数
  6. Ni 折射率
  7. d 融入背景的程度
  8. illum 指定材质的光照模型,如下
    1. 0 色彩开 阴影色关
    2. 1 色彩开,阴影色开
    3. 高光开
    4. 反射开,光纤追踪开
  9. map_Ka ambient color贴图
  10. map_Kd diffuse color贴图
  11. map_Ks specular color贴图
  12. map_d alpha通道纹理贴图
  13. map_bump 凹凸贴图

obj解析

虽然现在对obj文件中的许多属性的用途不很了解,但是了解其构成之后便可以实现解析了。于是我重新开始编写了游戏引擎,并在其中嵌入了自己的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
/*
解析模型数据,当前只支持obj

o myobject
v -0.5f, -0.5f, 0.0f,
v 0.5f, -0.5f, 0.0f,
v 0.0f, 0.5f, 0.0f
f 1 2 3

一个模型有好多个mesh。

model_parse解析模型并将结果传入到一个model对象中。 model对象是一个实体(物理存在),另有object对象可以复用model对象的数据。
*/


#pragma once
#include "../Global_config.h"
#include "../element/model.h"


class Model_parse
{
public:
size_t v_num=0;//顶点总数
size_t vt_num = 0;//顶点总数
size_t vn_num = 0;//顶点总数
void parse(const char* file_path);
void parse_obj();
void parse_mtl();

Model_parse(Model* model);

private:
Model* model;
std::string path;
std::string dir_path;
std::string file_name;
std::string file_postfix;

//跳到下一行
void skip_to_next_row(size_t& index, std::string* str);
void skip_white_char(size_t& index, std::string* str);
void parse_obj_token(size_t& index, std::string* str);
void parse_obj_token_o(size_t& index, std::string* str);//o 说明这一行的数据是一个mesh的name
void parse_obj_token_v(size_t& index, std::string* str);
void parse_obj_token_vt(size_t& index, std::string* str);
void parse_obj_token_vn(size_t& index, std::string* str);
void parse_obj_token_f(size_t& index, std::string* str);
void parse_obj_token_mtllib(size_t& index, std::string* str);
void parse_obj_token_usemtl(size_t& index, std::string* str);

void parse_mtl_token(size_t& index, std::string* str);
void parse_mtl_token_newmtl(size_t& index, std::string* str);
void parse_mtl_token_Ns(size_t& index, std::string* str);
void parse_mtl_token_Ka(size_t& index, std::string* str);
void parse_mtl_token_Kd(size_t& index, std::string* str);
void parse_mtl_token_Ks(size_t& index, std::string* str);
void parse_mtl_token_Ni(size_t& index, std::string* str);
void parse_mtl_token_d(size_t& index, std::string* str);
void parse_mtl_token_illum(size_t& index, std::string* str);
void parse_mtl_token_map_Ka(size_t& index, std::string* str);
void parse_mtl_token_map_Kd(size_t& index, std::string* str);
void parse_mtl_token_map_Ks(size_t& index, std::string* str);
void parse_mtl_token_map_d(size_t& index, std::string* str);
void parse_mtl_token_map_bump(size_t& index, std::string* str);
};
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
#include "model_parse.h"

Model_parse::Model_parse(Model* model)
{
this->model = model;
}

//解析总控程序
void Model_parse::parse(const char* file_path)
{
// C:/Users/admin/source/repos/CGE3D/CGE3D/code/glsl/shader.vert
//读入文件名,获取文件格式,获取文件目录路径。
if (!file_path)
{
std::cout << "error invalid file path" << std::endl;
}
std::string path(file_path);
this->path = path;
size_t last_backslash = path.rfind('/');
if (last_backslash == std::string::npos)
last_backslash = -1;
if (last_backslash != -1)
{
this->dir_path.assign(path, 0, last_backslash + 1);
}
int file_name_length = path.length() - last_backslash - 1;
this->file_name.assign(path, last_backslash + 1, file_name_length);
//std::cout << "file_name: " << this->file_name << std::endl;
size_t last_dot = this->file_name.find('.');
if (last_dot == std::string::npos || last_dot == 0 || this->file_name.length() == 1)
{
std::cout << "错误 不确定的文件格式: " << this->file_name << std::endl;
exit(EXIT_SUCCESS);
}
int postfix_length = file_name.length() - last_dot - 1;
this->file_postfix.assign(this->file_name, last_dot + 1, postfix_length);
//std::cout << "file_postfix: " << file_postfix << std::endl;
if (this->file_postfix.compare("obj") == 0)
{
this->parse_obj();
}
else
{
std::cout << "暂未支持的文件格式" << std::endl;
exit(EXIT_SUCCESS);
}

}
void Model_parse::parse_obj()
{
std::cout << "解析到这是一个obj文件,正在解析中" << std::endl;
double time = glfwGetTime();
std::ifstream ifile;
ifile.open(this->path, std::ios::beg);
char c;
std::string str;
size_t index = 0;
while ((c = ifile.get()) != EOF)
{
str.push_back(c);
}
//std::cout << "解析此串:\n" <<str<< std::endl;
while (index < str.length())
{
this->skip_white_char(index, &str);
this->parse_obj_token(index, &str);
}
std::cout << "obj解析完成 " << "耗时: " << glfwGetTime() - time << std::endl;
}

void Model_parse::parse_mtl()
{
std::cout << "解析mtl文件" << std::endl;
std::ifstream ifile;
ifile.open(this->model->mtl_path, std::ios::beg);
char c;
std::string str;
size_t index = 0;
while ((c = ifile.get()) != EOF)
{
str.push_back(c);
}
//std::cout << "mtl解析此串:\n" <<str<< std::endl;
while (index < str.length())
{
this->skip_white_char(index, &str);
this->parse_mtl_token(index, &str);
}
std::cout << "mtl解析完成" << std::endl;
}
// 跳过空白部分
// 解析 标识符 从而得知其后的数据是什么成分
// 将解析到的数据存放
// o v vt vn f

void Model_parse::skip_to_next_row(size_t& index, std::string* str)
{
char c;
while (index < str->size())
{
c = str->at(index);
if (c != '\n')
index++;
else
break;
}
//现在index指向换行符
index++;
}
//跳过空白符
void Model_parse::skip_white_char(size_t& index, std::string* str)
{
char c;
while (index < str->length())
{
c = str->at(index);
if (c == '\n' || c == '\t' || c == '\r' || c == ' ')
index++;
else
return;
}

}

//解析标识符 即一行的开始的字符串以此来认定是什么数据
void Model_parse::parse_obj_token(size_t& index, std::string* str)
{
//std::cout << "解析标识符" <<str->at(index)<< std::endl;
skip_white_char(index, str);
//从index开始比较1个字符
//前缀码
if (index >= str->length())
return;
//mtllib
else if (!str->compare(index, 6, "mtllib"))
{
index += 6;
this->skip_white_char(index, str);
this->parse_obj_token_mtllib(index, str);
}
//usemtl
else if (!str->compare(index, 6, "usemtl"))
{
index += 6;
this->skip_white_char(index, str);
this->parse_obj_token_usemtl(index, str);
}
// 顶点纹理坐标
else if (!str->compare(index, 2, "vt"))
{
index += 2;
this->skip_white_char(index, str);
this->parse_obj_token_vt(index, str);
}
//顶点法线
else if (!str->compare(index, 2, "vn"))
{
index += 2;
this->skip_white_char(index, str);
this->parse_obj_token_vn(index, str);
}
//object
else if (!str->compare(index, 1, "o"))
{
index++;
this->skip_white_char(index, str);
this->parse_obj_token_o(index, str);
}
// vertex 顶点坐标
else if (!(str->compare(index, 1, "v")))
{
index++;
this->skip_white_char(index, str);
this->parse_obj_token_v(index, str);
}
else if (!str->compare(index, 1, "f"))
{
index++;
this->skip_white_char(index, str);
this->parse_obj_token_f(index, str);
}
else if (!str->compare(index, 1, "#"))
{
skip_to_next_row(index, str);
}
else
{
if (index < str->length())
//std::cout << "obj 暂时无法解析" << str->at(index) << std::endl;
skip_to_next_row(index, str);
return;
}
}

//o 说明这一行的数据是一个mesh的name
void Model_parse::parse_obj_token_o(size_t& index, std::string* str)
{
//解析出一个 mesh 放入model中
int a = this->model->meshes.size();
if (a > 0)
{
this->v_num = this->v_num + this->model->meshes.at(a - 1)->v_num;
this->vt_num = this->vt_num + this->model->meshes.at(a - 1)->vt_num;
this->vn_num = this->vn_num + this->model->meshes.at(a - 1)->vn_num;
}
else
{
this->v_num = 0;
this->vt_num = 0;
this->vn_num = 0;
}
Mesh* mesh = new Mesh();
this->model->meshes.push_back(mesh);
//解析mesh的名字
size_t name_index = index;
char c;
while (name_index < str->length())
{
c = str->at(name_index);
if (c == '\n' || c == '\t' || c == '\r' || c == ' ')
break;
name_index++;
}
name_index--;
size_t name_length = name_index - index + 1;
mesh->name.assign(*str, index, name_length);
index = name_index + 1;
//std::cout << "解析出一个mesh:" << mesh->name << std::endl;
}


//解析顶点坐标
void Model_parse::parse_obj_token_v(size_t& index, std::string* str)
{
//std::cout << "获取顶点坐标" << std::endl;
//获取当前mesh
Mesh* mesh = this->model->meshes.at(this->model->meshes.size() - 1);
mesh->v_num++;
char* end;
CM::vecf3 res;
//for (int i = 1; i <= 1; i++)
{
skip_white_char(index, str);
res.x = strtod(str->c_str() + index, &end);
index = end - str->c_str();
skip_white_char(index, str);
res.y = strtod(str->c_str() + index, &end);
index = end - str->c_str();
skip_white_char(index, str);
res.z = strtod(str->c_str() + index, &end);
index = end - str->c_str();
}
mesh->vertex_coord.push_back(res);
}
//vt
void Model_parse::parse_obj_token_vt(size_t& index, std::string* str)
{
//std::cout << "获取顶点纹理坐标" << std::endl;
//获取当前mesh
Mesh* mesh = this->model->meshes.at(this->model->meshes.size() - 1);
mesh->vt_num++;
char* end;
CM::vecf2 res;
//for (int i = 1; i <= 1; i++)
{
skip_white_char(index, str);
res.x = strtod(str->c_str() + index, &end);
index = end - str->c_str();
skip_white_char(index, str);
res.y = strtod(str->c_str() + index, &end);
index = end - str->c_str();
}
mesh->vertex_texture.push_back(res);
}
//vn
void Model_parse::parse_obj_token_vn(size_t& index, std::string* str)
{
//std::cout << "获取顶点法线坐标" << std::endl;
//获取当前mesh
Mesh* mesh = this->model->meshes.at(this->model->meshes.size() - 1);
mesh->vn_num++;
char* end;
CM::vecf3 res;
//for (int i = 1; i <= 1; i++)
{
skip_white_char(index, str);
res.x = strtod(str->c_str() + index, &end);
index = end - str->c_str();
skip_white_char(index, str);
res.y = strtod(str->c_str() + index, &end);
index = end - str->c_str();
skip_white_char(index, str);
res.z = strtod(str->c_str() + index, &end);
index = end - str->c_str();
}
mesh->vertex_normal.push_back(res);
}
void Model_parse::parse_obj_token_f(size_t& index, std::string* str)
{
CM::length(CM::vecf3(1));
//obj中的索引是从1开始的,所以要进行减一处理
//std::cout << "获取索引(面)" << std::endl;
//获取当前mesh
Mesh* mesh = this->model->meshes.at(this->model->meshes.size() - 1);
mesh->face_num++;
char* end;
unsigned int res;
std::vector<unsigned int> ver_i;
std::vector<unsigned int> ver_t_i;
std::vector<unsigned int> ver_n_i;
for (int i = 1; i <= 3; i++)
{
//v
skip_white_char(index, str);
res = strtod(str->c_str() + index, &end) - 1 - this->v_num;
ver_i.push_back(res);
index = end - str->c_str();
//如果不是斜杠,说明没有纹理坐标,则略过
if (index >= str->size())
{
mesh->has_tex_coord = false;
break;
}
if (str->at(index) != '/')
{
mesh->has_tex_coord = false;
continue;
}
mesh->has_tex_coord = true;
index++;//略过下一个斜杠
//vt
res = strtod(str->c_str() + index, &end) - 1 - this->vt_num;
ver_t_i.push_back(res);
index = end - str->c_str();
//检查是否超限
if (index >= str->size())
{
mesh->has_normal = false;
break;
}
//如果不是斜杠,说明没有法向量 则略过
if (str->at(index) != '/')
{
mesh->has_normal = false;
continue;
}
mesh->has_normal = true;
index++;//略过下一个斜杠
//vn
res = strtod(str->c_str() + index, &end) - 1 - this->vn_num;
ver_n_i.push_back(res);
index = end - str->c_str();
}
//将vector转化为veci3
CM::veci3 temp;
temp.x = ver_i.at(0);
temp.y = ver_i.at(1);
temp.z = ver_i.at(2);
mesh->vertex_index.push_back(temp);
if (mesh->has_tex_coord)
{
temp.x = ver_t_i.at(0);
temp.y = ver_t_i.at(1);
temp.z = ver_t_i.at(2);
}
else
{
temp.x = 0;
temp.y = 0;
temp.z = 0;
}
mesh->vertex_texture_index.push_back(temp);

if (mesh->has_normal)
{
temp.x = ver_n_i.at(0);
temp.y = ver_n_i.at(1);
temp.z = ver_n_i.at(2);
}
else
{
temp.x = 0;
temp.y = 0;
temp.z = 0;
}
mesh->vertex_normal_index.push_back(temp);
}

void Model_parse::parse_obj_token_mtllib(size_t& index, std::string* str)
{
//解析出一个 mtl路径 放入model中
//解析mtl的名字
//std::cout << "获取mtllib" << std::endl;
std::string mtl_name;
size_t name_index = index;
char c;
while (name_index < str->length())
{
c = str->at(name_index);
if (c == '\n' || c == '\t' || c == '\r' || c == ' ')
break;
name_index++;
}
//name_index--;
size_t name_length = name_index - index;
mtl_name.assign(*str, index, name_length);
index = name_index;
//生成mtl的路径
this->model->mtl_path = this->dir_path + mtl_name;
//std::cout << "解析出一个mtl:" << this->model->mtl_path << std::endl;
//解析该mtl库 mtllib - mtles 之于 model - meshes
this->model->mtllib = new Mtllib();
this->model->mtllib->mtl_path = this->model->mtl_path;
this->parse_mtl();
}
void Model_parse::parse_obj_token_usemtl(size_t& index, std::string* str)
{
//std::cout << "获取 usemtl" << std::endl;
//获取当前mesh
Mesh* mesh = this->model->meshes.at(this->model->meshes.size() - 1);
size_t name_index = index;
size_t name_length = 0;
char c;
while (name_index < str->length())
{
c = str->at(name_index);
if (c == '\n' || c == '\t' || c == '\r' || c == ' ')
break;
name_index++;
}
name_length = name_index - index;
mesh->usemtl.assign(*str, index, name_length);
index = name_index;
//std::cout << "解析出一个usemtl:" << mesh->usemtl << std::endl;
//由于mtl文件早已解析完成,这里只需要进行寻找并装配即可
if (this->model->mtllib)
{
for (unsigned int i = 0; i <= this->model->mtllib->mtls.size() - 1; i++)
{
if (mesh->usemtl.compare(this->model->mtllib->mtls.at(i)->name) == 0)
{
mesh->attach_mtl(this->model->mtllib->mtls.at(i));
//std::cout << "usemtl已成功attach" << mesh->usemtl << std::endl;
return;
}
}
}
std::cout << "usemtl错误,没有此mtl" << mesh->usemtl << std::endl;
}

void Model_parse::parse_mtl_token(size_t& index, std::string* str)
{
//std::cout << "解析标识符" <<str->at(index)<< std::endl;
skip_white_char(index, str);
if (index >= str->length())
return;
//newmtl
else if (!str->compare(index, 6, "newmtl"))
{
index += 6;
this->skip_white_char(index, str);
this->parse_mtl_token_newmtl(index, str);
}
//map_Ka
else if (!str->compare(index, 6, "map_Ka"))
{
index += 6;
this->skip_white_char(index, str);
this->parse_mtl_token_map_Ka(index, str);
}
//map_Kd
else if (!str->compare(index, 6, "map_Kd"))
{
index += 6;
this->skip_white_char(index, str);
this->parse_mtl_token_map_Kd(index, str);
}
//map_Ks
else if (!str->compare(index, 6, "map_Ks"))
{
index += 6;
this->skip_white_char(index, str);
this->parse_mtl_token_map_Ks(index, str);
}
else if (!str->compare(index, 1, "#"))
{
//std::cout << "注释" << str->at(index) << std::endl;
skip_to_next_row(index, str);
}
else
{
if (index < str->length())
//std::cout << "mtl 暂时无法解析,略过此行" << str->at(index) << std::endl;
skip_to_next_row(index, str);
return;
}
}
void Model_parse::parse_mtl_token_newmtl(size_t& index, std::string* str)
{
//std::cout << "parse_mtl_token_newmtl" << std::endl;
skip_white_char(index, str);
//解析出名字,新生成一个mtl放入model->mtllib中
Mtl* new_mtl = new Mtl();
std::string mtl_name;
size_t name_index = index;
char c;
while (name_index < str->length())
{
c = str->at(name_index);
if (c == '\n' || c == '\r' || c == '\t' || c == ' ')
break;
name_index++;
}
size_t name_length = name_index - index;
mtl_name.assign(*str, index, name_length);
index = name_index;
new_mtl->name = mtl_name;
this->model->mtllib->mtls.push_back(new_mtl);
//std::cout << "解析出一个新的mtl:"<< new_mtl->name << std::endl;
}
void Model_parse::parse_mtl_token_Ns(size_t& index, std::string* str)
{

}
void Model_parse::parse_mtl_token_Ka(size_t& index, std::string* str)
{

}
void Model_parse::parse_mtl_token_Kd(size_t& index, std::string* str)
{

}
void Model_parse::parse_mtl_token_Ks(size_t& index, std::string* str)
{

}
void Model_parse::parse_mtl_token_Ni(size_t& index, std::string* str)
{

}
void Model_parse::parse_mtl_token_d(size_t& index, std::string* str)
{

}
void Model_parse::parse_mtl_token_illum(size_t& index, std::string* str)
{

}
void Model_parse::parse_mtl_token_map_Ka(size_t& index, std::string* str)
{
//ambient
//解析参数,即目标文件名,由目标文件生成一个纹理并放入当前的mtl中
//std::cout << "获取 ambient Ka" << std::endl;
//获取当前的mtl
Mtl* cur_mtl = this->model->mtllib->mtls.at(this->model->mtllib->mtls.size() - 1);
skip_white_char(index, str);
std::string file_name;
size_t name_index = index;
char c;
while (name_index < str->length())
{
c = str->at(name_index);
if (c == '\n' || c == '\r' || c == '\t' || c == ' ')
break;
name_index++;
}
size_t name_length = name_index - index;
file_name.assign(*str, index, name_length);
index = name_index;
std::string file_path = this->dir_path + file_name;
Texture* new_tex = new Texture(file_path.c_str());
new_tex->texture_type = TEXTURE_TYPE_AMBIENT;
cur_mtl->texes.push_back(new_tex);
//std::cout << "获取 ambient KA 成功 path: " << file_path << std::endl;
}
void Model_parse::parse_mtl_token_map_Kd(size_t& index, std::string* str)
{
//diffuse
//解析参数,即目标文件名,由目标文件生成一个纹理并放入当前的mtl中
//std::cout << "获取 diffuse Kd" << std::endl;
//获取当前的mtl
Mtl* cur_mtl = this->model->mtllib->mtls.at(this->model->mtllib->mtls.size() - 1);
skip_white_char(index, str);
std::string file_name;
size_t name_index = index;
char c;
while (name_index < str->length())
{
c = str->at(name_index);
if (c == '\n' || c == '\r' || c == '\t' || c == ' ')
break;
name_index++;
}
size_t name_length = name_index - index;
file_name.assign(*str, index, name_length);
index = name_index;
std::string file_path = this->dir_path + file_name;
Texture* new_tex = new Texture(file_path.c_str());
new_tex->texture_type = TEXTURE_TYPE_DIFFUSE;
cur_mtl->texes.push_back(new_tex);
//std::cout << "获取 diffuse Kd 成功 path: "<< file_path << std::endl;
}
void Model_parse::parse_mtl_token_map_Ks(size_t& index, std::string* str)
{
//specular
//std::cout << "获取 specular Ks" << std::endl;
//获取当前的mtl
Mtl* cur_mtl = this->model->mtllib->mtls.at(this->model->mtllib->mtls.size() - 1);
skip_white_char(index, str);
std::string file_name;
size_t name_index = index;
char c;
while (name_index < str->length())
{
c = str->at(name_index);
if (c == '\n' || c == '\r' || c == '\t' || c == ' ')
break;
name_index++;
}
size_t name_length = name_index - index;
file_name.assign(*str, index, name_length);
index = name_index;
std::string file_path = this->dir_path + file_name;
Texture* new_tex = new Texture(file_path.c_str());
new_tex->texture_type = TEXTURE_TYPE_SPECULAR;
cur_mtl->texes.push_back(new_tex);
//std::cout << "获取 specular Ks 成功 path: " << file_path << std::endl;
}
void Model_parse::parse_mtl_token_map_d(size_t& index, std::string* str)
{

}
void Model_parse::parse_mtl_token_map_bump(size_t& index, std::string* str)
{

}

只是将可以用到的属性进行了解析,但是这就已经说明可以实现自己编写obj解析器。事实证明,这个解析器解析那一个纳米套装的模型只需要0.6秒钟。好快呀。


文章作者: 崔文耀
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 崔文耀 !
  目录