(我在https://gamedev.stackexchange.com/questions/133399/can-i-map-uniform-variables中问了同样的问题,到目前为止没有答案)。
我真的只是从GLSL开始,我正在使用python而我实际上无法运行330(Debian上的intel hd3000)所以我使用130,到目前为止还可以。
我首先开始使用in
并且不知道uniform
变量,我使用了一段代码,允许我在用户空间内存中映射in变量,然后将其映射到使用ctypes的numpy数组。
在我的循环中,我打电话:
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glDrawArrays(GL_TRIANGLES, 0, 3)
之后,我将与顶点关联的变量映射回我的用户空间:
def map_buffer(size):
func = ctypes.pythonapi.PyBuffer_FromReadWriteMemory
func.restype = ctypes.py_object
p = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE)
buffer = func(ctypes.c_void_p(p), size)
array = np.frombuffer(buffer, dtype='float32')
return array
这段代码基本上只使用glMapBuffer
返回的指针,并创建一个缓冲区从该位置开始的数组。
我可以毫无问题地操纵该数组numpy
然后取消映射,以便下一个循环看到变化,到目前为止只是旋转三角形的顶点。
现在,我的一系列问题很简单:
uniform
这不是吗?uniform
变量,我真的很喜欢使用numpy
进行操作,如何将制服的内存映射到我的用户空间?in
代替uniform
是否会对性能造成任何影响? (除了在python上映射的自然开销之外,因为在这个过程中没有分配内存我觉得已经足够了)。据我所知,从着色器的角度来看,uniform是常量或不可变的,因此只能在着色器之外进行修改。这就是我到目前为止使用in
变量的方式。因此,似乎更喜欢uniform
而不是in
,但我更喜欢in
的API而不是uniform
的API,除非出现性能问题,我会继续使用in
1}}。
再见。
答案 0 :(得分:3)
我将分别处理你问题的不同部分。
"映射制服"
您可以将GL缓冲区对象用作统一值的后端stoarge。这个概念称为Uniform Buffer Object (UBO),从OpenGL 3.1开始就可以使用。
关键的想法是你可以在GLSL着色器代码中的所谓interface blocks中使用统一变量,就像这样
layout(std140) uniform some_block_name {
vec4 foo;
float bar;
mat4 baz;
}
请注意,您可以在单个着色器中使用不同的统一块,并且每个块都可以从不同的缓冲区对象(必须在CPU端绑定)中获取数据。
如果你没有指定任何layout
,GL会按照它认为合适的方式在缓冲区中布局数据,你基本上必须查询每个变量的字节偏移量(就像你有查询普通制服的位置)。但是,如我在示例中所做的那样使用std(140)
布局将使用一些标准化的对齐规则,以便您可以直接计算每个成员的偏移量,而无需查询它,并且具有不会查询的优点取决于GL实施。确切的对齐规则可以在OpenGL规范中找到,我也确实重现了它们in this answer here on SO。
制服与顶点属性
据我所知,从着色器的角度来看,uniform是常量或不可变的,因此只能在着色器之外进行修改。这就是我到目前为止使用
in
变量的方式。因此,uniform
优于in
似乎很自然。
您应该在一些抽象的管道阶段中考虑这一点,而是以单个着色器调用为中心。
顶点着色器的in
个放置是所谓的顶点属性。这些是每个顶点(或至少可以)每个顶点变化的值。另一方面,制服在整个绘制调用期间保持常量 - 这意味着顶点属性是每个调用不同的数据,而制服在它们之间共享。
因此,如何使用它是将所有顶点数据放入顶点属性。并且你为计算提供了一些额外的参数,但它们并不依赖于精确的顶点,而是制服。
我可以毫无问题地使用numpy操作该数组,然后取消映射,以便下一个循环可以看到更改,到目前为止只是旋转三角形的顶点。
目前还不清楚你最终想要实现什么,但你在这里做的不是如何使用渲染管道。
这个想法是你的模型是不变的,只有变换才会发生变化。所以你将它上传到一个缓冲区,每次你绘制它时让GPU 重新转换。通常,我们使用4x4矩阵和线性代数,所以我们只是为绘制调用更新一些统一矩阵,并且永远不会重新指定几何(除非我们实际想要变形 - 在CPU上,我们通常不会# 39; t想要。)
然而,随着可编程GPU灵活性的提高,制服和顶点属性之间的界限开始模糊。从概念上讲,您现在可以执行类似
的操作uniform vec3 vertexPosition[someBigNumber];
// ...
vec3 pos = vertexPosition[gl_VertexID]
gl_Position = some_matrix * vec4(pos, 1.0);
这样,你可以解决顶点属性的一些限制(即有16个属性槽,每个只有vec4),但是根据GPU,你可能会或者可能不会以性能的形式支付一些价格由于间接的进一步层面的惩罚。一些GPU确实有特殊的硬件单元,可以优化获取顶点属性(允许它更好地调度顶点着色器调用)。另请注意,统一内存本身通常仅限于2kB,UBO限制为64k。但是,您可以将缓冲区对象类型用于此类用法(例如texture buffer objects或shader storage buffer objects)。
您的实际问题
- 似乎我应该使用制服来解决这个问题
醇>
嗯,目前尚不清楚你究竟想要达到的目的,所以我无法给出任何明确的答案。在正常情况下,顶点的位置被视为顶点属性,因此您不应该使用制服。
- 如果是这样,我无法看到如何映射统一变量,我真的很喜欢使用numpy进行操作,如何将制服的内存映射到我的用户空间?
醇>
您可以使用UBO。
- 使用而不是统一是否有任何性能损失? (除了在python上映射的自然开销之外,因为在这个过程中没有分配内存我觉得已经足够了)。
醇>
这在很大程度上取决于。关于您的实际用例和数据访问模式。在GPU上。在你的实际工作量上 - 即顶点着色器可能不是瓶颈(在每次绘制调用时只绘制一个三角形的情况下肯定不是),所以即使在VS中存在一些概念性能差异,可能对实际渲染性能没有任何影响。
我仍然说使用每顶点数据的顶点属性应该至少与使用制服一样快或更快,至少在正常使用情况下是这样。