我有一个像Minecraft这样的基于多维数据集的世界,我想知道是否有一种方法可以构造一个少于24个顶点的多维数据集,从而减少内存使用量。
在我看来,这是不可能的,原因有两个:法线无法正确显示,每面纹理也无法使用。
是这种情况还是我错了?也许有些新颖的DX11技术可以提供帮助?
编辑:为了明确起见,我有2个要求:我需要每个立方体面的表面法线以进行适当的照明,并且需要一种方法来解决每个立方体面的纹理数组中的不同索引
我有一个像Minecraft这样的基于多维数据集的世界,我想知道是否有一种方法可以构造一个少于24个顶点的多维数据集,从而减少内存使用量。
在我看来,这是不可能的,原因有两个:法线无法正确显示,每面纹理也无法使用。
是这种情况还是我错了?也许有些新颖的DX11技术可以提供帮助?
编辑:为了明确起见,我有2个要求:我需要每个立方体面的表面法线以进行适当的照明,并且需要一种方法来解决每个立方体面的纹理数组中的不同索引
Answers:
如果只需要按面法线,并且面的texcoords严格为0 / 0、0 / 1、1 / 0、1 / 1(或与您的布局相似),则可以构造具有8个顶点的立方体以及30(带重新启动的条带)或36(列表)索引。使用基于顶点着色器中的SV_VertexID的常量数组查找来获取法线和texcoord。
这样做意味着您甚至不需要在顶点缓冲区中包含texcoords或法线,这将为您节省更多的内存。
更进一步,您仍然可以将每个多维数据集一路转到24个顶点,但也可以使用实例化。每个多维数据集在顶点缓冲区(1x1x1)中都是固定大小的,并且具有按实例数据的缩放因子和位置(假设多维数据集不旋转,如果它们旋转,则为矩阵)。在非旋转情况下,您一次要花费24个顶点,但是每个多维数据集只需要6个浮点数即可完全指定。在旋转情况下,您要查看16个浮点数,但即使这样也可以节省很多钱(在这种情况下,您很可能在矩阵转换时遇到CPU方面的瓶颈-对于非旋转情况下,动态地构造矩阵您的顶点着色器-即使是按顶点完成的,也是如此之快,以至于您甚至不必担心它)。
对于每面纹理,只需使用纹理数组即可。当然,您需要确保数组中每个此类纹理的大小均相同,并且如果数组本身需要更改,您仍需要中断当前的批处理,否则,它将做得很好。在您的顶点定义中添加第三个texcoord,以定义要用于每个面的数组切片。
您不需要带有GS的GS,它的运行速度应比使用GS的运行速度快,因为启用了几何着色器阶段会增加额外的开销。
我的引擎中已经有基准测试代码,使用此方法可以绘制一堆多维数据集,并且可以在相对低端的GPU上轻松地检查超过300,000个多维数据集,同时仍以60fps的速度清除,而无需执行其他任何操作来优化流程。诚然,我既不进行照明也不对其进行纹理处理,但是我确实启用了alpha混合,禁用了背面剔除,并且总体而言,它与我的“不做其他任何事情来优化”部分保持平衡,因此应该为您提供一种合理的想法可以用这种方法击球。
我认为您可以进行的主要优化基于以下事实:并非每个多维数据集实际上都需要全部24个顶点。实际上,唯一需要24个顶点的立方体是漂浮在空中的立方体,这可能很少见。
通常,仅为与空气接触的面生成四边形。这意味着,如果两个立方体相互接触,则无需为它们接触的面生成任何顶点。
下图演示了此概念,但以2D形式显示以便于理解。在图像中,有11个被占用的块(由实心的灰色圆圈表示),通常需要4 x 11 = 44个边来表示(4个是正方形,而不是立方体)。但是,正如您所看到的,仅当边缘与一个空的正方形接触时才真正需要绘制边缘,在这种情况下,该正方形只有8个边缘。
如果这样一个简单的2D示例设法将44条边减少到8条边,请想象一下在大型3D世界中的收益...
这是本文中介绍的方法,尽管它针对OpenGL,但我还是建议您阅读该方法。这些概念应该相当普遍。
您可能还可以使用几何着色器在GPU上动态生成顶点,从而无需将其存储在内存中,但是我没有经验,也不知道它在大范围内的性能如何世界。