我正在写一个2d的基于瓦片的引擎。目前,我的绘图例程使用C#绘制库在每次屏幕刷新时重新绘制每个可见的瓦片。我可以滚动和缩放来工作,一切看起来都像我想要的那样。但是这个例程很慢。现在我正在努力改进它。我有几个问题:
首先,我认为在每次刷新时重新绘制磁贴是不必要的(因为它们永远不会改变)。现在我正在尝试更改算法,以便在初始化时将整个地图写入单个位图,然后在绘制时剪切位图的正确部分。你认为这是正确的方法吗?(我也考虑过将图像留在背景中,然后滚动过去。但后来我决定,我不想画视野之外的东西。然而,也许这比剪切/粘贴更便宜?记忆与时间的问题?)
第二,据我所知,C#绘图例程没有使用图形处理器的全部功能。我想我应该试着用OpenGL (或者DirectX,但我更喜欢前者,因为它是多平台的)。这会有帮助吗?你知道OpenGL的任何平铺(或一般的像素绘制)教程吗?一本书的参考资料也会有所帮助。
我目前也不做多线程(事实上,我对多线程是什么只有一个模糊的概念)。我应该试着给抽屉穿多条线吗?或者OpenGL会让图形的多线程变得多余吗?
谢谢。
发布于 2010-08-21 09:35:33
您计划使用哪种应用程序框架?高效绘图的技术在WinForms (Win32)和WPF中有很大的不同。
您说得对,.NET绘图例程没有充分利用GPU。使用DirectX或OpenGL,一种直接的优化方法是使用图像列表或显示列表将所有图像分片(或者至少是即时查看区域所需的所有分片加一点)预加载到GPU内存中。然后,您可以通过索引绘制瓦片N在x,y处在表面上绘制瓦片。这通常比使用存储在主系统内存中的位图在GPU表面上绘制要快得多,因为必须将绘制的每个瓦片的位图像素复制到GPU中,这会占用大量时间。当您可以在输出中的多个位置使用相同的图像瓦片时,按索引绘制也会使用更少的GPU内存。
OpenGL vs DirectX是你的选择,但DirectX的发展速度更快,提供了比OpenGL更多的硬件加速功能。Windows上的OpenGL驱动程序也有被硬件供应商忽视的名声。他们的主要关注点是DirectX驱动程序。
考虑一下你的2D tile应用程序是真的需要OpenGL还是DirectX。要求使用OpenGL或DirectX将减少可以运行应用程序的计算机数量,尤其是较旧的计算机。OpenGL和DirectX可能有些过头了。如果你聪明的话,你可以用普通的GDI做很多事情。
远离多线程,直到你有一个很好的理由去那里,并且你有一些线程的经验。多线程为某些计算环境提供了一些性能提升的奖励,但也带来了新的令人头疼的问题和新的性能问题。在你签约接受所有这些令人头疼的新问题之前,请确保好处是显著的。
一般来说,在屏幕上移动像素通常不适合多线程。您只有一个显示设备(在大多数情况下),所以用多个线程尝试同时更改像素并不能很好地工作。借用项目管理的一句话:如果一个女人可以在9个月内生出一个孩子,你能用9个女人在1个月内生出1个孩子吗?;>
努力识别系统中不需要访问相同资源或设备的部分。这些都是并行线程运行的更好的候选者,而不是在屏幕上显示磁贴。
最好的优化是发现不需要完成的工作-例如,减少重新绘制瓷砖的次数,或者更改为索引模型,以便可以从GPU内存而不是系统内存中绘制瓷砖。
发布于 2010-08-21 09:17:16
发布于 2010-08-21 10:26:21
我不熟悉OpenGL,但我用ManagedDX编写了一个基于瓦片的引擎(后来移植到了XNA)。ManagedDX已经过时了,但SlimDX项目仍在积极开发中。
使用DX,您可以将每个单独的磁贴加载到Texture中。(例如,使用Texture.FromFile()或Texture.FromStream() ),并让单个Sprite实例绘制它们。这一点表现得相当不错。我将纹理分组在一个简单的类中,使用Point或Vector2作为它们的位置,只在位置改变时设置它们,而不是每次调用draw方法时设置它们。我只在内存中为即时屏幕和一两个屏幕缓存磁贴,不需要更多,因为文件IO足够快,可以在滚动时获取新的磁贴。
struct Tile
{
public Point Location;
public Texture Texture;
}
Device device;
Sprite sprite;
List<Tile> tiles = new List<Tile>();
.ctor() {
this.device = new Device(...)
this.sprite = new Sprite(this.device);
}
void Draw() {
this.device.Clear(ClearFlags.Target, Color.CornflowerBlue, 1.0f, 0);
this.device.BeginScene();
this.sprite.Begin(SpriteFlags.AlphaBlend);
foreach (Tile tile in this.tiles) {
this.sprite.Draw2D(tile.Texture,
new Point(0, 0), 0.0f, tile.Location, Color.White);
}
this.sprite.End();
this.device.EndScene();
this.device.Present();
}https://stackoverflow.com/questions/3535814
复制相似问题