网格(Mesh):一个模型会由几个子模型/形状组合拼接而成,而模型中的那些子模型/形状就是一个网格,一个网格在OpenGL中是绘制物体的最小单位
从字面上的意思来看就是下面这个东西:
其实差不多,如果你是游戏开放相关的工作者,又或者了解过图形学,应该对网格(Mesh)这个词很熟悉,大概印象是下面这样的:
理解的没问题的话,网格就是上面这些东东,不过对于大多数游戏开发者更喜欢用Mesh这个词而并非网格,在Assimp里面
和之前的Camera类和Shader类一样,实现一个Mesh类,以满足:
#ifndef MESH_H
#define MESH_H
#include
#include
#include
#include
#include"Shader.h"
#include
#include
#include
#include
#include
#include
using namespace std;
struct Vertex
{
glm::vec3 Position; //顶点
glm::vec3 Normal; //法线
glm::vec2 TexCoords; //贴图
};
struct Texture
{
GLuint id;
string type; //贴图类型:漫反射贴图还是镜面贴图(后面还有法线贴图、错位贴图等)
aiString path; //贴图路径
};
class Mesh
{
public:
vector vertices;
vector indices; //索引
vector textures;
Mesh(vector vertices, vector indices, vector textures)
{
this->vertices = vertices;
this->indices = indices;
this->textures = textures;
this->setupMesh();
}
void Draw(Shader shader)
{
GLuint diffuseNr = 1;
GLuint specularNr = 1;
for (GLuint i = 0; i < this->textures.size(); i++)
{
glActiveTexture(GL_TEXTURE0 + i);
stringstream ss;
string name = this->textures[i].type;
if (name == "texture_diffuse")
ss << diffuseNr++;
else if (name == "texture_specular")
ss << specularNr++;
name = name + ss.str();
glUniform1i(glGetUniformLocation(shader.Program, name.c_str()), i);
//这样的话,着色器中的纹理名就必须有一个对应的规范,例如“texture_diffuse3”代表第三个漫反射贴图
//方法不唯一,这是最好理解/最简单的一种规范/写法
glBindTexture(GL_TEXTURE_2D, this->textures[i].id);
}
glUniform1f(glGetUniformLocation(shader.Program, "material.shininess"), 16.0f); //暂时写死反光度,也可配置
glBindVertexArray(this->VAO);
glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0); //EBO绘制
for (GLuint i = 0; i < this->textures.size(); i++)
{
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, 0);
}
glBindVertexArray(0);
}
private:
GLuint VAO, VBO, EBO;
void setupMesh()
{
glGenVertexArrays(1, &this->VAO);
glGenBuffers(1, &this->VBO);
glGenBuffers(1, &this->EBO);
glBindVertexArray(this->VAO);
glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(Vertex), &this->vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(GLuint), &this->indices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
//别忘了struct中内存是连续的
//offsetof():获取结构体属性的偏移量
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Normal));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, TexCoords));
glBindVertexArray(0);
}
};
#endif
都是之前已经掌握的知识,相当于就是从主程序里移一下代码
别忘了struct的内存布局:
Vertex vertex;
vertex.Position = glm::vec3(0.2f, 0.4f, 0.6f);
vertex.Normal = glm::vec3(0.0f, 1.0f, 0.0f);
vertex.TexCoords = glm::vec2(1.0f, 0.0f);
// = [0.2f, 0.4f, 0.6f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f];