我正在XNA的“落砂”游戏中工作。当然,这意味着必须绘制很多很多像素!它开始很好,每个像素使用透明蓝色纯粹用于测试算法。在丢失任何帧速率(稳定的60 FPS)之前,我能够在屏幕上绘制大约100,000像素,这比我需要的还多!然而,当我最终添加一个不同颜色的像素(蓝色和红色)而没有其他变化时,我的FPS呈指数下降,只允许在FPS下降到大约10之前将大约10,000个像素绘制到屏幕上。经过实验,我得出结论精灵批次最有可能是错误的,虽然我可能完全错了,如果你想到不同的东西请告诉我,因为精灵批量自动排序并将像素混合在一起。我假设将两种颜色混合在一起的行为是我失去速度的地方。那么,我怎么能绕过精灵批处理的方法呢?还是我完全偏离基地?
我已经尝试过使用SpriteSortMode和BlendMode,甚至每次sprite批量调用只绘制彩色像素,但到目前为止还没有运气。
此外,我绘制到屏幕上的像素从不具有相同的坐标,因此不需要混合等。
//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个像素),直到我添加了额外的颜色。
感谢您的帮助!
答案 0 :(得分:1)
好的,我会尽可能给出最好的答案,但我受到你发布的代码数量的限制。首先,我将引导您this answer了解影响效果的各种因素。
SpriteBatch
可能遇到的问题是你强迫它开始批量过多。每次更改纹理时都必须启动一个批处理 - 听起来你正在为不同的像素使用不同的纹理,然后以随机顺序绘制它们。
在SpriteBatch
(带SpriteSortMode.Texture
)内按纹理排序本身就是一项昂贵的操作。你自己编写类似纹理的精灵的代码可能很慢或不正确 - 但是我不知道你给出的代码。
更好的情况,而不是使用许多纹理,将使用单个白色纹理,然后使用tint参数动态地将每个sprite着色为所需的颜色。然后每个精灵都可以一次发送。
但是,以及为这么多精灵设置顶点的大量处理,我们应该考虑实际发送到GPU的数据量。每个精灵都有4个顶点,每个顶点都有一个位置,一个颜色和一个纹理坐标。这是每像素高达 96字节。并且所有这些都必须每帧发送到GPU!
另一方面,纹理每像素仅 4字节。所以它应该更快。
有两件事可能会减慢它的速度:
首先,如果你打电话给Texture2D.SetData
超过你所需要的。每次调用SetData
都需要相当大的开销。如果你每个像素调用一次它将会非常慢。改为为整个图像调用一次。那个应该使它足够快以便可用 - 虽然我没有广泛地测试它。
另一种可能性是你的GPU有一个深度管道(依赖于硬件),并且仍在使用纹理渲染帧N,而你正在尝试为帧N + 1更新它。这会强制GPU在接受新更改之前完成渲染帧N.虽然这似乎不太可能是一个问题,除非你正在做其他GPU密集型的事情,或者你的图形驱动程序正在做一些愚蠢的事情。