繁体   English   中英

如何使用 tinyobjloader 在 OpenGL 中绘制 OBJ 文件?

[英]How do I draw an OBJ file in OpenGL using tinyobjloader?

我正在尝试从 OpenGL 中的 Starfox 64 绘制这个免费的机翼 model。 我在 Blender 中将 .fbx 文件转换为 .obj 并使用tinyobjloader加载它(我的大学科目的所有要求)。

我几乎将示例代码(使用现代 API)添加到我的程序中,替换了文件名,并抓取了attrib.verticesattrib.normals向量来绘制机翼。

我可以用 GL_POINTS 查看顶点:

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &vertices[0]);
glDrawArrays(GL_POINTS, 0, vertices.size() / 3);
glDisableClientState(GL_VERTEX_ARRAY);

哪个看起来正确(我......认为?):

在此处输入图像描述

但我不确定如何渲染坚固的 model。 简单地将 GL_POINTS 替换为 GL_TRIANGLES(如图所示)或 GL_QUADS 不起作用:

在此处输入图像描述

我正在使用 OpenGL 1.1 w/GLUT(再次,大学)。 我想我只是不知道自己在做什么,真的。 帮助?

E:当我最初写这个答案时,我只使用顶点和法线。 我已经想出了如何让材质和纹理发挥作用,但目前没有时间写出来。 我会在我有时间的时候补充一下,但如果你想同时在 tinyobj header 周围戳一下,这在很大程度上是相同的逻辑。 :-)

我在最后一天学到了很多关于 TinyOBJLoader 的知识,所以我希望这对将来的人有所帮助。 归功于这个 GitHub 存储库,它在 fileloader.cpp 中非常清楚和干净地使用了fileloader.cpp

总结一下我学习该代码所学到的知识:

形状是shape_t类型。 对于单个 model OBJ, shapes的大小为 1。我假设 OBJ 文件可以包含多个对象,但我对文件格式了解不多。

shape_t有一个mesh_t类型的成员mesh 该成员存储从 OBJ 的人脸行解析的信息。 您可以通过检查material_ids成员的大小来计算 object 的面数。

每个面的顶点、纹理坐标和法线索引都存储在网格的indices成员中。 这是std::vector<index_t>类型。 这是一个扁平化的索引向量。 因此,对于具有三角面f1, f2... fi的 model ,它存储v1, t1, n1, v2, t2, n2... vi, ti, ni 请记住,这些索引对应于整个顶点、纹理坐标或法线。 就我个人而言,我通过将 model 导入 Blender 并在打开三角测量的情况下将其导出来对我的 model 进行三角测量。 TinyOBJ 有自己的三角测量算法,您可以通过设置reader_config.triangulate标志来打开。

到目前为止,我只使用了顶点和法线。 以下是我如何访问和存储它们以在 OpenGL 中使用:

  1. 将平面顶点和法线 arrays 转换为 3 个组,即 3D 向量
for (size_t vec_start = 0; vec_start < attrib.vertices.size(); vec_start += 3) {
    vertices.emplace_back(
        attrib.vertices[vec_start],
        attrib.vertices[vec_start + 1],
        attrib.vertices[vec_start + 2]);
}

for (size_t norm_start = 0; norm_start < attrib.normals.size(); norm_start += 3) {
    normals.emplace_back(
        attrib.normals[norm_start],
        attrib.normals[norm_start + 1],
        attrib.normals[norm_start + 2]);
}

这样,顶点和法线容器的索引将与面条目给出的索引相对应。

  1. 循环遍历每个面,并将顶点和法线索引存储在单独的 object 中
for (auto shape = shapes.begin(); shape < shapes.end(); ++shape) {
    const std::vector<tinyobj::index_t>& indices = shape->mesh.indices;
    const std::vector<int>& material_ids = shape->mesh.material_ids;

    for (size_t index = 0; index < material_ids.size(); ++index) {
        // offset by 3 because values are grouped as vertex/normal/texture
        triangles.push_back(Triangle(
            { indices[3 * index].vertex_index, indices[3 * index + 1].vertex_index, indices[3 * index + 2].vertex_index },
            { indices[3 * index].normal_index, indices[3 * index + 1].normal_index, indices[3 * index + 2].normal_index })
        );
    }
}

绘图很容易:

glBegin(GL_TRIANGLES);
for (auto triangle = triangles.begin(); triangle != triangles.end(); ++triangle) {
    glNormal3f(normals[triangle->normals[0]].X, normals[triangle->normals[0]].Y, normals[triangle->normals[0]].Z);
    glVertex3f(vertices[triangle->vertices[0]].X, vertices[triangle->vertices[0]].Y, vertices[triangle->vertices[0]].Z);

    glNormal3f(normals[triangle->normals[1]].X, normals[triangle->normals[1]].Y, normals[triangle->normals[1]].Z);
    glVertex3f(vertices[triangle->vertices[1]].X, vertices[triangle->vertices[1]].Y, vertices[triangle->vertices[1]].Z);

    glNormal3f(normals[triangle->normals[2]].X, normals[triangle->normals[2]].Y, normals[triangle->normals[2]].Z);
    glVertex3f(vertices[triangle->vertices[2]].X, vertices[triangle->vertices[2]].Y, vertices[triangle->vertices[2]].Z);
}
glEnd();

在此处输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM