最近在使用opengl做学校的大作业,在读取模型时遇到了无法显示材质的问题,在通过研究obj与mtl文件格式时发现了原因。
由于之前一直是使用别人做好的读取类,对于有贴图的模型可以正常处理,但是这次的模型没有贴图,材质都是用属性直接指定的,如
其中,Ka代表环境光,Kd代表漫反射光,Ks代表镜面高光。
为了读取这些数据,在已有的代码中进行了修改(代码在最下)。assimp中其实提供了方法读取这些数据,我们只要保存在mesh信息中,并传入着色器即可使用。
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
Material mat;
aiColor3D color;
//读取mtl文件顶点数据
material->Get(AI_MATKEY_COLOR_AMBIENT, color);
mat.Ka = glm::vec4(color.r, color.g, color.b,1.0);
其中AI_MATKEY_COLOR_AMBIENT即对应了环境光的信息。
在将数据传入着色器时,使用了ubo对象,因为vbo中已经保存了模型的顶点和法线等信息,所以单独处理材质。
代码如下:
mesh.h
#pragma once
#ifndef MESH_H
#define MESH_H
#include <glad/glad.h> // holds all OpenGL type declarations
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "shader_m.h"
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
using namespace std;
struct Vertex {
// position
glm::vec3 Position;
// normal
glm::vec3 Normal;
// texCoords
glm::vec2 TexCoords;
// tangent
glm::vec3 Tangent;
// bitangent
glm::vec3 Bitangent;
};
struct Material {
//材质颜色光照
glm::vec4 Ka;
//漫反射
glm::vec4 Kd;
//镜反射
glm::vec4 Ks;
};
struct Texture {
unsigned int id;
string type;
string path;
};
class Mesh {
public:
/* Mesh Data */
vector<Vertex> vertices;
vector<unsigned int> indices;
vector<Texture> textures;
Material mats;
unsigned int VAO;
unsigned int uniformBlockIndex;
/* Functions */
// constructor
Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures, Material mat)
{
this->vertices = vertices;
this->indices = indices;
this->textures = textures;
this->mats = mat;
// now that we have all the required data, set the vertex buffers and its attribute pointers.
setupMesh();
}
// render the mesh
void Draw(Shader shader)
{
// bind appropriate textures
unsigned int diffuseNr = 1;
unsigned int specularNr = 1;
unsigned int normalNr = 1;
unsigned int heightNr = 1;
for (unsigned int i = 0; i < textures.size(); i++)
{
glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding
// retrieve texture number (the N in diffuse_textureN)
string number;
string name = textures[i].type;
if (name == "texture_diffuse")
number = std::to_string(diffuseNr++);
else if (name == "texture_specular")
number = std::to_string(specularNr++); // transfer unsigned int to stream
else if (name == "texture_normal")
number = std::to_string(normalNr++); // transfer unsigned int to stream
else if (name == "texture_height")
number = std::to_string(heightNr++); // transfer unsigned int to stream
// now set the sampler to the correct texture unit
glUniform1i(glGetUniformLocation(shader.ID, (name + number).c_str()), i);
// and finally bind the texture
glBindTexture(GL_TE