图像绘制速度
Image draw speed
我正在开发一款游戏,但目前我是 运行 基准。
如果有人能在这件事上帮助我,我将不胜感激。
我在做什么,是在单击开始按钮时触发面板上的绘画事件,代码如下:
private void startToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
pnlArea.Invalidate();
}
catch (Exception)
{
throw;
}
}
然后我在绘画活动中这样做:
private void pnlArea_Paint(object sender, PaintEventArgs e)
{
try
{
stopwatch = new Stopwatch();
// Begin timing
stopwatch.Start();
if (gameStatus == GameStatus.PlaceHead)
{
e.Graphics.DrawImage(dictHead["HeadRight"], 100, 100, 15, 15);
}
//e.Graphics.Clear(Color.White);
if (gameStatus == GameStatus.GameTest)
{
int x = 0;
int y = 0;
for (int i = 0; i < 5000; i++)
{
x += 15;
if (x > 1000)
{
x = 0;
y += 15;
}
e.Graphics.DrawImage(body.Value, x, y, 15, 15);
}
}
toolTimer.Text = Math.Round((stopwatch.Elapsed.TotalMilliseconds / 1000), 2).ToString() + "s";
// Stop timing
stopwatch.Stop();
}
catch (Exception)
{
throw;
}
}
这是我在上面的代码中绘制的 body 部分:
这是准确尺寸 --> 15px x 15px
但这有时需要 1.2 秒!!!
有什么办法可以改进吗?
这是最终结果屏幕的示例:
您需要考虑如何最大限度地减少绘图调用的次数。目前你绘制了 5000 个小方块以生成一个网格。每次绘制一个框时,您都会执行几条指令,然后调用图形方法来渲染缩放图像。这对每个网格方块来说都是很大的开销。
因此,您首先要考虑的是找到更有效的方法来绘制图像 - 例如,DrawImageUnscaled
可能比 DrawImage
工作得更快并达到您想要的结果。但这是对低效算法的优化 - 要获得真正的性能优势,您需要做的是看看是否可以采用一种新的、更高效的算法。
如果您必须使用位图进行渲染,那么请查看模式是如何重复的 - 您能否制作一个更大的位图来提供 4x4 或 16x16 的单元格组,然后进行渲染?还是代表整列或整行的位图?那么您可能会使用 50 次调用而不是 5000 次进行渲染。
但如果你不需要使用位图渲染,你可能会做得更好。例如,如果您 gfx.Clear(backgroundColor)
然后向下和横向绘制大约 140 条黑线,则只需调用 141 次就可以创建相同的显示。或者,如果您绘制大约 70 个矩形,则每次调用可以有效地执行 2 行 这极大地减少了您必须进行的方法调用的数量,并允许图形系统使用高度优化的线渲染和矩形渲染例程一次性绘制更多像素(事实上,由于系统知道线条始终是垂直和水平的,因此矩形的计算速度可能比通用直线快得多)。
(如果有不符合这个模式的位,那你还能渲染背景网格,然后在上面绘制变化吗?)
接下来,如果从一帧到下一帧只有一小部分图像发生变化,那么您的算法将绘制 5,000 个框,即使其中 4999 个框没有变化(或者 70 个矩形,1 个就足够了)。因此,如果您 (a) 仅使需要更改的视图部分无效,并且 (b) 编写渲染例程来计算出哪些网格正方形在裁剪边界之外,因此可以毫无意义地绘制,那么您可以大大改善问题。这可以减少对绘制 1 个矩形而不是每帧 5000 个的更新。 (实现相同目的的另一种方法是将图像保留在屏幕外位图中,然后在其上绘制更改。当您将其渲染到主屏幕显示时,显卡会为您剪辑它并获得相同的结果 -更快的重绘速度)
这一切都是为了通过 "lazy" 和横向思考尽可能少的工作来实现相同的显示。 (让计算机运行得更快总是归结为要求它做的更少)
加上大家给我的信息,我得出了双缓冲面板的结论。这解决了我的问题 -->
class DoubleBufferedPanel : Panel { public DoubleBufferedPanel() : base() { DoubleBuffered = true; } }
我只是使用了这个双缓冲面板。
完全没有闪烁的新基准! :
我正在开发一款游戏,但目前我是 运行 基准。
如果有人能在这件事上帮助我,我将不胜感激。
我在做什么,是在单击开始按钮时触发面板上的绘画事件,代码如下:
private void startToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
pnlArea.Invalidate();
}
catch (Exception)
{
throw;
}
}
然后我在绘画活动中这样做:
private void pnlArea_Paint(object sender, PaintEventArgs e)
{
try
{
stopwatch = new Stopwatch();
// Begin timing
stopwatch.Start();
if (gameStatus == GameStatus.PlaceHead)
{
e.Graphics.DrawImage(dictHead["HeadRight"], 100, 100, 15, 15);
}
//e.Graphics.Clear(Color.White);
if (gameStatus == GameStatus.GameTest)
{
int x = 0;
int y = 0;
for (int i = 0; i < 5000; i++)
{
x += 15;
if (x > 1000)
{
x = 0;
y += 15;
}
e.Graphics.DrawImage(body.Value, x, y, 15, 15);
}
}
toolTimer.Text = Math.Round((stopwatch.Elapsed.TotalMilliseconds / 1000), 2).ToString() + "s";
// Stop timing
stopwatch.Stop();
}
catch (Exception)
{
throw;
}
}
这是我在上面的代码中绘制的 body 部分:
这是准确尺寸 --> 15px x 15px
但这有时需要 1.2 秒!!! 有什么办法可以改进吗?
这是最终结果屏幕的示例:
您需要考虑如何最大限度地减少绘图调用的次数。目前你绘制了 5000 个小方块以生成一个网格。每次绘制一个框时,您都会执行几条指令,然后调用图形方法来渲染缩放图像。这对每个网格方块来说都是很大的开销。
因此,您首先要考虑的是找到更有效的方法来绘制图像 - 例如,DrawImageUnscaled
可能比 DrawImage
工作得更快并达到您想要的结果。但这是对低效算法的优化 - 要获得真正的性能优势,您需要做的是看看是否可以采用一种新的、更高效的算法。
如果您必须使用位图进行渲染,那么请查看模式是如何重复的 - 您能否制作一个更大的位图来提供 4x4 或 16x16 的单元格组,然后进行渲染?还是代表整列或整行的位图?那么您可能会使用 50 次调用而不是 5000 次进行渲染。
但如果你不需要使用位图渲染,你可能会做得更好。例如,如果您 gfx.Clear(backgroundColor)
然后向下和横向绘制大约 140 条黑线,则只需调用 141 次就可以创建相同的显示。或者,如果您绘制大约 70 个矩形,则每次调用可以有效地执行 2 行 这极大地减少了您必须进行的方法调用的数量,并允许图形系统使用高度优化的线渲染和矩形渲染例程一次性绘制更多像素(事实上,由于系统知道线条始终是垂直和水平的,因此矩形的计算速度可能比通用直线快得多)。
(如果有不符合这个模式的位,那你还能渲染背景网格,然后在上面绘制变化吗?)
接下来,如果从一帧到下一帧只有一小部分图像发生变化,那么您的算法将绘制 5,000 个框,即使其中 4999 个框没有变化(或者 70 个矩形,1 个就足够了)。因此,如果您 (a) 仅使需要更改的视图部分无效,并且 (b) 编写渲染例程来计算出哪些网格正方形在裁剪边界之外,因此可以毫无意义地绘制,那么您可以大大改善问题。这可以减少对绘制 1 个矩形而不是每帧 5000 个的更新。 (实现相同目的的另一种方法是将图像保留在屏幕外位图中,然后在其上绘制更改。当您将其渲染到主屏幕显示时,显卡会为您剪辑它并获得相同的结果 -更快的重绘速度)
这一切都是为了通过 "lazy" 和横向思考尽可能少的工作来实现相同的显示。 (让计算机运行得更快总是归结为要求它做的更少)
加上大家给我的信息,我得出了双缓冲面板的结论。这解决了我的问题 -->
class DoubleBufferedPanel : Panel { public DoubleBufferedPanel() : base() { DoubleBuffered = true; } }
我只是使用了这个双缓冲面板。
完全没有闪烁的新基准! :