2

我正在开发一种“落沙”风格的游戏。

我尝试了许多将沙子绘制到屏幕上的方法,但是,每种方法似乎都会以一种或另一种形式产生一些问题。

我经历过的事情清单:

  1. 从像素大小的纹理一次一个地绘制每个像素。问题:每次更新大约有 100,000 个像素发生变化后速度变慢。

  2. 将每个像素绘制到一个大的texture2d,绘制texture2d,然后清除数据。问题:使用 texture.SetPixel() 非常慢,即使处理旧纹理,也会导致少量内存泄漏(大约每秒 30kb,加起来很快),即使在对象上调用 dispose 也是如此。我根本不知道如何阻止它。然而,总的来说,这是最好的方法(到目前为止)。如果有办法阻止泄漏,我想听听。

  3. 使用位图中的 Lockbits。从位图的角度来看,这非常有效,但不幸的是,我仍然必须将位图转换回 texture2d,这会导致帧速率下降到小于 1。所以,如果我能找到一种在 xna 中绘制位图而不转换它(或其他东西)的方法,它就有可能很好地工作。

  4. 通过用透明像素替换像素的“旧”位置,然后用正确的颜色设置新位置,将每个像素设置为带有设置像素的纹理 2d。这使完成工作所需的像素组数量增加了一倍,并且比使用数字 2 慢得多。

所以,我的问题是,有更好的主意吗?或者关于如何修复样式 2 或 3 的想法?

4

1 回答 1

1

我的直接想法是你正在拖延 GPU 管道。GPU 可以有一个管道,它比您发出的命令滞后几帧。

因此,如果您发出命令在纹理上设置数据,而 GPU 当前正在使用该纹理来渲染旧帧,则它必须完成所有渲染才能接受新的纹理数据。所以它会等待,扼杀你的表现。

解决方法可能是在双(甚至三重或四重)缓冲区排列中使用多个纹理。不要尝试写入刚刚用于渲染的纹理。

此外 - 您可以从渲染线程以外的线程写入纹理。这可能会派上用场,特别是对于清除纹理。

正如您似乎已经发现的那样,SetData大块调用实际上更快,而不是发出许多小SetData调用。确定“块”的理想大小在 GPU 之间有所不同 - 但它比单个像素大一点。

此外,在原始性能方面,创建纹理比重用纹理要慢得多(如果您忽略我刚刚描述的管道效果);所以重用那个纹理。

值得一提的是,“像素精灵”需要向 GPU 发送的每像素数据量可能是纹理的 30 倍。

另请参阅this answer,如果您想更深入,它有更多细节和一些深入的链接。

于 2013-04-17T08:38:48.597 回答