实例化
对于在同一场景中使用相同顶点数据的对象(如草地中的草),可以使用实例化(Instancing)技术,用一个绘制函数让OpenGL绘制多个物体,而非循环(Drawcall: N->1)。
实例化技术本质上是减少了数据从CPU到GPU的传输次数。
实例化这项技术能够让我们使用一个渲染调用来绘制多个物体,来节省每次绘制物体时CPU -> GPU的通信,它只需要一次即可。
使用 glDrawArraysInstanced 和 glDrawElementsInstanced 就可以。这些渲染函数的实例化版本需要一个额外的参数,叫做实例数量(Instance Count),它能够设置我们需要渲染的实例个数。
顶点着色器内建变量 gl_InstanceID 保存了当前渲染图元所在是实例索引。借助该变量,我们可以改变其位置,渲染方式等。从0开始,当渲染第43个实例时,该变量为42
索引一个包含100个偏移向量的uniform数组,将偏移值加到每个实例化的四边形上。最终的结果是一个排列整齐的四边形网格:
//vs
#version 330 core
out vec4 FragColor;
in vec3 fColor;
void main()
{
FragColor = vec4(fColor, 1.0);
}
//fs
#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec3 aColor;
out vec3 fColor;
uniform vec2 offsets[100];
void main()
{
vec2 offset = offsets[gl_InstanceID];
gl_Position = vec4(aPos + offset, 0.0, 1.0);
fColor = aColor;
}
//.cpp
//定义数组
glm::vec2 translations[100];
int index = 0;
float offset = 0.1f;
for(int y = -10; y < 10; y += 2)
{
for(int x = -10; x < 10; x += 2)
{
glm::vec2 translation;
translation.x = (float)x / 10.0f + offset;
translation.y = (float)y / 10.0f + offset;
translations[index++] = translation;
}
}
//将数组转移到顶点着色器的uniform中
shader.use();
for(unsigned int i = 0; i < 100; i++)
{
stringstream ss;
string index;
ss << i;
index = ss.str();
shader.setVec2(("offsets[" + index + "]").c_str(), translations[i]);
}
//绘制
glBindVertexArray(quadVAO);
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 100);
实例化数组
实例化数组(Instanced Array),它被定义为一个顶点属性(能够让