6

我正在使用 .NET Framework 4 在 C# 中进行编程,并打算使用 XNA 制作基于图块的游戏。我有一个大纹理(256 像素 x 4096 像素)。请记住,这是一个基于图块的游戏,所以这个纹理之所以如此庞大只是因为它包含许多图块,每个图块都是 32 像素 x 32 像素。我想专家们肯定会知道基于图块的游戏是什么样的。方向是正交的(如棋盘),而不是等距的。

在 Game.Draw() 方法中,我有两个选择,其中一个会比另一个更有效率。

选择/方法#1:

半伪代码:

    public void Draw()
    {
        // map tiles are drawn left-to-right, top-to-bottom
        for (int x = 0; x < mapWidth; x++)
        {
            for (int y = 0; y < mapHeight; y++)
            {
                SpriteBatch.Draw(
                    MyLargeTexture, // One large 256 x 4096 texture
                    new Rectangle(x, y, 32, 32), // Destination rectangle - ignore this, its ok
                    new Rectangle(x, y, 32, 32), // Notice the source rectangle 'cuts out' 32 by 32 squares from the texture corresponding to the loop
                    Color.White); // No tint - ignore this, its ok
            }
        }
    }

说明: 因此,有效地,第一种方法是多次引用一个大纹理,每次使用这个大纹理的一个小矩形来绘制适当的平铺图像。

选择/方法#2

半伪代码:

    public void Draw()
    {
        // map tiles are drawn left-to-right, top-to-bottom
        for (int x = 0; x < mapWidth; x++)
        {
            for (int y = 0; y < mapHeight; y++)
            {
                Texture2D tileTexture = map.GetTileTexture(x, y); // Getting a small 32 by 32 texture (different each iteration of the loop)

                SpriteBatch.Draw(
                    tileTexture,
                    new Rectangle(x, y, 32, 32), // Destination rectangle - ignore this, its ok
                    new Rectangle(0, 0, tileTexture.Width, tileTexture.Height), // Notice the source rectangle uses the entire texture, because the entire texture IS 32 by 32
                    Color.White); // No tint - ignore this, its ok
            }
        }
    }

说明: 所以,实际上,第二种方法是多次绘制许多小纹理。

问题:使用哪种方法,为什么?就个人而言,我认为使用第一种方法会更加有效。如果您考虑一下这对地图中的瓦片数组意味着什么(例如,考虑具有 2000 x 2000 个瓦片的大地图),每个瓦片对象只需包含 2 个整数,用于源的 X 和 Y 位置一个大纹理中的矩形 - 8 个字节。但是,如果您使用方法 #2,则地图瓦片数组中的每个瓦片对象都必须存储一个 32×32 纹理 - 一个图像 - 必须为 RGBA 像素分配 32 x 32 倍的内存 - 每个瓦片 4096 字节然后?那么,哪种方法以及为什么?第一要务是速度,然后是内存负载,然后是效率或专家认为的任何东西。

4

2 回答 2

9

第一种方法会快得多!它也与您的 CPU 端数据结构没有任何关系。在任何一种情况下,您都可能会减少到几个字节 - 所以没关系。

第一种方法会更快的原因是 GPU 的工作方式。简单地说,您发送带有顶点/三角形列表的 GPU 绘制命令。这些顶点具有各种数据(位置、颜色、纹理坐标等)。至关重要的是,他们无法指定纹理 - 必须在绘制之前在图形设备上指定用于绘制三角形的纹理,以用于整个三角形列表。

SpriteBatch 所做的是在可能的情况下自动将您的精灵批处理在一起,以便最大限度地减少纹理交换并因此发送绘制命令。这就是为什么它可以选择按纹理排序的原因。这也是存在 source-rectangle 参数的原因——允许使用精灵表——因此可以绘制更多精灵而无需更改纹理。

(事实上​​,你发送到 GPU 的绘图命令——即使你没有使用 SpritBatch——也被称为“批次”。当你发送太多时,你会变成“批次受限”。变得非常容易成为批次受限 - 一个几百个批次是对限制的非常粗略的估计。)

于 2010-12-28T02:14:46.140 回答
2

同意。您提取的纹理越少,这将越快,因为它最大限度地减少了 GPU 上的状态变化。

为了让它更快,请注意大多数图块不会在帧之间发生变化。因此,将它们全部绘制到单个屏幕大小的渲染目标一次,然后在后续帧上只需使用一次绘制调用重绘该单个纹理。添加顶部变化的瓷砖。

于 2010-12-28T02:22:10.383 回答