OpenGL foundation 27: Grid

Keywords: Attribute

1, Grid

Mesh: a model is composed of several sub models / shapes. Those sub models / shapes in the model are a mesh. A mesh is the smallest unit of drawing objects in OpenGL

Literally, it means the following:

In fact, if you are a game opening related worker or have known graphics, you should be familiar with the word mesh. The general impression is as follows:

It's OK to understand that grid is the above things. However, most game developers prefer to use the word Mesh instead of grid in Assimp

  • A Mesh object itself contains all the relevant data needed for rendering, such as vertex position, normal vector, texture coordinates, patch and object material
  • A Mesh can contain multiple faces. A patch represents one of the most basic shape units in rendering, that is, the entity (the basic entity has points, lines, triangular patches, rectangular patches), which records the vertex index of an entity. Through this index, the corresponding vertex position data can be found
  • A Mesh also contains a Material object to assign some Material properties to the object. Such as color, texture map

 

2, Mesh class

Like the previous Camera class and Shader class, implement a Mesh class to meet the following requirements:

  • Only the vertex data and texture data need to be passed in, the correct buffer can be automatically configured, and the layout of the vertex shader can be defined through the vertex attribute pointer
  • Provide Draw() method to complete the binding and painting of texture
#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;         //vertex
    glm::vec3 Normal;           //normal
    glm::vec2 TexCoords;        //Mapping
};

struct Texture
{
    GLuint id;
    string type;                //Map type: diffuse map or specular map (followed by normal map, dislocation map, etc.)
    aiString path;              //Map path
};

class Mesh
{
    public:

        vector<Vertex> vertices;
        vector<GLuint> indices;             //Indexes
        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);
                //In this way, the texture name in the shader must have a corresponding specification, such as "texture"_ Diffuse3 represents the third diffuse map
                //It's not the only way. It's the best way to understand / write
                glBindTexture(GL_TEXTURE_2D, this->textures[i].id);
            }

            glUniform1f(glGetUniformLocation(shader.Program, "material.shininess"), 16.0f);     //Temporarily write dead reflectance, also configurable
            glBindVertexArray(this->VAO);
            glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0);             //EBO drawing
            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);
            //Don't forget that memory in struct is continuous
            //offsetof(): get the offset of the structure property
            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

It's all the previous knowledge, equivalent to moving the code from the main program

Don't forget the memory layout of 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];

Posted by eideticmnemonic on Thu, 25 Jun 2020 01:53:52 -0700