我正在尝试在XNA 4.0中编写一个自定义的Minecraft Classic多人游戏客户端,但是当我真正在游戏中绘制世界时,我感到非常难过。每个块都是3D空间中的立方体,并且它可以在每一侧具有不同的纹理。我一直在互联网上阅读,并发现对于一个立方体,每一面都有不同的纹理,每个面都需要自己的一组顶点。这使得每个立方体总共有24个顶点,如果你有一个由64 * 64 * 64立方体组成的世界(或者可能更多!),那就会产生很多顶点。
在我的原始代码中,我将纹理贴图分成单独的纹理,并在绘制每个立方体的每一面之前应用这些纹理贴图。我被告知这是一种非常昂贵的方法,我应该将纹理保存在同一个文件中,只需使用UV坐标将某些子纹理映射到立方体上。尽管如此,这对性能没有太大作用,因为顶点的数量太多了。我还被告知要在VertexBuffer中收集顶点并立即绘制它们,但这也没有多大帮助,并且当顶点数量超过缓冲区的最大大小时偶尔会导致异常。我尝试制作立方体共享顶点的任何尝试也都失败了,导致大量减速和毛刺的立方体。
我不知道该怎么做。我一般都非常擅长编程,但任何类型的3D编程或游戏开发都完全逃脱了我。
这是我用来绘制立方体的方法。我有两个全局列表List<VertexPositionTexture>
和List<int>
,一个用于顶点,一个用于索引。绘图时,我遍历世界上的所有立方体,并对非空的立方体(如Air)进行RenderShape。我拥有的形状类粘贴在下面。 AddVertices方法中的注释代码是尝试使多维数据集共享顶点。当所有立方体的顶点都已添加到列表中时,数据将粘贴到VertexBuffer和IndexBuffer中,并调用DrawIndexedPrimitives。
老实说,我可能完全错了,但我真的不知道怎么做,并且没有教程实际描述如何绘制大量对象,只有非常简单的对象。我必须弄清楚如何重做BasicShape以获得多个纹理。
答案 0 :(得分:3)
您可以获得我与其他一些名为TechCraft的开发人员编写的代码副本:
它的免费和开源。它应该向您展示如何创建类似于Minecrafts的引擎。
答案 1 :(得分:1)
你可以做很多事情来加快速度:
您要做的是将立方体区域烘焙到顶点缓冲区中。我的意思是将所有立方体放在一个小区域中,并将它们全部放入一个顶点缓冲区。仅在多维数据集更改时更新此缓冲区。
在像“我的世界”这样的世界里,很多面孔互相遮挡。你可以做的最重要的事情就是隐藏两个立方体之间共享的面孔。想象一下,两个立方体紧挨着坐在一起,你真的不需要在它们之间画脸,因为它无论如何都无法看到。在我们的引擎中,这导致顶点减少了20倍。
_ _ _ _
|_|_| == |_ _|
至于你的纹理,像你说的那样使用纹理图集是一个好主意。这大大减少了您的绘制调用。
祝你好运!如果你想作弊,请看 Infiniminer 。 Infiniminer是基于Minecraft的游戏。它是用XNA编写的,是开源的!答案 2 :(得分:1)
您需要考虑减少问题的大小。如何通过减少工作来产生相同的图像?
如果您的立方体以规则的间隔间隔并且大小相同,则可能根本不需要存储顶点 - 您的着色器可以在运行时计算顶点位置。如果它们的大小不同并且没有以规则的间隔间隔,那么你仍然可以使用一些用于onf实例化(你将一个立方体的位置和大小提供给着色器,它可以在哪里渲染顶点来制作一个立方体出现在那个位置)
如果你的立方体遮挡了它们之外的任何东西,那么你只需要绘制最前面的立方体 - 它们后面的任何东西都是不可见的。一种自然的方法是使用八叉树数据结构,将3D空间划分为体素(立方体)。使用八叉树,您可以快速确定哪些立方体可见,并且只绘制这些立方体 - 所以不是绘制64x64x64立方体,您可能会发现每帧必须绘制几百个。您还会发现,当相机移动时,可见立方体的集合不会发生太大变化,因此您可以使用此“时间相干性”来更新数据结构,以最大限度地减少需要完成的工作以确定哪些立方体是可见的。
答案 3 :(得分:0)
我不认为Minecraft会一直画出所有的立方体。它们中的大部分是内部的,你只需要绘制表面上的那些。所以基本上,你需要一个高效的voxel渲染器。
答案 4 :(得分:0)
我最近在XNA中编写了一个引擎来执行此操作,您要查看的技术称为硬件实例化,并允许您将一个模型传递到着色器中,其中包含一个世界位置流到“实例”模型数百个(甚至数千次)遍布整个游戏世界。
我在这个示例的基础上构建了我的引擎,用我自己的模型替换了实例模型。
http://xbox.create.msdn.com/en-US/education/catalog/sample/mesh_instancing
一旦你把它变成一个可重复使用的类,它及其附带的着色器就会变得非常有用,可以渲染成千上万的任何你想要的东西(灌木丛,树木,立方体,成群鸟等)。
一旦你有一个基础模型(可能是块的一个面),它的网格将有一个相关的纹理,然后你可以用你想要的任何东西替换,以动态地改变每一面的块纹理和不同的类型块。