【问题标题】:Unable to load 3D model with assimp无法使用 assimp 加载 3D 模型
【发布时间】:2018-05-11 10:40:42
【问题描述】:

我喜欢加载 3D 模型。因此,我尝试使用 Assimp。

很遗憾,我无法从中得到任何结果。 我能够让一个网格类工作,并通过手动向它填充数据,我能够制作一个立方体。但是我的模型课似乎不起作用。

Assimp 没有返回任何类型的错误,所以我想在 Assimp 的脑海中我没有错(我可能确实错了)

根据调试器,数据填充成功(注意:“mod”为模型名)


除此之外,代码灵感来自this,最大的区别在于纹理加载(我使用SFML库加载纹理)和网格加载一点点,逻辑保持不变。

这是代码

模型.h:

#ifndef MODEL_H
#define MODEL_H

#include "Mesh.h"
#include "ressourceManager/TextureManager.h"

#include <iostream>
#include <string>


#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>


using namespace std;

class Model
{
    public:
        Model(const string &path);
        void Draw(Shader &shader);

    private:
        vector<Mesh> meshes;

        string directory;

        void loadModel(const string &path);
        void processNode(aiNode *node, const aiScene *scene);
        Mesh processMesh(aiMesh *mesh, const aiScene *scene);
        vector<Texture> loadMaterialTextures(aiMaterial *mat, aiTextureType type, string typeName);

};

#endif // MODEL_H

模型.cpp:

#include "Model.h"


Model::Model(const string &path)
{

    loadModel(path);
}

void Model::Draw(Shader &shader)
{
    for(Mesh mesh: meshes)
        mesh.draw(shader);

}

void Model::loadModel(const string &path)
{
    Assimp::Importer import;
    const aiScene *scene = import.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);

    if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode){
        cout << "ERROR::ASSIMP::" << import.GetErrorString() << endl;
        return;
    }

    directory = path.substr(0, path.find_last_of('/'));
    processNode(scene->mRootNode, scene);

}

void Model::processNode(aiNode* node, const aiScene* scene)
{
    for(unsigned int i = 0; i < node->mNumMeshes; i++){
        aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
        meshes.push_back(processMesh(mesh, scene));
    }

    for(unsigned int i = 0; i < node->mNumChildren; i++)
        processNode(node->mChildren[i], scene);

}

Mesh Model::processMesh(aiMesh* mesh, const aiScene* scene)
{

    vector<Vertex> vertices;
    vector<GLuint> indices;
    vector<Texture> textures;

    for(unsigned int i = 0; i < mesh->mNumVertices; i++){
        Vertex vertex;

        glm::vec3 vector;

        vector.x = mesh->mVertices[i].x;
        vector.y = mesh->mVertices[i].y;
        vector.z = mesh->mVertices[i].z;
        vertex.pos = vector;

        vector.x = mesh->mNormals[i].x;
        vector.y = mesh->mNormals[i].y;
        vector.z = mesh->mNormals[i].z;
        vertex.normal = vector;

        if(mesh->mTextureCoords[0]){
            glm::vec2 vec;
            vec.x = mesh->mTextureCoords[0][i].x;
            vec.y = mesh->mTextureCoords[0][i].y;
            vertex.texCoord = vec;

        }else
            vertex.texCoord = glm::vec2(0.0f, 0.0f);


        vertices.push_back(vertex);
    }

    for ( GLuint i = 0; i < mesh->mNumFaces; i++ ){
        aiFace face = mesh->mFaces[i];
        for ( GLuint j = 0; j < face.mNumIndices; j++ )
            indices.push_back( face.mIndices[j] );
    }

    if(mesh->mMaterialIndex >= 0){
        aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];

        vector<Texture> diffuseMaps = this->loadMaterialTextures( material, aiTextureType_DIFFUSE, "texture_diffuse" );
        textures.insert( textures.end( ), diffuseMaps.begin( ), diffuseMaps.end( ) );

        // 2. Specular maps
        vector<Texture> specularMaps = this->loadMaterialTextures( material, aiTextureType_SPECULAR, "texture_specular" );
        textures.insert( textures.end( ), specularMaps.begin( ), specularMaps.end( ) );
   }

    return Mesh(vertices, indices, textures);
}

vector<Texture> Model::loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName)
{

    vector<Texture> textures;

    for(unsigned int i = 0; i < mat->GetTextureCount(type); i++){

        aiString str;
        mat->GetTexture( type, i, &str );

        Texture texture;
        texture.ID = *RessourceManager::TextureManager::get(directory + "/" + str.C_Str());
        texture.type = typeName;
        texture.path = str;
        textures.push_back(texture);
    }
    return textures;
}

textureManager.h(我用来加载纹理的东西):

#ifndef TEXTUREMANAGER_H
#define TEXTUREMANAGER_H

#include <unordered_map>
#include <memory>
#include <GL/glew.h>

namespace RessourceManager{
    class TextureManager
        {
            public:
                TextureManager();
                static std::shared_ptr<GLuint> get(const std::string& name);
                static void removeUnused();
            private:
                static std::unordered_map<std::string, std::shared_ptr<GLuint>> p_textureIDs;
        };
    }

    #endif // TEXTUREMANAGER_H

纹理管理器.cpp

#include "TextureManager.h"
#include "SFML/Graphics.hpp"
#include <iostream>
namespace RessourceManager{
    TextureManager::TextureManager()
    {

    }

    std::shared_ptr<GLuint> TextureManager::get(const std::string& name)
    {
        const auto i = p_textureIDs.find(name);
        if(i != p_textureIDs.end())
            return i->second;
        else{
            std::shared_ptr<GLuint> p_textureID = std::make_shared<GLuint>();

            glGenTextures(1, p_textureID.get());


            sf::Image image;
            image.loadFromFile(name);

            glBindTexture(GL_TEXTURE_2D, *p_textureID.get());
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getSize().x, image.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.getPixelsPtr());
            glGenerateMipmap(GL_TEXTURE_2D);

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

            glBindTexture( GL_TEXTURE_2D, 0 );

            p_textureIDs.insert({name, p_textureID});
            std::cout << "new texture created" << std::endl;
            return p_textureID;
        }
    }

    void TextureManager::removeUnused()
    {
        for(auto i = p_textureIDs.begin(); i != p_textureIDs.end();)
            if(i->second.unique())
                i = p_textureIDs.erase(i);
            else
                ++i;
    }


    std::unordered_map<std::string, std::shared_ptr<GLuint>> TextureManager::p_textureIDs;

【问题讨论】:

  • 所以,我设法手动设置了一个立方体,它在 OpenGL 中渲染得很好。因此,接下来我下载了一个数百 KB 的复杂库,并尝试从文件中加载一个复杂的模型,但没有成功。我调试了它,但没有得到任何线索......:是的。我会说:退一步。我记得在某些 OpenGL 教程中提到了 AssImp。我会关注他们也会使用他们的样本数据。可能是因为不兼容,AssImp 根本无法读取 your 模型 - 谁知道呢。可能是,您搜索 3D 文件格式并尝试自己实现一个简单的格式。 (其中一些非常简单。)
  • 关于简单的 3D 文件格式:AC3D 使用 AC3D file format,我认为它很简单,但可能足以满足您的需求。该软件本身提供了一些示例(我用来测试我自己的加载器实现)。文件格式为 ASCII,因此是人类可读的。这使得测试/调试变得容易。
  • 您检查了verticesindices 中的值吗?他们是他们应该的样子吗?纹理是否正确加载(使用任何 OpenGL 调试器(如 CodeXL、renderdoc 等)进行验证)。如果您既不告诉我们您正在使用哪些数据,也不告诉我们它是如何呈现的,我们怎么知道出了什么问题?
  • 共有 36 个顶点和 36 个索引。我查看了所有顶点,它们似乎都直接指向一个好的位置。指数很奇怪。它们从 0 映射到 35。例如:索引 0 将具有索引 1 将具有索引 1,....等等。我不知道这是否正常,我对图书馆很陌生。也许是因为我比较菜鸟,但是在使用 renderDoc 时,我能够获得简单硬编码网格的结果,但是当我使用模型类时,它会立即关闭。

标签: c++ opengl 3d sfml assimp


【解决方案1】:

数据已成功加载。

您还需要以正确的方式将视图设置到模型上。也许您已经这样做了,但我无法在您的示例中检测到该代码。

对于放置位置 (0|0|0) 的简单立方体,您只需查看该原点即可。您可以使用 glm 来计算正确的矩阵。您可以找到一个示例 here

需要检查的一点:您的顶点和片段着色器设置是否正确?

【讨论】:

    猜你喜欢
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    • 2013-07-15
    • 2021-12-15
    • 2016-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多