动态精灵管理

Dynamic sprite management

我正在学习 Vulkan。

到目前为止,在我完成的示例程序中,我已经将足够的顶点上传到 GPU 以绘制一个或两个四边形。我还上传了一张图片以显示在四边形上。这一切都非常静态。

我现在有兴趣做一些动态测试——特别是动态创建和修改精灵。我不确定如何去做,所以我希望得到一些关于可能的技术的指示。我正在尝试创建一个玩具 2d 引擎,用于学习目的。

基本上,我不确定在 GPU 上保持顶点数据最新的最佳方法是什么。下面是一个四边形的定义:

struct Vertex2d {
    glm::vec3 mPos;
    glm::vec2 mCoord;
};

// Vertices for one quad.
const std::vector<fmk::Vertex2d> quadVertices = {
    {{-0.5f, -0.5f, 0.0f}, {0.0f, 0.0f}},   // Vert 0: Top left
    {{0.5f, -0.5f, 0.0f},  {1.0f, 0.0f}},   // Vert 1: Top Right
    {{0.5f, 0.5f, 0.0f},   {1.0f, 1.0f}},   // Vert 2: Bottom Right
    {{-0.5f, 0.5f, 0.0f},  {0.0f, 1.0f}},   // Vert 3: Bottom Left
};

const std::vector<uint16_t> quadIndexes = {
    0, 1, 2, 2, 3, 0,
};

顶点数据表示四边形的位置、旋转、比例、纹理坐标。这些属性中的任何一个都可能改变每一帧。此外,每帧都可能创建或销毁新的精灵。

任何有关数据结构、技术、函数或任何其他使用 Vulkan 管理 sprite 的信息的指针都将受到赞赏。

编辑:

我应该补充一点,我正在努力避免在每一帧中强制上传所有顶点。我目前正在尝试实施一种蛮力方法,以便在我了解一个好的解决方案后将其与一个好的解决方案进行比较。

如果你想改变存储在缓冲区中的顶点的位置,你有两个选择:

  • 您从 CPU
  • 上传它们
  • 你在 GPU 上计算它们

没有其他方法可以让数据出现在 GPU 上。您要么传输它,要么生成它。

第一个解决方案是您称之为 brute-force 的解决方案,但在许多情况下您无法避免。一种或另一种方式您必须将数据传输到 GPU,以便它可以将其用于渲染目的。此外,当今 GPU 的传输速率相当高。每秒可以传输几十GB。

第二个选项更程序化,不需要 CPU 和 GPU 之间的数据传输。为此,您可以创建一个公式来根据时间或任何其他参数(不更改原始值)动态计算顶点着色器中的位置。第二种选择类似于变换反馈,是在计算着色器中计算位置,将它们存储在缓冲区中,然后使用该缓冲区进行绘图。 Here 是 Vulkan Cookbook 中的一个示例,它正是这样做的 - 绘制其位置在计算着色器中计算的粒子(精灵)。

并且不要忘记您不需要传输每个顶点的所有数据。要渲染四边形,您只需要一个位置(中心)和可能的水平和垂直比例(每个维度中四边形的大小)。偏移、旋转、平移和其他操作不需要对每个顶点都进行传递,而只需对整个四边形进行传递。所以这也限制了您可能需要传输的数据的大小。