3

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

我发现了实例化渲染。我所做的是创建了一个“立方体模型”,它存储了立方体的所有顶点、法线和纹理坐标,我从中创建了一个数组缓冲区并将其传递给 GPU 一次。然后我创建了一个(平移向量,纹理索引)结构数组,并使用实例化渲染一遍又一遍地重绘同一个立方体,每次平移并使用适当的纹理

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

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

  1. 为每种模块类型使用不同的模型。这样我可以在每个顶点上指定不同的纹理坐标。我仍然可以使用实例化渲染,但我会为每种块类型分别进行一次传递。
  2. 传递 6 个“纹理索引”(每个面 1 个)而不是每个块 1 个。

第二种解决方案需要传递更多(可能是冗余的)数据。我不确定实例化渲染的好处有多大……所以我不知道是不是最好做,比如说,最多 256 个“通过”(每种块类型 1 个),或者“一个大传递”所有数据,并一次渲染每个块。

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

4

4 回答 4

6

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

标准解决方案(以及它在 Minecraft 中的实现方式)是将您的地形划分为部门。计算哪些人脸是可见的并将它们上传到 GPU。当多维数据集更改时,您只需要重新上传它的扇区。渲染扇区时,您只需绘制图元而无需任何其他计算。

你可以做一些基于稀疏体素八叉树的事情。这是更多的工作,但您将能够有效且准确地分辨出您的世界的哪些部分是可见的。

于 2012-02-05T20:13:57.157 回答
2

我知道这个问题已经有将近两年的历史了,但是我可以制作一个 3D 纹理来存储所有单独的纹理,其中 z 纹理坐标有点像块 ID。使用 3D 纹理,您现在可以一次绑定所有单独的块纹理,这意味着您可以使用实例渲染来传递您的变换以及块 ID,以便为 3D 采样器获取正确的块纹理。

于 2013-12-10T02:07:45.833 回答
1

在我的 nVidia 8600M GT 上,我发现,在中等顶点和实例计数的情况下,实例化在“中间”表现最好,但我最终实例化了几个顶点数千次以消除冗余数据以及更新它的努力。

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

于 2012-02-05T19:42:15.580 回答
0

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

在主块类中有一个返回纹理的方法,带有一个面部参数。在需要多个纹理的单个类中,覆盖此方法并使用 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
     }
}

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

于 2015-01-20T05:31:15.153 回答