我正在用 C++ 创建一个图形库(https://github.com/jopo86/onyx了解更多信息)。到目前为止,我已经取得了相当好的进展,您可以使用用户定义的顶点渲染事物,包括位置顶点、法线、纹理坐标和/或颜色,但现在我正在尝试添加一些模型加载。我开始尝试使用 learnopengl.com 以及他们使用 Assimp 的模型加载部分,但是我当时编写的所有代码都与他们的做法非常不同,而且很难转移到我的库中。因此,我寻找了一个更简单的解决方案 - 我找到了一个漂亮且简单的 C++ 单头 OBJ 加载器(https://github.com/Bly7/OBJ-Loader),并解决了这个问题。奇怪的是加载和渲染的对象是可以识别的,只是有很多缺失或完全不合适。通常情况下,事情要么完全工作,要么非常接近完全工作,要么根本不工作,但我觉得奇怪的是,这有点中间。
因此,我尝试使用 OBJ 加载器将顶点、索引、纹理坐标等加载到我的网格数据结构中,该数据结构采用 VertexArray 和 IndexArray 数据结构。 VertexArray 保存实际的顶点数据(浮点指针/数组)、数据的大小和顶点格式(VN、VNT、VNC、VNCT 等,其中 V 是顶点(位置),N 是法线,T 是纹理坐标,C 是颜色)。顶点格式仅用于设置着色器的顶点属性指针。索引数组保存实际的索引数据(uint 指针/数组)和数据的大小。然后,我将纹理数据加载到纹理数据结构中,该结构仅保存 OpenGL 纹理 ID,并从 ImageData 生成纹理,ImageData 使用 stb_image 从文件路径加载纹理信息。我创建一个着色器,要么从 OBJ(Kd)的材质中获取顶点和法线以及漫反射颜色,或者如果有纹理,则获取顶点、法线和纹理坐标,并在适当的时候绑定纹理。
所有这些都是在 Model 类中完成的,该类保存 OBJ 的目录以及网格、着色器和纹理的向量。这是代码:
Onyx::Model* Onyx::Model::LoadOBJ(const std::string& filepath)
{
Model* model = new Model;
AddMalloc(model, false);
std::string slash = filepath.find("/") ? "/" : "\\";
model->directory = filepath.substr(0, filepath.find_last_of(slash));
objl::Loader loader;
if (!loader.LoadFile(filepath))
{
Err("Unable to load OBJ model: \"" + filepath + "\"");
return model;
}
for (const objl::Mesh& objlMesh : loader.LoadedMeshes)
{
std::vector<float>* vertices = new std::vector<float>;
for (const objl::Vertex& vertex : objlMesh.Vertices)
{
vertices->push_back(vertex.Position.X);
vertices->push_back(vertex.Position.Y);
vertices->push_back(vertex.Position.Z);
vertices->push_back(vertex.Normal.X);
vertices->push_back(vertex.Normal.Y);
vertices->push_back(vertex.Normal.Z);
vertices->push_back(vertex.TextureCoordinate.X);
vertices->push_back(vertex.TextureCoordinate.Y);
}
std::vector<uint>* indices = new std::vector<uint>;
for (uint index : objlMesh.Indices)
{
indices->push_back(index);
}
AddMalloc(vertices, false);
AddMalloc(indices, false);
model->meshes.push_back(Mesh(
VertexArray(vertices->data(), vertices->size(), VertexFormat::VNT),
IndexArray(indices->data(), indices->size())
));
bool hasTexture = objlMesh.MeshMaterial.map_Kd != "";
model->textures.push_back(
hasTexture ?
Texture(
ImageData::Load(model->directory + "/" + objlMesh.MeshMaterial.map_Kd)
)
: Texture()
);
if (hasTexture) model->shaders.push_back(ShaderPresets::VNT());
else
{
model->shaders.push_back(ShaderPresets::VN_Color(Vec4(objlMesh.MeshMaterial.Kd.X, objlMesh.MeshMaterial.Kd.Y, objlMesh.MeshMaterial.Kd.Z, 1.0f)));
}
}
return model;
}
所以我尝试使用一个人、一辆布加迪和一些低多边形苹果的 OBJ 文件,这就是我得到的:
人:
布加迪:
苹果:
三角测量不是问题,我尝试过使用三角测量的 OBJ 文件,结果几乎相同。
程序不会崩溃,它完全正常关闭,退出代码为 0。
所有源代码(供额外参考)均位于 GitHub 上:https://github.com/jopo86/onyx
问题最终是 VertexArray 和 IndexArray 中的
size
参数以字节为单位,因此我必须将向量的大小乘以其数据类型的大小。这解决了一切。