参考:
https://learnopenglcn.github.io/03%20Model%20Loading/02%20Mesh/
…
…
…
…
使用Assimp,我们可以加载不同的模型到程序中,但是载入后它们都被储存为Assimp的数据结构。我们最终仍要将这些数据转换为OpenGL能够理解的格式,这样才能渲染这个物体.
网格(Mesh)代表的是单个的可绘制实体,我们现在先来定义一个我们自己的网格类.
…
…
一个网格应该至少需要一系列的顶点,每个顶点包含一个位置向量、一个法向量和一个纹理坐标向量。
一个网格还应该包含用于索引绘制的索引以及纹理形式的材质数据(漫反射/镜面光贴图
有了一个网格类的最低需求,我们可以在OpenGL中定义一个顶点了:
struct Vertex {
glm::vec3 Position;
glm::vec3 Normal;
glm::vec2 TexCoords;
};
将所有需要的向量储存到一个叫做Vertex的结构体中,我们可以用它来索引每个顶点属性。
除了Vertex结构体之外,我们还需要将纹理数据整理到一个Texture结构体中.
struct Texture
{
unsigned int id;
string type;
};
储存了纹理的id以及它的类型,比如是漫反射贴图或者是镜面光贴图
定义网格类的结构:
class Mesh {
public:
/* 网格数据 */
vector<Vertex> vertices;
vector<unsigned int> indices;
vector<Texture> textures;
/* 函数 */
Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures);
void Draw(Shader shader);
private:
/* 渲染数据 */
unsigned int VAO, VBO, EBO;
/* 函数 */
void setupMesh();
};
构造器中,所有必须的数据赋予了网格,在setupMesh函数中初始化缓冲,并最终使用Draw函数来绘制网格
注意我们将一个着色器传入了Draw函数中,将着色器传入网格类中可以让我们在绘制之前设置一些uniform(像是链接采样器到纹理单元)。
…
…
构造器的内容非常易于理解。我们只需要使用构造器的参数设置类的公有变量就可以了。我们在构造器中还调用了setupMesh函数:
Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures)
{
this->vertices = vertices;
this->indices = indices;
this->textures = textures;
setupMesh();
}
初始化
有了构造器,我们现在有一大列的网格数据用于渲染。在此之前我们还必须配置正确的缓冲,并通过顶点属性指针定义顶点着色器的布局,但我们这次会稍微有一点变动,使用结构体中的顶点数据:
void setupMesh()
{
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() *<