OpenGL学习之实例化

实例化学习参考于LearnOpenGL-实例化网站,本次试验是基于Assimp这一节的纳米铠甲机器人为例,来简单实现实例化的绘制。
下面摘自实例化的原文,作用很重要颜色标注:

像这样绘制出你模型的其他实例,多次绘制之后,很快将达到一个瓶颈,这是因为你glDrawArrays或glDrawElements这样的函数(Draw call)过多。这样渲染顶点数据,会明显降低执行效率,这是因为OpenGL在它可以绘制你的顶点数据之前必须做一些准备工作(比如告诉GPU从哪个缓冲读取数据,以及在哪里找到顶点属性,所有这些都会使CPU到GPU的总线变慢)。所以即使渲染顶点超快,而多次给你的GPU下达这样的渲染命令却未必。 如果我们能够将数据一次发送给GPU,就会更方便,然后告诉OpenGL使用一个绘制函数,将这些数据绘制为多个物体。这就是我们将要展开讨论的实例化(Instancing)。 实例化是一种只调用一次渲染函数却能绘制出很多物体的技术,它节省渲染物体时从CPU到GPU的通信时间,而且只需做一次即可。要使用实例化渲染,我们必须将glDrawArrays和glDrawElements各自改为glDrawArraysInstanced和glDrawElementsInstanced。这些用于实例化的函数版本需要设置一个额外的参数,叫做实例数量(Instance Count),它设置我们打算渲染实例的数量。这样我们就只需要把所有需要的数据发送给GPU一次就行了,然后告诉GPU它该如何使用一个函数来绘制所有这些实例 。
首先看看着色器里面的代码
Instance.vs

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal
layout (location = 2) in vec2 texCoords;
out vec2 TexCoords;
out vec3 fragPosition;
out vec3 Normal;
uniform mat4 model;      //模型矩阵
uniform vec2 offsets[25]; //索引数为绘制总数由外部传入偏移数据
layout (std140) uniform Matrices
{
	mat4 projection;
	mat4 view;
};
void main()
{
	vec2 offset = offsets[gl_InstanceID];
    gl_Position = projection * view * model * vec4(position.x + offset.x,position.y,position.z + offset.y, 1.0f);
	fragPosition = vec3(model * vec4(position, 1.0f));
    Normal = mat3(transpose(inverse(model))) * normal;
    TexCoords = texCoords;
}

 

而片段着色器没有什么变化,再次忽略。
下面看看如何提供位置的偏移数据?
首先在你的初始化函数里面准备位置偏移数据,代码如下:

     std::vector translations;
     int index = 0;
     GLfloat offset = 5.0f;
     GLint instCount = 5;
     for (GLint y = -instCount; y < instCount; y += 2)
     {
         for (GLint x = -instCount; x < instCount; x += 2)
         {
             glm::vec2 translation;
             translation.x = (GLfloat)x*5  + offset;
             translation.y = (GLfloat)y*5  + offset;
             translations.push_back(translation);
         }
     }

     for (int i = 0; i < translations.size(); i++)
     {
         std::stringstream ss;
         std::string index;
         ss << i;
         index = i;
         index = ss.str();
         std::string uniformName = "offsets[" + index + "]";
         m_modelShader->setShaderUniform(m_modelShader->getProgram(), uniformName, translations.at(i));
     }

最后在你的绘制函数里面调用实例绘制函数,代码如下:,(记得把你之前的将glDrawArrays和glDrawElements各自改为glDrawArraysInstanced和glDrawElementsInstanced)

    glBindVertexArray(m_VAO);
    //实例个数
    GLuint amount = 25;
    //绘制实例
    glDrawElementsInstanced(GL_TRIANGLES, m_indices.size(), GL_UNSIGNED_INT, 0, amount);
  //  glDrawElements(GL_TRIANGLES, m_indices.size(), GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

好了,最后贴出效果的图片:

简单的实例化绘制,就此位置,帧率也没有丝毫变化。

你可能感兴趣的:(OpenGL)