实例化
程序员文章站
2022-03-26 08:49:37
...
文章目录
实例化
诞生
- 如果要对同一物体渲染很多次,每次只是在世界坐标中的位置不一样,要是使用常规的绘制接口glDrawArrays或glDrawElements,那么当绘制的数量达到一定的程度后,就会出现卡帧
- 卡帧的原因:OpenGL在绘制顶点数据之前,需要做很多的准备工作,比如告诉GPU该从哪个缓冲的哪个位置读数据,而且这些过程都是在CPU到GPU的总线上进行的,效率比较低,所以我们常说GPU渲染顶点很快,但命令GPU去渲染不一定快
- 解决办法:将数据一次性发送到GPU,并且只使用一次绘制就让OpenGL利用那些数据绘制出多个物体,这种方法就是实例化
- 总结一下:实例化允许我们使用一次渲染调用来绘制多个物体
使用
- 将glDrawArrays和glDrawElements分别改为glDrawArraysInstanced和glDrawElementsInstanced
- glsl在顶点着色器中定义了一个内置变量gl_InstanceID,在使用实例化渲染时,他从0开始,每渲染一个实例加1
实例化数组
- 使用场景:在使用实例化渲染,往着色器发送uniform类型的数据,并且超过最大发送量时,他的一个代替方案是使用实例化数组
- 实例化数组被定义为一个顶点属性,仅在顶点着色器渲染一个新的实例时才会更新
- glVertexAttribDivisor(index, count) index表示顶点着色器中的某个顶点属性的索引,这个顶点属性的数据使用实例化数组存储的,count表示渲染多少个实例更新一次顶点属性的数据
一个栗子(实例化数组)
- 顶点着色器
#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 offset;
main()
{
gl_Position = vec4(position + offset, 1.0);
}
- 客户端
glm::vec3 offset[10000] = {
glm::vec3(1.0, 1.0, 1.0),
glm::vec3(2.0, 2.0, 2.0),
...
};
unsigned int instanceVBO;//创建一个vbo,将实例化数据发送到vbo中
glGenBuffers(1, &instanceVBO);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * 10000, &offset[0], GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FLASE, 3 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribDivisor(1, 1);//第一个参数表示顶点着色器中变量offset的索引,第二个参数表示每一个实例更新一次
glDrawArraysInstanced(GL_TRIANGLES, 0, 3, 10000);//调用一次绘制函数,实现绘制10000个三角形
上一篇: ASP基础入门第一篇(ASP技术简介)
下一篇: pyopengl全解析-9