繁体   English   中英

有效地绘制2D Sprite(位图)TIles

[英]Drawing 2D Sprite (Bitmap) TIles Efficiently

我正在写一个2d基于磁贴的引擎。 目前,我的绘图例程使用C#绘图库每次刷新屏幕时重绘每个可见的图块。 我滚动和缩放工作,一切看起来都像我想要的那样。 但例程很慢。 现在我正在努力改进它。 我有几个问题:

首先,我认为在每次刷新时重新绘制图块是不必要的(因为它们永远不会改变)。 现在我正在尝试更改算法,以便在初始化时将整个地图写入单个位图,然后在绘制时切割位图的正确部分。 你认为这是正确的方法吗? (我还考虑将图像保留在背景中,只是滚动它。但后来我决定不想绘制视野之外的东西。但是,也许这比切割/粘贴便宜?内存与时间问题?)

其次,据我所知,C#Drawing例程不使用GPU的全部功能。 我想我应该尝试在OpenGL(或DirectX中)绘图,但我更喜欢前者,因为它是多平台的。 这会有帮助吗? 你知道OpenGL的任何平铺(或一般像素绘图)教程吗? 书籍参考也可以提供帮助。

我此刻也不做多线程(实际上我对这是什么只有一个含糊的概念)。 我应该尝试多线程抽屉吗? 或者OpenGL会为图形冗余制作多线程吗?

谢谢。

如果你想使用OpenGL,2d的最佳选择是SDL 使用OpenGL和C#永远不会那么便携,因为它会使用.NET包装器。

XNA是一个用C#编写游戏的好工具,它应该提供比SDL更多的速度和灵活性(尤其是.net端口)以及更多功能(但更多的批量)。

对于您的剪切或滚动问题,最佳路线是滚动。 当您使用GDI +(System.Drawing使用的)绘图时,内存比CPU少得多。 您可以随时将地图拆分为多个部分并滚动它们,然后在必要时加载(如果它那么大)。

您打算使用哪种应用程序框架? WinForms(Win32)和WPF之间的高效绘图技术非常不同。

你是正确的.NET绘图例程没有充分利用GPU。 使用DirectX或OpenGL,一个即时优化是使用图像列表或显示列表将所有图像切片(或至少,即时视图区域所需的所有切片加上一些更多)预加载到GPU内存中。 然后,您将通过索引在曲面上绘制切片 - 在x,y处绘制切片N. 这通常比使用存储在主系统内存中的位图在GPU表面上绘制快得多,因为必须将位图像素复制到GPU以用于绘制的每个图块并且占用大量时间。 只要您可以在输出中的多个位置使用相同的图像切片,按索引绘制也会使用更少的GPU内存。

OpenGL与DirectX是您的选择,但IMO DirectX的发展速度更快,提供了比OpenGL更多的硬件加速功能。 Windows上的OpenGL驱动程序也因硬件供应商而被忽视。 他们的主要关注点是他们的DirectX驱动程序。

考虑一下您是否真的需要OpenGL或DirectX用于2D平铺应用程序。 要求OpenGL或DirectX将减少可以运行您的应用程序的计算机,尤其是旧计算机的数量。 OpenGL和DirectX可能过度。 如果你很聪明的话,你可以用普通的旧GDI做很多事情。

远离多线程,直到你有充分的理由去那里并且你有一些线程经验。 多线程为某些计算环境提供了一些性能提升的奖励,但也带来了新的麻烦和新的性能问题。 在注册所有这些新的麻烦之前,请确保好处是显着的。

通常,在屏幕上移动像素通常不适合多线程。 你只有一个显示设备(在大多数情况下),所以用多个线程同时尝试更改像素来点击它并不能正常工作。 借用项目管理的表达:如果一个女人可以在9个月内创造一个孩子,你可以使用9名女性在1个月内创造1个孩子吗? ;>

确定系统中不需要访问相同资源或设备的部分。 对于在并行线程中运行而言,这些比在屏幕上使用blitting tile更好。

最佳优化是发现不需要完成的工作 - 例如减少重绘图块的次数,或者更改为索引模型,以便可以从GPU内存而不是系统内存中抽取图块。

我不熟悉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();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM