我的 OpenGL 图形库中的模型加载策略有什么问题?

问题描述 投票:0回答:1

我正在用 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 文件,这就是我得到的:

人: Person

布加迪: Bugatti

苹果:

三角测量不是问题,我尝试过使用三角测量的 OBJ 文件,结果几乎相同。

程序不会崩溃,它完全正常关闭,退出代码为 0。

所有源代码(供额外参考)均位于 GitHub 上:https://github.com/jopo86/onyx

c++ opengl graphics model objloader
1个回答
0
投票

问题最终是 VertexArray 和 IndexArray 中的

size
参数以字节为单位,因此我必须将向量的大小乘以其数据类型的大小。这解决了一切。

© www.soinside.com 2019 - 2024. All rights reserved.