绘制()函数:使用20,000个32x32的纹理或1个大纹理重复绘制20,000次。

6
我正在使用 .NET Framework 4 中的 C# 进行编程,旨在使用 XNA 制作瓦片式游戏。我有一个大纹理(256 像素 × 4096 像素)。请注意,这是一款瓦片式游戏,所以这个纹理非常庞大,因为它包含了许多 32 像素 × 32 像素的小块。我想专家们肯定知道什么是瓦片式游戏。方向是正交的(像棋盘),而不是等距的。
在 Game.Draw() 方法中,我有两种选择,其中一种比另一种效率高得多。
方法1/选择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
            }
        }
    }

注释:因此,第二种方法是多次绘制许多小纹理。

问题:哪种方法以及为什么?个人认为使用第一种方法会更加高效。如果您考虑地图中的瓦片数组(想象一下一个有2000x2000个瓦片的大地图),每个Tile对象只需要包含2个整数,用于表示一个大纹理中源矩形的X和Y位置 - 8字节。然而,如果您使用第二种方法,在地图的瓦片数组中的每个Tile对象都必须存储一个32x32的Texture(即图像),该图像必须为R G B A像素分配32×32次内存 - 每个瓦片大约需要4096个字节。那么,哪种方法以及为什么?首要考虑速度,然后是内存负载,然后是效率或者您专家们所信任的任何其他因素。

2个回答

9
第一种方法会快得多!这与您的CPU端数据结构没有什么关系。在任何情况下,您都可以将其缩小到几个字节 - 所以没有关系。
第一种方法之所以更快,是因为GPU的工作方式。简而言之,您向GPU发送带有顶点/三角形列表的绘制命令。这些顶点具有各种数据(位置、颜色、纹理坐标等)。至关重要的是,它们无法指定纹理 - 在绘制该三角形列表之前,必须在图形设备上指定用于绘制三角形的纹理。
SpriteBatch自动批处理您的精灵,以尽可能减少纹理交换和因此发送的绘制命令。这就是为什么它具有按纹理排序的选项。这也是源矩形参数存在的原因 - 允许使用精灵表 - 因此可以绘制更多的精灵,而不必更改纹理。
(事实上,即使您不使用SpritBatch,您向GPU发送的绘制命令也被称为“批次”。当您发送太多批次时,您将变成“批次限制”。很容易受到批次限制的影响 - 几百个批次是极限的一个非常粗略的估计。)

2
同意。你从屏幕读取的纹理越少,这个过程就会越快,因为它可以最大程度地减少GPU上的状态更改。
为了使其更快,请注意大多数瓷砖在帧之间不会更改。因此,将它们全部绘制到单个屏幕大小的渲染目标中,然后在随后的帧中只需使用一个绘制调用重新绘制该单个纹理。在其上添加更改的瓷砖。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接