-1

I've life like loading 3D model. Because of that I tried to use Assimp.

Sadly, I wasn't able to get any result out of it. I was able to get a mesh class working and by manually filling data to it, I was able to make a cube. But my model class doesn't seem to work.

Assimp didn't return any kind of error, so I guess in the mind of Assimp I did not wrong(I probably did)

According to the debugger, the data was successfully filled (note: "mod" is the name of the model)

enter image description here

Other than that, the code is inspired by this, the biggest difference is really in the texture loading(I use theSFML library to load textures) and a little bit in the mesh loading, the logic stay the same.

here's the code

model.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

model.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 (the thing I use to load textures):

#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

textureManager.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;
genpfault
  • 51,148
  • 11
  • 85
  • 139
  • So, I managed to manually setup a cube and it rendered in OpenGL fine. Hence, next I down-loaded a complex library with some hundred KB and try to load a complex model from file but it didn't work. I debugged it but didn't get a clue...: Yeah. I would say: one step back. I remember AssImp is mentioned in certain OpenGL tutorials. I would follow them **but** also use their sample data. May be, AssImp simply cannot read _your_ model due to incompabilities - who knows. May be, you google for 3D file formats and try to implement a simple one by yourself. (Some of them are really simple.) – Scheff's Cat Nov 28 '17 at 07:15
  • Regarding simple 3D file formats: [AC3D](https://www.inivis.com/) uses the [AC3D file format](https://www.inivis.com/ac3d/man/ac3dfileformat.html) which I would consider as simple but probably powerful enough for your needs. The software itself provides some samples (which I used to test my own loader implementation). The file format is in ASCII and, thus, human-readable. That makes testing/debugging easy. – Scheff's Cat Nov 28 '17 at 07:22
  • Did you check the values inside `vertices` and `indices`? Are they what they should be? Are the textures correctly loaded (verify with any OpenGL debugger like CodeXL, renderdoc, whatever). How should we know what is going wrong if you neither tell us which data you are using nor how it gets rendered? – BDL Nov 28 '17 at 09:52
  • there is 36 vertices and 36 indices. I looked through all the vertices and they all seem to point directly in a good position. The indices are quite weird. they are mapped from 0 to 35. for exemple: the index 0 will have the index 1 will have the indice 1,....and so on. I don't know if it's normal, I'm quite new to the library. Maybe it's because I'm extra noob, but when using renderDoc, I am able to get result for a simple hardcoded mesh but when I'm using model class it close instantly. – Turquoisepotato Nov 28 '17 at 16:30

1 Answers1

0

The data was loaded successfully.

You need to setup your view onto the model in the right way as well. Maybe you did that already but I was not able to detect the code for that in your example.

For a simple cube placed a the position ( 0|0|0 ) you just can look onto this origin. You can use glm for computing the right matrix. You can find an example here .

One point to check: Your vertex- and fragment shaders a setup correctly as well?

KimKulling
  • 2,654
  • 1
  • 15
  • 26