对于类似Minecraft的游戏,在每侧渲染具有不同纹理的立方体的有效方法?

时间:2012-02-05 18:56:03

标签: opengl 3d textures voxel

我正在尝试决定在类似Minecraft的游戏中渲染一堆具有不同纹理的立方体的最有效方法是什么。

我发现了instanced rendering。我所做的是我创建了一个单独的“立方体模型”,它存储了立方体的所有顶点,法线和纹理坐标,我创建了一个数组缓冲区并将其传递给GPU一次。然后我创建了一个(转换矢量,纹理索引)结构数组,我使用实例渲染来反复重绘同一个立方体,每次翻译并with the appropriate texture

(希望Notch不介意我使用他的纹理,直到我自己制作)

问题在于,并非所有6个边都将具有相同的纹理,并且我正在试图弄清楚如何使每个块类型的它们不同。我提出的两个解决方案是:

  1. 为每种块类型使用不同的模型。这样我就可以在每个顶点上指定不同的纹理坐标。我仍然可以使用实例渲染,但我会为每个块类型单独传递。
  2. 传递6个“纹理索引”(每个面1个),而不是每个块1个。
  3. 第二种解决方案需要传递更多(可能是多余的)数据。我不确定实例化渲染的好处有多大......所以我不知道是否会更好,例如,最多256个“通过”(每个块类型1个)或“一个大”传递“包含所有数据,并在一次拍摄中渲染每个块。

    或许还有另一种我不知道的方法?

4 个答案:

答案 0 :(得分:6)

我认为你不能用实例有效地做到这一点。绝大多数面部/立方体永远不可见,您可以通过不渲染来节省大量时间。不幸的是,这会使每个立方体成为不同的对象。

标准解决方案(以及如何在Minecraft中完成)是将您的地形划分为多个扇区。计算哪些面是可见的并将它们上传到GPU。当一个多维数据集发生变化时,你只需要重新上传它的扇区。渲染扇区时,您只需绘制基元而无需任何其他计算。

您可以根据sparse voxel octrees执行某些操作。这是更多的工作,但你将能够有效和准确地告诉你世界的哪些部分是可见的。

答案 1 :(得分:2)

我知道这个问题差不多有两年了,但是我可以制作一个存储所有单个纹理的3D纹理,其中z纹理坐标就像块ID一样。使用3D纹理,您现在可以立即绑定所有单独的块纹理,这意味着您可以使用实例渲染将转换与blockID一起传递,以获取3D采样器的正确块纹理。

答案 2 :(得分:1)

在我的nVidia 8600M GT上我发现,实例化在中间表现最佳,具有适度的顶点和实例计数,但我最终实例化几个顶点数千次,以消除冗余数据以及更新的努力它

我选择 2 ,在顶点数组中使用纹理数组和单个实例化立方体,并使用“每个实例数组”的纹理索引选择面部纹理,其中6个指数甚至可以包含在几个整数中。 对于提供实例属性,GL_ARB_instanced_arrays也可以使用,其中一个不需要使用gl_InstanceID访问缓冲区(可预测,因此在大多数情况下更快)。 如果你需要具有特定于实例的纹理坐标,我会绑定一个额外的每个实例和顶点纹理坐标数组,以及相应修改的着色器。

答案 3 :(得分:0)

答案很晚,但有人肯定需要它。

在主块类中有一个返回纹理的方法,带有face的参数。在需要多个纹理的各个类中,重写此方法并使用switch case或一系列if / else语句。

这是方法在块类中的样子:

public int getBlockTexture(int face){
     if(face = top){
         return grass top
     } else if(face = bottom){
         return grass bottom
     } else {
         return grass side
     }
}

至于如何在渲染器中使用它,请在渲染每个面之前抓取纹理。类似于你如何剔除。