实例化时使用的值超过制服所能存储的值
Instancing using more values than uniforms can store
我对OpenGL相当陌生,并试图使用统一数组实现实例化。但是,我试图调用的实例数量大于MAX_UNIFORM_LOCATIONS限制:
QOpenGLShader::link: error: count of uniform locations > MAX_UNIFORM_LOCATIONS(262148 > 98304)error: Too many vertex shader default uniform block components
error: Too many vertex shader uniform components
还有什么方法可以处理这么多的对象?到目前为止,这是我的着色器代码:
layout(location = 0) in vec4 vertex;
layout(location = 1) in vec3 normal;
out vec3 vert;
out vec3 vertNormal;
out vec3 color;
uniform mat4 projMatrix;
uniform mat4 camMatrix;
uniform mat4 worldMatrix;
uniform mat4 myMatrix;
uniform sampler2D sampler;
uniform vec3 positions[262144];
void main() {
vec3 t = vec3(positions[gl_InstanceID].x, positions[gl_InstanceID].y, positions[gl_InstanceID].z);
float val = 0;
mat4 wm = myMatrix * mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, t.x, t.y, t.z, 1) * worldMatrix;
color = vec3(0.4, 1.0, 0);
vert = vec3(wm * vertex);
vertNormal = mat3(transpose(inverse(wm))) * normal;
gl_Position = projMatrix * camMatrix * wm * vertex;
}
如果它应该是重要的,我使用qopenglextrfunctions
有许多方法可以克服统一存储的限制:
例如, ubo;他们通常比非街区制服有更大的存储容量。现在在您的情况下,这可能不起作用,因为存储200,000 vec3
svec4s
将需要比大多数实现允许ubo提供的更多的存储空间。你需要的是无限的存储空间。
实例数组使用实例渲染机制根据实例索引自动获取顶点属性。这需要您的VAO设置工作更改一点。
你的着色器看起来像这样:
layout(location = 0) in vec4 vertex;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec3 position;
out vec3 vert;
out vec3 vertNormal;
out vec3 color;
uniform mat4 projMatrix;
uniform mat4 camMatrix;
uniform mat4 worldMatrix;
uniform mat4 myMatrix;
uniform sampler2D sampler;
void main() {
vec3 t = position;
/*etc*/
}
在这里,着色器本身从不使用gl_InstanceID
。这将根据您的VAO自动发生。
设置代码必须包含以下内容:
glBindBuffer(GL_ARRAY_BUFFER, buffer_containing_instance_data);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0);
glVertexAttribDivisor(2, 1);
此代码假设实例数据位于缓冲区的开头,并且每个值为3个浮点数(紧密打包)。因为你正在使用顶点属性,你可以使用通常的顶点属性压缩技术。
最后一个调用,对glVertexAttribDivisor
是什么告诉OpenGL,它将只移动到数组中的下一个值一次,而不是基于顶点的索引。
注意,通过使用实例化数组,您还可以使用baseInstance
glDraw*调用。OpenGL中的baseInstance
仅受实例化数组的尊重;gl_InstanceID
不受此影响。
缓冲纹理
Buffer textures是线性的,一维纹理,从Buffer对象的存储中获取数据。
你的着色器逻辑看起来像这样:
layout(location = 0) in vec4 vertex;
layout(location = 1) in vec3 normal;
out vec3 vert;
out vec3 vertNormal;
out vec3 color;
uniform mat4 projMatrix;
uniform mat4 camMatrix;
uniform mat4 worldMatrix;
uniform mat4 myMatrix;
uniform sampler2D sampler;
uniform samplerBuffer positions;
void main() {
vec3 t = texelFetch(positions, gl_InstanceID).xyz;
/*etc*/
}
缓冲区纹理只能通过texelFetch
等直接获取纹理的函数来访问。
GL 4中的缓冲纹理。x可以使用一些3通道格式,但早期的GL版本没有给你这个选项(除非有扩展)。因此,您可能希望将数据扩展到4通道值,而不是3通道。
另一个问题是缓冲纹理确实有最大大小限制。所需的最小大小只有64KB,因此实例化的数组方法可能更可靠(因为它没有大小限制)。然而,所有非intel的OpenGL实现都为缓冲区纹理提供了巨大的尺寸。
SSBOs
着色器存储缓冲区对象就像ubo,只是你可以读和写它们。后一种工具对您来说并不重要。这里的主要优势是它们所需的最小OpenGL大小是16M b(并且实现通常根据可用视频内存的顺序返回大小限制)。所以尺寸限制不是问题。
你的着色器代码看起来像这样:
layout(location = 0) in vec4 vertex;
layout(location = 1) in vec3 normal;
out vec3 vert;
out vec3 vertNormal;
out vec3 color;
uniform mat4 projMatrix;
uniform mat4 camMatrix;
uniform mat4 worldMatrix;
uniform mat4 myMatrix;
uniform sampler2D sampler;
buffer PositionSSBO
{
vec4 positions[];
};
void main() {
vec3 t = positions[gl_InstanceID].xyz;
/*etc*/
}
注意,我们在这里显式地使用了vec4
。这是因为你永远不应该在缓冲区支持的接口块(如:UBO/SSBO)中使用vec3
。
在代码中,ssbo的工作方式与ubo非常相似。您可以将它们与glBindBufferRange
绑定使用。
- 将字符串存储在c++中的稳定内存中
- std::原子加载和存储都需要吗
- C++:将控制台输出存储在宏中更好吗
- 使用QProcess执行命令,并将结果存储在QStringList中
- 访问存储在向量C++中的结构的多态成员
- 如何从存储在std::映射中的std::集中删除元素
- 存储模板类型以强制转换回派生<T>
- 类型总是使用其大小存储在内存中吗
- 当字符串存储在变量中时,如何将字符串转换为wchar_t
- 使用无符号字符数组有效存储内存
- 如何在cpp.中使用协议缓冲区存储大缓冲区/数组(char/int)
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- 带结构的二维矢量:如何存储元素
- 添加存储在向量中的大整数的函数出现问题
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 在std::vector上存储带有模板的类实例
- 谷歌测试中的期望值存储在哪里
- 为什么C中的通用链表中存储的数据已损坏
- 在c++中获取两个大int,并将它们存储在数组中
- 实例化时使用的值超过制服所能存储的值