OPenGL | 您所在的位置:网站首页 › opengl绘制多个物体 › OPenGL |
简述 多实例渲染是一种连续执行多次相同的渲染命令的方法,并且每个渲染命令所产生的结果都会有轻微的差异。这是一种使用少量API来渲染大量几何体的有效方法。 当一个模型需要创建多个实例时,一般地可以在程序中循环调用glDrawArrays()函数完成多次绘制,这样,顶点着色器对每次输入的顶点运行一次,就会从内存中重复提取一次的数据,绘制多次相当于多次运行OPenGL整个管线。给GPU造成了潜在的处理负担。如果使用实例化方式创建,则只会多次运行几何着色器及以后的渲染管线,而不会运行全部的管线,效率会显著提升。当然,两种方法也可以同时使用。
常见的多实例绘制函数 glDrawArraysInstanced(), glDrawElementsInstanced(), glDrawElementsInstancedBaseVertex()。 voidglDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primCount) 功 能:多实例绘制函数 返回值:void 参数:前三个参数是绘制几何体图元集的参数(与glDrawArrays()中的参数完全相同 primCount参数表示绘制实例的个数) 这个函数是glDrawArrays()的多实例版,这两个函数的参数完全是等价的,只是多了一个primCount参数,用于设置实例化的个数。其他绘制函数也有对应的实例化版本,函数glDrawElements()对应glDrawElementsInstanced(),函数glDrawElementsBaseVertex()对应glDrawElementsInstancedBaseVertex(),它们函数参数相同,只是实例化版的都会多一个参数设置实例化个数。 对于每个实例,在GLSL中的内置变量gl_InstanceID都会递增一次,新的数值会传递到顶点着色器中,以区分不同实例的顶点属性。
实例化实现思路 单纯实例化的实现非常简单,只需要调用上面实例化版本的绘制函数,并设置实例化个数就可以实现。但这样绘制的实例几乎是一摸一样的,包括位置颜色等属性,没有任何实际意义。 因此需要给每个实例都设置自己的属性,比如为每个实例设置不同的位置。
顶点着色器 1.这里的用uniform变量从程序中向实例传递数据,如果需要实例化100个,那么就在顶点着色其中声明一个数组来存储。 uniform vec2 offsets[100]; 2.在原来的位置上进行偏移,根据GLSL中的内置变量gl_InstanceID索引每个实例的属性 gl_Position = vec4(aPos + offset[gl_InstanceID], 0, 1.0); 3.顶点着色器应该是这样的,其他着色器不变。 #version 330 core layout (location = 0) in vec2 aPos; layout (location = 1) in vec3 aColor;
out vec3 fColor; uniform vec2 offsets[100];
void main() { fColor = aColor; gl_Position = vec4(aPos + offsets[gl_InstanceID], 0, 1.0); }; 应用程序 在应用程序中要做的就是准备着色器中要的数据,并传递到着色器中,每个实例需要和数据一一对应。再调用多实例绘制函数就可以完成了。 1.准备数据 要实例化100个就需要准备100分数据,也是一个数组。 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; } } 2.传递数据 准备好数据后需要传到着色器中,应用程序设置uniform数据要有名称索引,所以需要拼接字符串和着色器中的变量意义对应。 for (unsigned int i = 0; i < 100; i++) { std::stringstream ss; std::string index; ss |
CopyRight 2018-2019 实验室设备网 版权所有 |