OpenGL基础27:网格

shsshs 2020-06-25

一、网格

网格(Mesh):一个模型会由几个子模型/形状组合拼接而成,而模型中的那些子模型/形状就是一个网格,一个网格在OpenGL中是绘制物体的最小单位

从字面上的意思来看就是下面这个东西:

OpenGL基础27:网格OpenGL基础27:网格

其实差不多,如果你是游戏开放相关的工作者,又或者了解过图形学,应该对网格(Mesh)这个词很熟悉,大概印象是下面这样的:

OpenGL基础27:网格OpenGL基础27:网格

理解的没问题的话,网格就是上面这些东东,不过对于大多数游戏开发者更喜欢用Mesh这个词而并非网格,在Assimp里面

  • 一个Mesh对象本身包含渲染所需的所有相关数据,比如顶点位置、法线向量、纹理坐标、面片及物体的材质
  • 一个Mesh会包含多个面片(Face)。一个面片表示渲染中的一个最基本的形状单位,即图元(基本图元有点、线、三角面片、矩形面片),其记录了一个图元的顶点索引,通过这个索引,可以寻找到对应的顶点位置数据
  • 一个Mesh还会包含一个材质(Material)对象用于指定物体的一些材质属性。如颜色、纹理贴图

二、Mesh类

和之前的Camera类和Shader类一样,实现一个Mesh类,以满足:

  • 只需要将顶点数据和纹理数据传入,便可自动配置正确的缓冲,并通过顶点属性指针定义顶点着色器的布局
  • 提供Draw()方法,完成纹理的绑定和绘制
#ifndef MESH_H
#define MESH_H
#include<vector>
#include<string>
#include<fstream>
#include<sstream>
#include"Shader.h"
#include<opengl/glew.h>
#include<glm/glm.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include<assimp/Importer.hpp>
#include<assimp/scene.h>
#include<assimp/postprocess.h>
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<Vertex> vertices;
        vector<GLuint> indices;             //索引
        vector<Texture> textures;
        Mesh(vector<Vertex> vertices, vector<GLuint> indices, vector<Texture> 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];

 推荐:电脑怎么录屏,电脑录屏的方法

苹果id密码忘了怎么办,如何找回苹果id密码

中国名胜古迹简介,中国十大风景名胜古迹

相关推荐