我正在尝试将OpenGL游戏/应用引擎移植到Vulkan。
大多数Vulkan示例和教程都是针对功能演示的,因此它们的内容不是动态的,这意味着顶点,变换和纹理是为每个演示专门安排的。 但是,要构建一个真实的游戏/应用引擎来渲染完整的动态内容,我需要确保Vulkan管道能够渲染无法预先安排的内容,这有两个主要挑战:
我从其他经验丰富的Vulkan开发人员那里找到了第一个问题的最佳答案-使用具有不同出价偏移的动态DescriptorSet传入每个对象模型矩阵,效果很好。
现在,我仍在寻找第二个问题的最佳解决方案,即在渲染每个对象/网格时动态切换纹理。请记住,对象数和纹理数是不可预测的,因此无法在片段着色器中对其进行硬编码。
一些Vulkan开发人员在多个stackoverflow线程(例如this one)中提出了一些建议, 基本上,有三种主要的纹理切换解决方案:
最大的限制是不同层中的所有纹理都必须具有完全相同的大小,这对于游戏/应用引擎来说不是很有用
就像我的着色器中的这个一样:layout(set = 2, binding = 0) uniform texture2D textures[TEXTURE_ARRAY_SIZE];
的最大限制是每个平台上的最大数组大小各不相同,最坏的情况是在iOS上,只能使用31种纹理,这是由底层Metal API强制执行的。其他平台的数量也非常有限:Android:79,macOS:128。
我自己的想法:
到目前为止,我倾向于使用解决方案(1),但对此仍有更多疑问:
解决方案(1)-(a)-我需要为每个单个网格创建专用的纹理描述符集,对于池中允许的最大采样图像描述符数量没有太大的关注,这里是我收集的:nVidia: 1048576, AMD: 4294967295, Intel: 1200, Android/Snapdragon:768, macOS:256, iOS:62
。但是一些开发人员说基于每个网格的绑定纹理可能会影响性能吗?
解决方案(1)-(b)-好的一部分是仅创建一个采样的图像描述符集并将其绑定到不同的绑定位置。
我认为这是不可能的,因为所有绑定位置都必须通过"binding = x"
在片段着色器中进行硬编码,因此我认为建议此解决方案的人并不意味着将其用于动态内容呈现。
最后,我倾向于使用解决方案(1)-(a)。但是仍然想听到其他Vulkan开发人员的来信,看看该解决方案是否存在性能问题,或者可能会有更好的解决方案。
PS :当我回想起我们如何在OpenGL中切换纹理时,glGenTextures()
为每个纹理赋予了唯一的ID,然后使用此glBindTexture()
选择该ID渲染网格时使用的纹理。有没有一种方法可以在Vulkan中模拟这种机制而不会造成太多性能损失?