1. tiny_obj_loader.h 的使用
include这个头文件需要先定义一个宏

#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"
1
2
2. tiny_obj_loader.h 中数据结构的介绍
2.1 attrib_t
// Vertex attributes
typedef struct {
std::vector<real_t> vertices; // 'v'
std::vector<real_t> normals; // 'vn'
std::vector<real_t> texcoords; // 'vt'
std::vector<real_t> colors; // extension: vertex colors
} attrib_t;
1
2
3
4
5
6
7
attrib_t 主要存放的就是 OBJ文件中所有的顶点数据信息. 比如:

vertices : 顶点位置信息
normals : 法线信息
texcoords : 纹理坐标信息
colors : 颜色信息
2.2 shape_t
typedef struct {
std::string name;
mesh_t mesh;
path_t path;
} shape_t;
1
2
3
4
5
shape_t 表示的是比如这个物体的一个部分.
在 OBJ文件中, 如 o xxx 表示一个部分的开始.主要存储的信息有:

name : 这部分的名称 xxx
mesh : 构成这个部分的顶点信息. 这里通过使用索引的方式来记录 . 因为所有的数据信息都放在了 attrib_t 中.
path : pairs of indices for lines 按注释的意思是 线段的索引. 可能有问题. 因为没有用到这个.
在这里重点在于 mesh_t 这个数据结构:

// Index struct to support different indices for vtx/normal/texcoord.
// -1 means not used.
typedef struct {
int vertex_index;
int normal_index;
int texcoord_index;
} index_t;

typedef struct {
std::vector<index_t> indices;
std::vector<unsigned char> num_face_vertices; // The number of vertices per
// face. 3 = polygon, 4 = quad,
// ... Up to 255.
std::vector<int> material_ids; // per-face material ID
std::vector<unsigned int> smoothing_group_ids; // per-face smoothing group
// ID(0 = off. positive value
// = group id)
std::vector<tag_t> tags; // SubD tag
} mesh_t;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
索引信息重要放在 std::vector<index_t> indices; 中.
index_t 中是哪些数据信息的索引下标呢:

vertices : 顶点位置信息
normals : 法线信息
texcoords : 纹理坐标信息
3. 通过 tiny_obj_loader.h 读取并存储数据
主要参考了 loader_example.cc 的 PrintInfo(attrib, shapes, materials) 这个函数
bool Object::make_mesh_and_material_by_obj(const char* filename, const char* basepath,bool triangulate){

std::cout << "Loading " << filename << std::endl;

tinyobj::attrib_t attrib; // 所有的数据放在这里
std::vector<tinyobj::shape_t> shapes;
// 一个shape,表示一个部分,
// 其中主要存的是索引坐标 mesh_t类,
// 放在indices中
/*
// -1 means not used.
typedef struct {
int vertex_index;
int normal_index;
int texcoord_index;
} index_t;
*/
std::vector<tinyobj::material_t> materials;

std::string warn;
std::string err;

bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename,
basepath, triangulate);

// 接下里就是从上面的属性中取值了
if (!warn.empty()) {
std::cout << "WARN: " << warn << std::endl;
}

if (!err.empty()) {
std::cerr << "ERR: " << err << std::endl;
}

if (!ret) {
printf("Failed to load/parse .obj.\n");
return false;
}

// ========================== 将读入的模型数据存入自己定义的数据结构中 ========================

std::cout << "# of vertices : " << (attrib.vertices.size() / 3) << std::endl;
std::cout << "# of normals : " << (attrib.normals.size() / 3) << std::endl;
std::cout << "# of texcoords : " << (attrib.texcoords.size() / 2)
<< std::endl;

std::cout << "# of shapes : " << shapes.size() << std::endl;
std::cout << "# of materials : " << materials.size() << std::endl;

///1. 获取各种材质和纹理
{
for (int i = 0; i < materials.size(); i++) {
Material* m = new Material();
tinyobj::material_t tm = materials[i];
string name = tm.name;
if (name.size()) {
m->name = name;
}
m->ambient.r = tm.ambient[0];
m->ambient.g = tm.ambient[1];
m->ambient.b = tm.ambient[2];

m->diffuse.r = tm.diffuse[0];
m->diffuse.g = tm.diffuse[1];
m->diffuse.b = tm.diffuse[2];

m->specular.r = tm.specular[0];
m->specular.g = tm.specular[1];
m->specular.b = tm.specular[2];

m->transmittance.r = tm.transmittance[0];
m->transmittance.g = tm.transmittance[1];
m->transmittance.b = tm.transmittance[2];

m->emission.r = tm.emission[0];
m->emission.g = tm.emission[1];
m->emission.b = tm.emission[2];

m->shininess = tm.shininess;
m->ior = tm.ior;
m->dissolve = tm.dissolve;
m->illum = tm.illum;
m->pad0 = tm.pad0;

m->ambient_tex_id = -1;
m->diffuse_tex_id = -1;
m->specular_tex_id = -1;
m->specular_highlight_tex_id = -1;
m->bump_tex_id = -1;
m->displacement_tex_id = -1;
m->alpha_tex_id = -1;

m->ambient_texname = "";
m->diffuse_texname = "";
m->specular_texname = "";
m->specular_highlight_texname = "";
m->bump_texname = "";
m->displacement_texname = "";
m->alpha_texname = "";

if (tm.ambient_texname.size()) {

}
if (tm.diffuse_texname.size()) {

}
if (tm.specular_texname.size()) {

}
if (tm.specular_highlight_texname.size()) {

}
if (tm.bump_texname.size()) {

}
if (tm.displacement_texname.size()) {
}
if (tm.alpha_texname.size()) {

}

this->materials.push_back(m);
}

}

/// 2.顶点数据
{
// For each shape 遍历每一个部分
for (size_t i = 0; i < shapes.size(); i++) {
// 这部分的名称
printf("shape[%ld].name = %s\n", static_cast<long>(i),
shapes[i].name.c_str());
// 网格的点数
printf("Size of shape[%ld].mesh.indices: %lu\n", static_cast<long>(i),
static_cast<unsigned long>(shapes[i].mesh.indices.size()));
//printf("Size of shape[%ld].path.indices: %lu\n", static_cast<long>(i),static_cast<unsigned long>(shapes[i].path.indices.size()));

//assert(shapes[i].mesh.num_face_vertices.size() == shapes[i].mesh.material_ids.size());
//assert(shapes[i].mesh.num_face_vertices.size() == shapes[i].mesh.smoothing_group_ids.size());

printf("shape[%ld].num_faces: %lu\n", static_cast<long>(i),
static_cast<unsigned long>(shapes[i].mesh.num_face_vertices.size()));

Model* model = new Model(); // 每一部分的模型数据
// 顶点数量 = face的数量x3
model->mesh_num = shapes[i].mesh.num_face_vertices.size(http://www.my516.com) * 3;
// 开辟空间
Vertex *mesh_data = new Vertex[model->mesh_num];
size_t index_offset = 0;

// For each face
for (size_t f = 0; f < shapes[i].mesh.num_face_vertices.size(); f++) {
size_t fnum = shapes[i].mesh.num_face_vertices[f];

// 获得所索引下标
tinyobj::index_t idx;
int vertex_index[3];
int normal_index[3];
int texcoord_index[3];
for (size_t v = 0; v < fnum; v++) {
idx = shapes[i].mesh.indices[index_offset + v];
vertex_index[v] = idx.vertex_index;
texcoord_index[v] = idx.texcoord_index;
normal_index[v] = idx.normal_index;
}
for (size_t v = 0; v < fnum; v++) {
// v
mesh_data[index_offset + v].pos.x = attrib.vertices[(vertex_index[v]) * 3 + 0];
mesh_data[index_offset + v].pos.y = attrib.vertices[(vertex_index[v]) * 3 + 1];
mesh_data[index_offset + v].pos.z = attrib.vertices[(vertex_index[v]) * 3 + 2];
mesh_data[index_offset + v].pos.w = 1.0f;

// vt
mesh_data[index_offset + v].tc.u = attrib.texcoords[texcoord_index[v] * 2 + 0];
mesh_data[index_offset + v].tc.v = attrib.texcoords[texcoord_index[v] * 2 + 1];

// vn
mesh_data[index_offset + v].normal.x = attrib.normals[normal_index[v] * 3 + 0];
mesh_data[index_offset + v].normal.y = attrib.normals[normal_index[v] * 3 + 1];
mesh_data[index_offset + v].normal.z = attrib.normals[normal_index[v] * 3 + 2];
mesh_data[index_offset + v].normal.w = 1.0f;

// color
mesh_data[index_offset + v].color.r = 1.0f;
mesh_data[index_offset + v].color.g = 1.0f;
mesh_data[index_offset + v].color.b = 1.0f;
mesh_data[index_offset + v].color.a = 1.0f;
}

// 偏移
index_offset += fnum;
}
model->mesh = mesh_data;
models.push_back(model);
}
}

std::cout << "# Loading Complete #"<< std::endl;
//PrintInfo(attrib, shapes, materials);
return true;
}
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
实现结果
meshlab 观看效果.

导入光栅化渲染器的线框模型
---------------------

图形学基础 | 实现OBJ文件的载入的更多相关文章

  1. [计算机图形学] OpenGL读取obj文件并显示其3D效果

     读取三维网格模型(Wavefront OBJ文件) 无法向立方体:cube.obj 有法向兔子模型:bunny.obj 有法向有纹理八字模型:Eight.obj OBJ文件的格式可参考:http: ...

  2. obj文件的连接问题以及tlib的基本用法

    1.基础研究 用tcc将程序编译为.obj文件. 这里也可以使用tcc -linclude run.c来将run.c文件编译成run.obj文件. 再用tcc对下面的程序进行编译链接,发现提示错误: ...

  3. OBJ文件

    OBJ文件是Alias|Wavefront公司为它的一套基于工作站的3D建模和动画软件"Advanced Visualizer"开发的一种标准3D模型文件格式,很适合用于3D软件模 ...

  4. 软件光栅器实现(四、OBJ文件加载)

    本节介绍软件光栅器的OBJ和MTL文件加载,转载请注明出处. 在管线的应用程序阶段,我们需要设置光栅器所渲染的模型数据.这些模型数据包括模型顶点的坐标.纹理.法线和材质等等,可以由我们手动编写,也可以 ...

  5. 目前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Libary,以下简称“导入库”)。静态库是一个或者多个obj文件的打包

    前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Libary,以下简称“导入库”) ...

  6. CSharpGL(9)解析OBJ文件并用CSharpGL渲染

    CSharpGL(9)解析OBJ文件并用CSharpGL渲染 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo ...

  7. python基础知识---操作文件

    一.打开文件  open()函数 open函数返回一个文件对象. 用法:open('文件名','模式') 打开文件的模式有: r,只读模式(默认). w,只写模式.[不可读:不存在则创建:存在则删除内 ...

  8. Java基础之读文件——使用通道读取混合数据2(ReadPrimesMixedData2)

    控制台程序,本例读取Java基础之写文件部分(PrimesToFile2)写入的Primes.txt. 方法二:设置一个任意容量的.大小合适的字节缓冲区并且使用来自文件的字节进行填充.然后整理出缓冲区 ...

  9. Java基础之读文件——使用通道读取混合数据1(ReadPrimesMixedData)

    控制台程序,本例读取Java基础之写文件部分(PrimesToFile2)写入的Primes.txt. 方法一:可以在第一个读操作中读取字符串的长度,然后再将字符串和二进制素数值读入到文本中.这种方式 ...

随机推荐

  1. 区间DP 等腰三角形

    题目描述:给定一个正N边形,可以通过连线将这个多边形分割成N-2个三角形,问这N-2个三角形中恰有k个等腰三角形的分割方法有多少?这个值可能很大,输出对9397取模的结果.数据范围:n,k <= ...

  2. HNOI2008 明明的烦恼 (purfer序列 + 组合数学)

    传送门 这道题题意描述很清楚,不过我自己做的时候确实是一头雾水……又看了题解,发现要用到一个新知识,叫purfer序列. 我们来简单说一下什么是purfer序列.它可以被看作一种树的表现形式.一棵含有 ...

  3. Java中Semaphore(信号量) 数据库连接池

    计数信号量用来控制同时访问某个特定资源的操作数或同时执行某个指定操作的数量 A counting semaphore.Conceptually, a semaphore maintains a set ...

  4. 杂项:ASP.NET Core

    ylbtech-杂项:ASP.NET Core 1.返回顶部 1. ASP.NET Core 是一个跨平台的高性能开源框架,用于生成基于云且连接 Internet 的新式应用程序.使用 ASP.NET ...

  5. 【旧文章搬运】暴搜内存查找PE镜像

    原文发表于百度空间,2008-7-28========================================================================== 前面介绍了修 ...

  6. 土法搞docker系列之自制docker的graph driver vdisk

    写在最前 偶然整理,翻出来14年刚开始学docker的时候的好多资料.当时docker刚刚进入国内,还有很多的问题.当时我们的思考方式很简单,docker确实是个好的工具,虽然还不成熟.但是不能因为短 ...

  7. E20180407-hm

    queue   n. (人或车辆) 行列,长队; 辫子;   vi. (人.车等) 排队等候;   vt. (使) 排队,列队等待; compatible  adj. 兼容的,相容的; 和谐的,协调的 ...

  8. 基础BFS+DFS poj3083

    //满基础的一道题 //最短路径肯定是BFS. //然后靠右,靠左,就DFS啦 //根据前一个状态推出下一个状态,举靠左的例子,如果一开始是上的话,那么他的接下来依次就是 左,上 , 右 , 下 // ...

  9. java 发送get,post请求

    package wzh.Http; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStr ...

  10. windows 远程连接 密码正确但是无法登陆,提示证书不正确

    问题: windows8.1 远程连接 windows8 进入输入用户名密码环节,用户名,密码都正确,但是无法登陆 连接时,下方写着 域名 MicrosoftAccount 解决: 在输入密码后,点击 ...