如何使用来自 PyGLM 的数据初始化缓冲区对象的数据存储?

How to initialize a buffer object's data store with data from PyGLM?

我用PyGLM and PyOpenGL

我指定了以下 Shader Storage Buffer in the Vertex Shader:

layout(std430, binding = 1) buffer MVP
{
    mat4 u_proj;
    mat4 u_view;
    mat4 u_model;
} mvp_data;

我已经初始化了模型、视图和投影矩阵:

model = glm.mat4(1)
view  = glm.lookAt(glm.vec3(0,-3,0), glm.vec3(0,0,0), glm.vec3(0,0,1))
proj  = glm.perspective(glm.radians(90), self.__vp_size[0]/self.__vp_size[1], 0.1, 100)

如何使用 glBufferData(或 glNamedBufferData

创建和初始化缓冲区对象的数据存储
ssbo = glGenBuffers( 1 )
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo )
glBufferData(GL_SHADER_STORAGE_BUFFER, 3*16*4, ???, GL_STATIC_DRAW )

分别由glBufferSubData(或glNamedBufferSubData)初始化

ssbo = glGenBuffers( 1 )
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo )
glBufferData(GL_SHADER_STORAGE_BUFFER, 3*16*4, None, GL_STATIC_DRAW )
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, ???, ???);

由于 SSBO 包含 3(紧密包装)mat4,缓冲区的大小为 3 * 16 * 4(3 个 4x4 矩阵,元素数据类型为 float)。
所以缓冲区的初始化可以通过一个NumPy数组来完成。
但是如何将 PyGLM 矩阵有效地分配给 NumPy 数组?

buffer_data = numpy.zeros(3*16, dtype=numpy.float32)

??? buffer_data = model, view, proj

glBufferData(GL_SHADER_STORAGE_BUFFER, buffer_data.nbytes, buffer_data, GL_STATIC_DRAW)

或者是否有更有效的解决方案,无需将数据复制到 NumPy 数组?

最后我自己找到了解决方案。

需要注意的是,Shader Storage Buffer 由 344=48 个紧密排列的浮点数组成。

PyGlm provides the handy functions glm.value_ptr and glm.sizeof. glm.value_ptr corresponds to the glm::value_ptr. glm.sizeof works like c++ sizeof operator 用于 glm 数据类型。

这个函数可以与glBufferSubData wrapping of PyOpenGL一起使用来更新缓冲区数据:

glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0,                      glm.sizeof(glm.mat4), glm.value_ptr(model))
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 1*glm.sizeof(glm.mat4), glm.sizeof(glm.mat4), glm.value_ptr(view))
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 2*glm.sizeof(glm.mat4), glm.sizeof(glm.mat4), glm.value_ptr(proj))

类型 glm.mat4 的对象可以分配给形状 (4, 4) 类型 np.float32numpy.array。所以这 3 个矩阵可以分配给形状为 (3, 4, 4):

numpy.array 的元素
buffer_data = np.empty([3, 4, 4], dtype=np.float32)
buffer_data[0] = model
buffer_data[1] = view
buffer_data[2] = proj

这个数组可用于一次更新整个缓冲区数据:

buffer_size = buffer_data.size * buffer_data.itemsize
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, buffer_size, buffer_data)

或者对于缓冲区对象数据存储的初始glBufferData创建和初始化:

glBufferData(GL_SHADER_STORAGE_BUFFER, buffer_data, GL_DYNAMIC_DRAW)

从 PyGLM 版本 2.0.0 开始,有一种更简单的方法来 这个。见 Using Arrays:

PyGLM's array type was introduced in version 2.0.0 to reduce the likelihood of requiring users to also use numpy besides glm. It's mainly intended to provide a way of passing multiple glm type instances (such as vectors) to external C functions (such as glBufferData).

buffer_data = glm.array(model, view, proj)
glBufferData(GL_SHADER_STORAGE_BUFFER, buffer_data.nbytes, buffer_data.ptr, GL_STATIC_DRAW)

有一种方法可以一次更新所有数据,而无需使用 numpy。

在 PyGLM 文档中,它说 (https://github.com/Zuzu-Typ/PyGLM/wiki/Using-arrays):

PyGLM's array type was introduced in version 2.0.0 to reduce the likelihood of requiring users to also use numpy besides glm. It's mainly intended to provide a way of passing multiple glm type instances (such as vectors) to external C functions (such as glBufferData).

你可以做的是像这样用 glm.array 包裹矩阵:

buffer_data = glm.array(model, view, proj)

然后像这样更新数据:

glBufferData(GL_SHADER_STORAGE_BUFFER, buffer_data.nbytes, buffer_data.ptr, GL_STATIC_DRAW)

注意:nbytesptr 内置于 glm.array 的成员中,您使用它们代替 glm.sizeofglm.value_ptr