C++ Vulkan中的动态顶点缓冲区格式设置

C++ Vulkan中的动态顶点缓冲区格式设置,c++,opengl,vulkan,opengl-4,C++,Opengl,Vulkan,Opengl 4,我目前的任务是将OpenGL代码库转换为Vulkan,但现在遇到了一个问题,即该代码如何使用顶点缓冲区,因为它非常动态地改变布局,将其作为一个大的帧数组来处理 为了渲染其动画模型,它设置了一个大缓冲区,其中包含整个模型的所有数据,并调用以下函数进行设置: void SetupVertexBufferFormat(unsigned int frame1, unsigned int frame2) { glVertexAttribPointer(PositionAttr, 3, GL_FLO

我目前的任务是将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后端一起工作


有没有办法解决这个问题,或者一些复杂的管道管理是唯一的选择?

您似乎将顶点格式与顶点缓冲区绑定混为一谈
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) },
};
std::vector bindingDescriptions={
{0,sizeof(顶点),vk::VertexInputRate::eVertex},
{1,sizeof(顶点),vk::VertexInputRate::eVertex}
};
std::vector attributeDescriptions={
{PositionAttr,0,vk::Format::eR32G32B32Sfloat,offsetof(顶点,x)},
{TexcoordAttr,0,vk::Format::er32g32float,offsetof(顶点,u)},
{NormalAttr,0,vk::Format::ea2b1010r10snrompack32,offsetof(顶点,packedNormal)},
{Position2Attr,1,vk::Format::eR32G32B32Sfloat,offsetof(顶点,x)},
{Normal2Attr,1,vk::Format::ea2b1010r10snormpack32,offsetof(顶点,packedNormal)},
};

您似乎将顶点格式与顶点缓冲区绑定混为一谈
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) },
};
std::vector bindingDescriptions={
{0,sizeof(顶点),vk::VertexInputRate::eVertex},
{1,sizeof(顶点),vk::VertexInputRate::eVertex}
};
std::vector attributeDescriptions={
{PositionAttr,0,vk::Format::eR32G32B32Sfloat,offsetof(顶点,x)},
{TexcoordAttr,0,vk::Format::er32g32float,offsetof(顶点,u)},
{NormalAttr,0,vk::Format::ea2b1010r10snrompack32,offsetof(顶点,packedNormal)},
{Position2Attr,1,vk::Format::eR32G32B32Sfloat,offsetof(顶点,x)},
{Normal2Attr,1,vk::Format::ea2b1010r10snormpack32,offsetof(顶点,packedNormal)},
};

来扩展杰里科的答案

如果使用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的状态。

来扩展杰里科的答案

如果使用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的状态