实例化
在之前我们绘制多个物体都是用for循环去实现,在每个循环里面单独绑定VAO,但是这样的做法会特别消耗性能。使用glDrawArrays或glDrawElements函数告诉GPU去绘制顶点数据会消耗更多的性能,因为OpenGL在绘制顶点数据之前需要做很多准备工作(比如告诉GPU该从哪个缓冲读取数据,从哪寻找顶点属性,而且这些命令都是在相对缓慢的CPU到GPU总线上进行的。所以,即便渲染顶点非常快,命令GPU去渲染就会变得很慢。
实例化就是把数据一次性地发送给GPU,然后只使用一个绘制函数来绘制所有物体,这样可以避免CPU与GPU之间的过多通信,使用实例化渲染,只需要将glDrawArrays和glDrawElements的渲染调用分别改为glDrawArraysInstanced和glDrawElementsInstanced。这些渲染函数的实例化版本需要一个额外的参数:实例数量(Instance Count),它能够设置我们需要渲染的实例个数。这样我们只需要将必须的数据发送到GPU一次,然后使用一次函数调用告诉GPU它应该如何绘制这些实例。GPU将会直接渲染这些实例,而不用不断地与CPU进行通信,从而节省了很多性能。
而为了让每次绘制的物体的位置可以被我们调整,GLSL在顶点着色器中嵌入了一个内建变量:gl_InstanceID。在使用实例化渲染调用时,gl_InstanceID会从0开始,在每个实例被渲染时递增1。因为每个实例都有唯一的ID,我们可以建立一个数组,将ID与位置值对应起来,将每个实例放置在世界的不同位置。
为了体验这个方法,我们去渲染很多个四边形试试。
首先复制一下四边形的顶点和颜色数据:
1 | float quadVertices[] = { |
顶点着色器&片段着色器:
1 |
|
首先,我们要去设置偏移量数组的值:
1 | glm::vec2 translations[100]; |
然后把偏移量存到buffer中:
1 | GLuint instanceVBO; |
最后去设置所有的VAO:
1 | GLuint quadVAO, quadVBO; |
最后画:
1 | myShader->use(); |
就可以用实例化的方法画出这100个四边形: