0

我正在开发 XNA 中的“落沙”游戏。当然,这意味着必须绘制大量像素!它开始很好,每个像素使用透明的蓝色纯粹用于测试算法。在失去任何帧速率(稳定的 60 FPS)之前,我能够在屏幕上绘制大约 100,000 个像素,这超出了我的需要!然而,当我最终添加了不同颜色的像素(蓝色和红色)并且没有其他变化时,我的 FPS 呈指数级下降,在 FPS 下降到大约 10 之前,只允许在屏幕上绘制大约 10,000 个像素。经过一些实验后,我得出结论精灵批次最有可能有问题,尽管我可能完全错了,如果您想到不同的东西,请告诉我,因为精灵批次会自动排序并将像素混合在一起。我认为将两种颜色混合在一起的行为是我失去速度的地方。那么,我怎样才能绕过精灵批处理的方法呢?还是我完全不在基地?

我尝试过使用 SpriteSortMode 和 BlendMode,甚至只在每个精灵批处理调用中绘制彩色像素,但到目前为止还没有运气。

此外,我在屏幕上绘制的像素从一开始就没有相同的坐标,因此不需要混合等。

    //Game Draw Method
    protected override void Draw(GameTime gameTime)
    {                      
        stopWatch.Start();          

        GraphicsDevice.Clear(Color.Black);

        spriteBatch.Begin();

        //backgroundSprite.Draw(spriteBatch);

        terrainSprite.Draw(spriteBatch);

        resourceMap.Draw(spriteBatch, spriteFont);            

        frameCounter++;

        string fps = string.Format("fps: {0}", frameRate);

        int totalint = 0;

        for (int i = 0; i < resourceMap.activeCoordinates.Count; i++)
        {
            totalint += resourceMap.activeCoordinates[i].Count;
        }

        string total = string.Format("resource count: {0}", totalint);

        spriteBatch.DrawString(spriteFont, fps, new Vector2(33, 33), Color.White);
        spriteBatch.DrawString(spriteFont, total, new Vector2(33, 45), Color.White);
        spriteBatch.DrawString(spriteFont, totalTime, new Vector2(33, 17),    Color.White);            
        spriteBatch.DrawString(spriteFont, totalTime, new Vector2(33, 17),  Color.White); 


        spriteBatch.End();
        stopWatch.Stop();
        totalTime = "Draw Time:     " + stopWatch.Elapsed;
        stopWatch = new Stopwatch();


        base.Draw(gameTime);
    }

    //resourceMap.Draw(SpriteBatch spriteBatch, SpriteFont font) from Game Draw
    public void Draw(SpriteBatch spriteBatch, SpriteFont font)
    {
        //spriteBatch.End();
        //this was originally one for loop to draw all pixels, but was separated to draw each different color pixel after discovering performance issue
        for (int c = 0; c < activeCoordinates.Count(); c++)
        {
            //spriteBatch.Begin();
            for (int i = 0; i < activeCoordinates[c].Count; i++)
            {
                mapArray[(int)activeCoordinates[c][i].X][(int)activeCoordinates[c][i].Y].Draw(spriteBatch);
            }
            //spriteBatch.End();
        }
        //spriteBatch.Begin();
        spriteBatch.DrawString(font, timeInMilli, new Vector2(33, 0), Color.White);
    }

同样,对代码所做的唯一更改是在要绘制的像素列表中添加不同的颜色,因此这里的代码运行良好(以大约 60fps 的速度绘制 100,000 个像素),直到我添加了额外的颜色。

谢谢您的帮助!

4

1 回答 1

1

好的,我将尽我所能给出最好的答案,但我受到您发布的代码数量的限制。首先,我将引导您查看此答案,以了解影响性能的各种因素的概述。

您可能遇到的问题SpriteBatch是您强制它启动太多批次。每次更改纹理时,它都必须启动一个批处理 - 听起来您正在为不同的像素使用不同的纹理,然后以随机顺序绘制它们。

SpriteBatch在(with )内按纹理排序SpriteSortMode.Texture本身可能是一项昂贵的操作。您自己的用于对类似纹理的精灵进行分组的代码可能很慢或不正确 - 但我无法用您给出的代码来判断。

一个更好的情况是使用单个白色纹理,而不是使用许多纹理,然后使用 tint 参数将每个精灵动态着色为所需的颜色。然后每个精灵都可以在一个批次中发送。

但是,以及为这么多精灵设置顶点的大量处理,我们应该考虑实际发送到 GPU 的数据量。每个精灵有 4 个顶点,每个顶点都有一个位置、一个颜色和一个纹理坐标。每像素高达96 个字节。所有这些都必须每帧发送到 GPU!

另一方面,纹理每个像素只有4 个字节。所以按理说它应该更快。

有两件事可能会减慢速度:

首先,如果你打电话的Texture2D.SetData次数超出了你的要求。每次调用都SetData需要相当大的开销。如果你每像素调用一次,它会非常慢。而是为整个图像调用一次。这应该使它足够快可以使用——尽管我自己没有对此进行广泛的测试。

另一种可能性是您的 GPU 有一个深管道(取决于硬件)并且仍在使用您的纹理来渲染第 N 帧,而您正在尝试为第 N+1 帧更新它。这会强制 GPU 在接受新更改之前完成渲染帧 N。尽管这似乎不太可能成为问题,除非您正在做其他非常 GPU 密集型的事情,或者您的图形驱动程序正在做一些愚蠢的事情。

于 2013-02-26T06:53:11.647 回答