美文网首页OpenGL学习笔记
【五十八,模型加载-5 网格(Mesh)实现】

【五十八,模型加载-5 网格(Mesh)实现】

作者: Woodlouse | 来源:发表于2020-01-05 17:37 被阅读0次

    网格构造函数

    网格构造函数处理的事情很简单:使用构造函数的参数设置对应类成员的值,实现如下:

    Mesh(vector<Vertex> vertices, vector<GLuint> indices, vector<Texture> textures)
    {
        this->vertices = vertices;
        this->indices = indices;
        this->textures = textures;
    
        this->setupMesh();
    }
    

    初始化(SetupMesh)函数

    在构造函数处理完毕后,我们有一大列的网格数据用于渲染了,需要设置合适的缓冲,通过顶点属性指针定义顶点着色器的布局,如下:

    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); 
        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);
    }
    

    C++的结构体有一个重要的属性,那就是在内存中它们是连续的。如果我们用结构体表示一列数据,这个结构体只包含结构体的连续的变量,它就会直接转变为一个float(实际上是byte)数组,我们就能用于一个数组缓冲(array buffer)中了。

    渲染(Draw)函数

    在真正渲染前我们需要绑定合适的纹理,然后调glDrawElements
    问题:不知道这个网格有多少纹理以及它们是什么类型的,如何在着色器中设置纹理单元和采样器?
    命名惯例:每个diffuse纹理被命名为texture_diffuseN,每个specular纹理应该被命名为texture_specularN。N是一个从1到纹理才抢其允许使用的最大值之间的数。可以说,在一个网格中我们有3个diffuse纹理和2个specular纹理,它们的纹理采样器应该这样被调用:

    uniform sampler2D texture_diffuse1;
    uniform sampler2D texture_diffuse2;
    uniform sampler2D texture_diffuse3;
    uniform sampler2D texture_specular1;
    uniform sampler2D texture_specular2;
    

    最后的绘制代码如下:

    void Draw(Shader shader) 
    {
        GLuint diffuseNr = 1;
        GLuint specularNr = 1;
        for(GLuint i = 0; i < this->textures.size(); i++)
        {
            glActiveTexture(GL_TEXTURE0 + i); // 在绑定纹理前需要激活适当的纹理单元
            // 检索纹理序列号 (N in diffuse_textureN)
            stringstream ss;
            string number;
            string name = this->textures[i].type;
            if(name == "texture_diffuse")
                ss << diffuseNr++; // 将GLuin输入到string stream
            else if(name == "texture_specular")
                ss << specularNr++; // 将GLuin输入到string stream
            number = ss.str(); 
    
            glUniform1f(glGetUniformLocation(shader.Program, ("material." + name + number).c_str()), i);
            glBindTexture(GL_TEXTURE_2D, this->textures[i].id);
        }
        glActiveTexture(GL_TEXTURE0);
    
        // 绘制Mesh
        glBindVertexArray(this->VAO);
        glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
    }
    

    相关文章

      网友评论

        本文标题:【五十八,模型加载-5 网格(Mesh)实现】

        本文链接:https://www.haomeiwen.com/subject/mkoaoctx.html