Home > Back-end >  loading mtl on obj file in OpenGL - how to write fragment shader?
loading mtl on obj file in OpenGL - how to write fragment shader?

Time:10-03

I have an obj file with the the following mtl, see below. I am using mesh.cpp and model.cpp based on Assimp and from learnopengl. The relevant parts of the code are below. I think that everything works except Fragment Shader.

newmtl k909090
 Ns 163
 Tr 1
 Ni 0.001
 illum 2
 Ka 0.20 0.20 0.20
 Kd .566 .566 .566
 Ks 0.25 0.25 0.25

newmtl kff0d0d
 Ns 163
 Tr 1
 Ni 0.001
 illum 2
 Ka 0.20 0.20 0.20
 Kd 1 .055 .055
 Ks 0.25 0.25 0.25

newmtl kffffff
 Ns 163
 Tr 1
 Ni 0.001
 illum 2
 Ka 0.20 0.20 0.20
 Kd 1 1 1
 Ks 0.25 0.25 0.25

In the relevant code parts I described :

  struct Material {
        float shininess;
        float opacity;
        float density;
        float illum;
        glm::vec3 ambient;
        glm::vec3 diffuse;
        glm::vec3 specular;
    };

// render the mesh
    void Draw(Shader &shader)
    {
        shader.setFloat("material.shininess", material.shininess);
        shader.setFloat("material.opacity", material.opacity);
        shader.setFloat("material.density", material.shininess);
        shader.setFloat("material.illum", material.opacity);
        shader.setVec3("material.ambient", material.ambient);
        shader.setVec3("material.diffuse", material.diffuse);
        shader.setVec3("material.specular", material.specular);

        // draw mesh
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, static_cast<unsigned int>(indices.size()), GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
    }

The model class:

 Material loadMaterial(aiMaterial *mat)
    {
        Material material{};
        aiColor3D color(0.f, 0.f, 0.f);

        float shininess;
        float opacity;
        float density;
        float illum;
        glm::vec3 ambient;
        glm::vec3 diffuse;
        glm::vec3 specular;


        mat->Get(AI_MATKEY_SHININESS, shininess);
        material.shininess = shininess;

        mat->Get(AI_MATKEY_OPACITY, opacity);
        material.opacity = opacity;

        mat->Get(AI_MATKEY_COLOR_TRANSPARENT, density);
        material.density = density;

        mat->Get(AI_MATKEY_SHADING_MODEL, illum);
        material.illum = illum;

        mat->Get(AI_MATKEY_COLOR_AMBIENT, color);
        material.ambient = glm::vec3(color.r, color.g, color.b);

        mat->Get(AI_MATKEY_COLOR_DIFFUSE, color);
        material.diffuse = glm::vec3(color.r, color.g, color.b);

        mat->Get(AI_MATKEY_COLOR_SPECULAR, color);
        material.specular = glm::vec3(color.r, color.g, color.b);

        return material;
    }
    Mesh processMesh(aiMesh *mesh, const aiScene *scene)
    {
        // data to fill
        vector<Vertex> vertices;
        vector<unsigned int> indices;
        Material matProps;

        // walk through each of the mesh's vertices
        for(unsigned int i = 0; i < mesh->mNumVertices; i  )
        {
            Vertex vertex;
            glm::vec3 vector; // we declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to glm's vec3 class so we transfer the data to this placeholder glm::vec3 first.
            // positions
            vector.x = mesh->mVertices[i].x;
            vector.y = mesh->mVertices[i].y;
            vector.z = mesh->mVertices[i].z;
            vertex.Position = vector;
            // normals
            if (mesh->HasNormals())
            {
                vector.x = mesh->mNormals[i].x;
                vector.y = mesh->mNormals[i].y;
                vector.z = mesh->mNormals[i].z;
                vertex.Normal = vector;
            }

            vertices.push_back(vertex);
        }
        // now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.
        for(unsigned int i = 0; i < mesh->mNumFaces; i  )
        {
            aiFace face = mesh->mFaces[i];
            for(unsigned int j = 0; j < face.mNumIndices; j  )
                indices.push_back(face.mIndices[j]);
        }

        // process materials
        aiMaterial *mat = scene->mMaterials[mesh->mMaterialIndex];
        matProps = loadMaterial(mat);


        return {vertices, indices, matProps};
    }

And now I am struggling with fragment shader that gives me various errors and cannot compile. Question: what would be the right setup for fragment shader?

#version 330 core
out vec4 FragColor;

struct Material {
        float shininess;
        float opacity;
        float density;
        float illum;
        vec3 ambient;
        vec3 diffuse;
        vec3 specular;
}

struct Light {
    //vec3 position;
    vec3 direction;

    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

in vec3 FragPos;
in vec3 Normal;

uniform vec3 viewPos;
uniform Material material;

void main()
{
    // ambient
    vec3 ambient = light.ambient;

    // diffuse
    vec3 norm = normalize(Normal);
    // vec3 lightDir = normalize(light.position - FragPos);
    vec3 lightDir = normalize(-light.direction);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = light.diffuse * diff;

    // specular
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec3 specular = light.specular * spec;

    vec3 result = ambient   diffuse   specular;
    FragColor = vec4(result, 1.0);
}

CodePudding user response:

The most important part that is missing in your light model implementation is the consideration of material colors. Ka, Kd and Ks specify the ambient color, diffuse color and specular color of the material.
Tr specifies the alpha value and transparency of the material. You only can use it together with Blending. Ni is the refraction of the material, which can be used e.g. with environment maps. illum specifies the lighting model and is only useful if you have implemented different lighting models. In your case, you can just ignore it. There are many resources about that all over the web (e.g. Wikipedia - Wavefront).

With your actual render implementation you can use the properties Ka (ambient), Kd (diffuse), Ks (specular) and Ns (shininess). e.g:

void main()
{
    // ambient
    vec3 ambient = light.ambient * material.ambient;

    // diffuse
    vec3 norm = normalize(Normal);
    // vec3 lightDir = normalize(light.position - FragPos);
    vec3 lightDir = normalize(-light.direction);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = light.diffuse * diff * material.diffuse;

    // specular
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec3 specular = light.specular * spec * material.specular;

    vec3 result = ambient   diffuse   specular;
    FragColor = vec4(result, 1.0);
}
  • Related