XNA - 合并精灵以获得更好的绘图性能?

Vec*_*vox 3 performance xna 2d sprite

我在某处读到,当渲染大量3D对象时,可以将它们合并形成一个巨大的网格,这样就只能进行一次绘制调用.因此,让,引用:"GPU做它的魔力",而CPU可以自由地进行其他调用而不是绘制.

那么就我的问题而言,在考虑到性能2D环境中这样做是否可行?

例如,假设我们有一个简单的tile系统,而不是为视图中的每个tile进行绘制调用,而是将所有tile合并为一个大的sprite,然后在其上调用draw.

任何有关此事的见解 - 提示,链接或诸如此类 - 都非常受欢迎,因为我之前没有图形性能方面的经验.

编辑:对不起,我的解释很糟糕.我正在创造一个供个人使用的瓷砖发动机,并希望它尽可能多样化.因此,我希望优化,以防万一我必须在不久的将来绘制大量的瓷砖.

确实使用了一个瓷砖表,但我对这个问题的意思是,将从工作表中绘制的所有瓷砖合并到一个新的Texture2D中是否会获得性能.例如:

我们在屏幕上绘制了128x72的瓷砖.我们不是循环遍历所有图块并为每个要绘制的图块调用绘图,而是将所有图块合并为一个大小为1280x720的新图形并绘制它.这样,draw()方法每帧只调用一次.我的问题是,这是否会提高性能,因为它会在制作3D时将3d对象合并为单个网格.

因为我收集的信息是调用draw()是一个性能损失,应该尽可能少地调用.有人确认或否认?:)

Ven*_*rix 10

我对XNA和3D没有任何经验,但我会给你一些关于2D游戏的建议.我花了一些时间在今年年初在XNA创建一个磁贴引擎,并想知道同样的事情.我认为这里的简短答案是肯定的,如果你担心性能,将你的瓷砖组合成一个更大的精灵是一个好主意.但是,如果你感兴趣,还有更长的答案.

一般来说,在性能优化方面,答案几乎总是"不要这样做".如果您确定需要针对性能进行优化,那么下一个答案几乎总是"不要这样做".最后,如果您尝试优化性能,那么您可以做的最重要的事情是使用基准测试来收集更改前后性能的精确度量.没有它,你不知道你是否成功了!

现在,更多地涉及2D游戏,我了解到我在我的tile引擎中看到了更好的性能,我切换的纹理越少.例如,假设我有草砖和砾石砖.如果这些是内存中的两个独立纹理,我绘制草砖,然后是砾石砖,然后是草砖到屏幕,GPU将加载草纹理,然后将其切换出来加载砾石纹理,然后切换草纹理回来画另一个草瓦.这很快就杀死了性能!解决这个问题的最简单方法是使用spritesheet,将草和砾石瓷砖放入一个纹理中,然后告诉SpriteBatch每次都从同一纹理上的不同区域进行绘制.

另一件需要考虑的事情是你要在屏幕上同时绘制多少个瓷砖.我不记得具体,但我一次画了数千个瓷砖(在缩小的视图中).我注意到,当我使用更大的瓷砖并减少它们时,正如您在问题中所建议的那样,性能也得到了提升.这并没有我在上一段中描述的那么大,我仍然鼓励你测量不同实现产生的性能变化.此外,如果您只绘制了十几个或几百个瓷砖,那么现在尝试对其进行优化可能是不值得的(参见第2段).

只是你知道我并没有完全做到这一点,这里是Shawn Hargreaves关于纹理交换,spritesheets等的帖子的链接.如果你搜索的话,XNA论坛以及Shawn Hargreaves的博客上可能有更好的帖子话题.

http://forums.xna.com/forums/p/24254/131437.aspx#131437

更新:

由于您更新了问题,请让我更新我的帖子.我决定只对一些样本进行基准测试,以便了解性能差异可能是什么.在我的Draw()函数中,我有以下内容:

        GraphicsDevice.Clear(Color.CornflowerBlue);

        Stopwatch sw = new Stopwatch();
        sw.Start();

        spriteBatch.Begin();

#if !DEBUG
        spriteBatch.Draw(tex, new Rectangle(0, 0, 
                         GraphicsDevice.Viewport.Width,
                         GraphicsDevice.Viewport.Height), 
                         Color.White);            
#else
        for (int i = 0; i < 128; i++)
            for (int j = 0; j < 72; j++)
            {
                Rectangle r = new Rectangle(i * 10, j * 10, 10, 10);
                spriteBatch.Draw(tex, r, r, Color.White);
            }
#endif
        spriteBatch.End();

        sw.Stop();

        if (draws > 60)
        {
            numTicks += sw.ElapsedTicks;
        }
        draws++;

        if (draws % 100 == 0)
            Console.WriteLine("avg ticks: " + numTicks / (draws - 60));

        base.Draw(gameTime);
Run Code Online (Sandbox Code Playgroud)

只需删除"#if!DEBUG"语句中的感叹号即可在两种方法之间切换.我跳过前60次抽签,因为他们包括一些初始设置(不确定是什么)并且偏向平均值.我下载了一个1280x720图像,对于顶级测试用例,我只画了一次.对于底部测试用例,我在平铺中绘制了一个源图像,128x72就像您在问题中询问的那样.结果如下.

绘制一张图片:

avg ticks: 68566
avg ticks: 73668
avg ticks: 82659
avg ticks: 81654
avg ticks: 81104
avg ticks: 84664
avg ticks: 86626
avg ticks: 88211
avg ticks: 87677
avg ticks: 86694
avg ticks: 86713
avg ticks: 88116
avg ticks: 89380
avg ticks: 92158
Run Code Online (Sandbox Code Playgroud)

绘制128x72瓷砖:

avg ticks: 7902592
avg ticks: 8052819
avg ticks: 8012696
avg ticks: 8008819
avg ticks: 7985545
avg ticks: 8028217
avg ticks: 8046837
avg ticks: 8291755
avg ticks: 8309384
avg ticks: 8336120
avg ticks: 8320260
avg ticks: 8322150
avg ticks: 8381845
avg ticks: 8364629
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,那里有几个数量级的差异,所以它非常重要.测试这种东西非常简单,我建议你为你的特定设置运行自己的基准测试,以考虑我可能错过的东西.