【问题标题】:Dynamic vertex buffer format setup in VulkanVulkan 中的动态顶点缓冲区格式设置
【发布时间】:2018-10-27 09:33:54
【问题描述】:

我目前的任务是将 OpenGL 代码库转换为 Vulkan,但现在偶然发现了此代码如何使用顶点缓冲区的问题,因为它非常动态地改变布局以将其作为大量帧来处理。

为了渲染其动画模型,它设置了一个包含整个模型所有数据的大缓冲区,并调用以下函数进行设置:

void SetupVertexBufferFormat(unsigned int frame1, unsigned int frame2)
{
    glVertexAttribPointer(PositionAttr, 3, GL_FLOAT, false, sizeof(Vertex), &vNull[frame1].x);
    glVertexAttribPointer(TexcoordAttr, 2, GL_FLOAT, false, sizeof(Vertex), &vNull[frame1].u);
    glVertexAttribPointer(Position2Attr, 3, GL_FLOAT, false, sizeof(Vertex), &vNull[frame2].x);
    glVertexAttribPointer(NormalAttr, 4, GL_INT_2_10_10_10_REV, true, sizeof(Vertex), &vNull[frame1].packedNormal);
    glVertexAttribPointer(Normal2Attr, 4, GL_INT_2_10_10_10_REV, true, sizeof(Vertex), &vNull[frame2].packedNormal);
}

在 OpenGL 上这一切都很好,但在 Vulkan 上,顶点缓冲区布局是管道对象的一部分!这意味着移植设置需要每帧创建和销毁多个管道,因为 frame1 和 frame2 值可能几乎是随机组合的。

不能做的是改变缓冲区的内容,这是由前端生成的,因为它仍然需要与现有的 OpenGL 后端一起工作。

有什么办法可以绕过它,还是这里唯一的选择是一些复杂的管道管理?

【问题讨论】:

    标签: c++ opengl vulkan opengl-4


    【解决方案1】:

    您似乎将顶点格式与顶点缓冲区绑定混为一谈。 glVertexAttrib 将两者结合在一个调用中,但您似乎有一个一致的顶点格式,它由两个绑定组成,一个具有 3 个属性,第二个具有 2 个属性。

    查看一些关于 OpenGL 中单独顶点格式的教程,并尝试重构您的 GL 后端以使用它。等效的 Vulkan 管道设置应该会变得更加明显。

    对应于 Ratchet 的 GL 调用的 Vulkan 顶点绑定和属性描述应如下所示

    std::vector<vk::VertexInputBindingDescription> bindingDescriptions = { 
        { 0, sizeof(Vertex), vk::VertexInputRate::eVertex },
        { 1, sizeof(Vertex), vk::VertexInputRate::eVertex }
    };
    
    std::vector<vk::VertexInputAttributeDescription> attributeDescriptions = {
        { PositionAttr, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, x) },
        { TexcoordAttr, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, u) },
        { NormalAttr, 0, vk::Format::eA2B10G10R10SnormPack32, offsetof(Vertex, packedNormal) },
        { Position2Attr, 1, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, x) },
        { Normal2Attr, 1, vk::Format::eA2B10G10R10SnormPack32, offsetof(Vertex, packedNormal) },
    };
    

    【讨论】:

      【解决方案2】:

      扩展 JHerico 的答案。

      如果你使用来自 opengl 的单独顶点属性,你会得到这种形式:

      glVertexAttribFormat( PositionAttr,  3, GL_FLOAT, false, offsetof(Vertex, x));
      glVertexAttribBinding(PositionAttr,  1);
      glVertexAttribFormat( TexcoordAttr,  2, GL_FLOAT, false, offsetof(Vertex, u));
      glVertexAttribBinding(TexcoordAttr,  1);
      glVertexAttribFormat( NormalAttr,    4, GL_INT_2_10_10_10_REV, true, offsetof(Vertex, packedNormal));
      glVertexAttribBinding(NormalAttr,    1);
      
      glVertexAttribFormat( Position2Attr, 3, GL_FLOAT, false, offsetof(Vertex, x));
      glVertexAttribBinding(Position2Attr, 2);
      glVertexAttribFormat( Normal2Attr,   4, GL_INT_2_10_10_10_REV, true, offsetof(Vertex, packedNormal));
      glVertexAttribBinding(Normal2Attr,   2);
      

      然后在渲染时将绑定 1 的偏移量设置为第 1 帧的偏移量,将绑定 2 的偏移量设置为第 2 帧的偏移量。

      void SetupVertexBufferFormat(unsigned int frame1, unsigned int frame2) {
          glBindVertexBuffer(1, vbo, &vNull[frame1], sizeof(Vertex));
          glBindVertexBuffer(2, vbo, &vNull[frame2], sizeof(Vertex));
      }
      

      这个你可以直接翻译成vulkan的状态。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多