1
\$\begingroup\$

I have model created in Blender that have 3 UV Maps, 3 materials and each material has texture. Below you can see it.

enter image description here

Also I have OpenGL application that draw this model. Application is working perfectly with one material, but with two or more materials it draw only first. Model was imported with Assimp. I saw that Assimp splits the mesh in three meshes for each material, maybe I handle wrong way these 3 meshes. Below is illustrated results(left in Blender and right in OpenGL): enter image description here

Code. Initializing model

void AnimatedModel::initModel(string filePath) {
    path = filePath;
    loaded = true;
    Importer importer;
    unsigned int flags = aiProcess_Triangulate |
        aiProcess_FlipUVs |
        aiProcess_CalcTangentSpace | aiProcess_GenNormals | aiProcess_LimitBoneWeights;
    const aiScene* scene = importer.ReadFile(filePath, flags);
    if (!scene || scene->mFlags&& AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
        cout << "Model::'" << filePath << "': " << importer.GetErrorString() << endl;
        loaded = false;
        return;
    }

    processNode(scene->mRootNode, scene);
}
void AnimatedModel::processNode(aiNode* node, const aiScene* scene) {
    //process all meshes
    unsigned int nrMeshes = node->mNumMeshes;
    for (int a = 0; a < nrMeshes; ++a) {
        aiMesh* mesh = scene->mMeshes[a];
        BoneMesh processedMesh = processBoneMesh(mesh, scene);
        meshes.push_back(processedMesh);
    }

    //do the same with children
    for (int a = 0; a < node->mNumChildren; ++a) {
        processNode(node->mChildren[a], scene);
    }
}
map<string, int> tmp;
BoneMesh AnimatedModel::processBoneMesh(aiMesh* mesh, const aiScene* scene) {
    vector<BoneVertex> vertices;
    vector<unsigned int> indices;
    vector<Texture> textures;

    //calculate texture index
    string meshName(mesh->mName.C_Str());
    int textureIndex = 0;
    if (tmp.find(meshName) == tmp.end()) {
        tmp.insert(make_pair(meshName, 1));
    }
    else {
        textureIndex = tmp.at(meshName);
        tmp.at(meshName) += 1;
    }

    //read vertices
    unsigned int nrVertices = mesh->mNumVertices;
    for (int a = 0; a < nrVertices; ++a) {
        BoneVertex vertex;
        vec3 tmpVector;

        //position
        tmpVector.x = mesh->mVertices[a].x;
        tmpVector.y = mesh->mVertices[a].y;
        tmpVector.z = mesh->mVertices[a].z;
        vertex.position = tmpVector;

        //textures
        if (mesh->mTextureCoords[textureIndex]) {
            vec2 texCoord;
            texCoord.x = mesh->mTextureCoords[textureIndex][a].x;
            texCoord.y = mesh->mTextureCoords[textureIndex][a].y;
            vertex.texCoords = texCoord;
        }

        vertices.push_back(vertex);
    }

    //read faces
    unsigned int nrFaces = mesh->mNumFaces;
    for (int a = 0; a < nrFaces; ++a) {
        aiFace face = mesh->mFaces[a];
        for (int b = 0; b < face.mNumIndices; ++b) {
            indices.push_back(face.mIndices[b]);
        }
    }

    //read material
    aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
    if (material) {
        vector<Texture> diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
        textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
        vector<Texture> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
        textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
    }

    BoneMesh boneMesh(vertices, indices, textures);
    return boneMesh;
}
vector<Texture> AnimatedModel::loadMaterialTextures(aiMaterial* material, aiTextureType texType, string texName) {
    vector<Texture> textures;
    unsigned int nrTextures = material->GetTextureCount(texType);

    for (int a = 0; a < nrTextures; ++a) {
        aiString texPath;
        aiReturn ret = material->GetTexture(texType, a, &texPath);
        if (ret != aiReturn_SUCCESS) {
            cout << "Error: Can't get '" << texPath.C_Str() << "' texture" << endl;
            continue;
        }

        unsigned int nrLoadedTextures = this->textures.size();
        bool alreadyLoaded = false;
        for (int b = 0; b < nrLoadedTextures; ++b) {
            if (strcmp(texPath.C_Str(), this->textures[b].path.C_Str()) == 0) {
                alreadyLoaded = true;
                textures.push_back(this->textures[b]);
                break;
            }
        }

        if (!alreadyLoaded) {
            Texture texture;
            string directory = path.substr(0, path.find('/', 0));
            texture.id = loadTextureFromFile(texPath.C_Str(), directory);
            texture.path = texPath;
            texture.type = texName;
            textures.push_back(texture);
            this->textures.push_back(texture);
        }
    }

    return textures;
}
unsigned int AnimatedModel::loadTextureFromFile(const string& path, const string& directory, bool gamma) {
    unsigned int id;
    glGenTextures(1, &id);


    int width, height, nrComponents;
    string matPath = string(directory + "/" + path);

    unsigned char* data = stbi_load(matPath.c_str(), &width, &height, &nrComponents, 0);
    if (data) {
        GLenum format;
        if (nrComponents == 1)
            format = GL_RED;
        else if (nrComponents == 3)
            format = GL_RGB;
        else if (nrComponents == 4)
            format = GL_RGBA;

        glBindTexture(GL_TEXTURE_2D, id);
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        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);
    }
    else
    {
        cout << "Error: Can't load texture '" << matPath.c_str() << "'" << endl;
    }
    stbi_image_free(data);

    return id;
}

Drawing model

void AnimatedModel::draw(Shader shader) {
    for (BoneMesh m : meshes) {
        m.draw(shader);
    }
}

Initializing Mesh

void BoneMesh::initMesh(){
    // create buffers/arrays
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    glBindVertexArray(VAO);
    // load data into vertex buffers
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(BoneVertex), &vertices[0], GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);

    // set the vertex attribute pointers
    // vertex Positions
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BoneVertex), (void*)0);
    // vertex texture coords
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(BoneVertex), (void*)offsetof(BoneVertex, texCoords));

    //reset
    glBindVertexArray(0);
}

Draw Mesh

void BoneMesh::draw(Shader shader)
{
    //bind textures
    unsigned int diffuseNr = 1;
    unsigned int specularNr = 1;
    for (unsigned int nrTexture = 0; nrTexture < textures.size(); ++nrTexture)
    {
        glActiveTexture(GL_TEXTURE0 + nrTexture);
        stringstream ss;
        string number;
        string name = textures[nrTexture].type;
        if (name == "texture_diffuse")
            ss << diffuseNr++; 
        else if (name == "texture_specular")
            ss << specularNr++; 
        number = ss.str();

        glUniform1i(glGetUniformLocation(shader.getId(), (name + number).c_str()), nrTexture);
        glBindTexture(GL_TEXTURE_2D, textures[nrTexture].id);
    }

    // draw mesh
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, (GLsizei)indices.size(), GL_UNSIGNED_INT, (void*)0);


    //set to default
    glBindVertexArray(0);
    glActiveTexture(GL_TEXTURE0);
}
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I found solution. Problem was in bone weights. I have skeletal animation so in vertex shader I multiply each bone matrixes with bone weights and finally with vertex position. Bone weights had 0.0 value so all vertex positions after multiply becomes 0.0 .

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .