gpt4 book ai didi

glsl - 如何重复更新单个 Vulkan 渲染 channel 内对象数量的统一数据并使更新同步?

转载 作者:行者123 更新时间:2023-12-03 22:11:18 27 4
gpt4 key购买 nike

我正在尝试将我的 OpenGL 3D 游戏引擎移植到 Vulkan。游戏场景中有大量 3D 对象,每个对象都有自己的属性(模型矩阵、灯光等),并且对象是完全动态的,这意味着在游戏过程中可能会出现一些 3D 对象,也可能会移除一些 3D 对象.使用 OpenGL,我将 3D 对象的属性分组到着色器中的统一缓冲区中(代码简化):


layout(std140, set = 0, binding = 0) uniform object_attrib
{
vec3 light_pos;
vec3 light_color;
mat4 model;
mat4 view_projection;
...
} params;

我现在要做的是为游戏场景中的每个 3D 对象使用这个单一的统一缓冲区,以通过 Vulkan 渲染它们。

我在 begin-render-pass 和 end-render-pass 中使用单个 Vulkan 渲染 channel ,我使用 for-each 循环遍历每个 3D 对象并执行以下操作来渲染它们。请参阅下面的伪代码。

vkBeginCommandBuffer(cmdBuffer, ...);
vkCmdBeginRenderPass(cmdBuffer, ...);
for(object3D obj : scene->objects)
{
// Step 1 - update object's uniform data by memcpy()
_updateUniformBuffer(obj);

// Step 2 - build draw command for this object
// bind vertex buffer, bind index buffer, bind pipeline, ..., draw
_buildDrawCommands(obj);
}
vkCmdEndRenderPass(cmdBuffer, ...);
vkEndCommandBuffer(cmdBuffer, ...);
vkQueueSubmit(...); // Finally, submit the commands to queue to render the scene


显然,我的解决方案将不起作用,因为缓冲区中的所有 Vulkan 命令仅在调用 vkQueueSubmit() 之后才在 GPU 上执行。但是对 _updateUniformBuffer(obj) 的调用(通过 memcpy(...))是与命令记录“交错”的,它会立即执行,因此序列困惑,最后每个对象都不会获得自己的属性。

因此,Vulkan 在单个渲染过程中为每个对象重复正确更新统一缓冲区并确保每个对象获得其正确的属性数据的解决方案可能是什么?

在我发布这个问题之前,我试图考虑以下解决方案,但它们似乎都不是一个好的解决方案:
  • 使用 render-pass-per-object 并使用栅栏来确保一个对象完全渲染,直到我开始渲染下一个对象。如果有 1000 个对象,每帧会有 1000 个渲染 channel ?这是不可能的。
  • 我可以在一个渲染过程中重复提交命令缓冲区吗?我的意思是我在构建一个对象的绘制命令以渲染对象后立即提交命令缓冲区,使用栅栏确保渲染完成,然后转到下一个对象。这将有一个渲染 channel 和 1000 个 vkQueueSubmit() 调用
  • 使用动态统一缓冲区创建一个巨大的统一缓冲区,其中包含 1000 个对象的数据。由于对象编号是动态的,因此难以实现。
  • 使用推送常量?这也是不可能的,因为最大数据大小只有 128 字节。
  • 最佳答案

    因为您正在以制服的形式记录绘制命令及其输入数据,所以对于场景中的所有对象,在它们执行和读取其输入数据之前,没有办法存储所有版本的制服缓冲区分配在某处。 OpenGL ES 驱动程序会为您执行此操作:当您更新制服时,它们会在内部分配新空间,将新制服写入其中,然后更新内部指针,以便下一次调用将使用新的制服数据而不是之前的制服数据。

    在 Vulkan 中,您可以自己做,而您的第三个想法最接近正确的方法。有一些变化,但最直接的一种是:

    创建一个大的 VkBuffer 并将其绑定(bind)到内存。它可能应该足够大以处理典型/平均帧的所有统一数据。从零偏移量开始,对于每次绘制,在当前偏移量处写入新制服,在描述符集中重新绑定(bind) VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC 与指向新制服数据的动态偏移量,然后更新偏移量以便下一次绘制的制服将放置在您刚刚使用的那些之后。

    在每一帧结束时(假设每帧一个命令缓冲区),记住您在缓冲区中的距离,并将其与表示该命令缓冲区完成的事件相关联。该事件将告诉您何时可以覆盖该帧中使用的缓冲区区域。如果在足够的空间再次可用之前您最终需要更多空间来存放制服,您可以创建一个新的 VkBuffer 并开始使用它,最终在其数据停用时恢复到原来的状态。通过这种方式,您可以最终得到一个由多个 VkBuffer 组成的动态大小的统一数据环形缓冲区。

    关于glsl - 如何重复更新单个 Vulkan 渲染 channel 内对象数量的统一数据并使更新同步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54103399/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com