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
\$\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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.