代码之家  ›  专栏  ›  技术社区  ›  Colton

设置像素数据的最佳方式?

  •  2
  • Colton  · 技术社区  · 11 年前

    我正在研究一种“落沙”风格的游戏。

    我试过很多种把沙子画到屏幕上的方法,然而,每种方法似乎都会以某种形式产生一些问题。

    我经历过的事情列表:

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

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

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

    4. 通过将像素的“旧”位置替换为透明像素,然后将新位置设置为适当的颜色,将每个像素设置为具有设置像素的texture2d。这使完成任务所需的像素集数量增加了一倍,并且比使用数字2慢得多。

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

    1 回复  |  直到 11 年前
        1
  •  2
  •   Community Ian Goodfellow    7 年前

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

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

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

    此外,您可以从渲染线程以外的线程写入纹理。这可能会派上用场,尤其是在清除纹理时。

    正如你似乎已经发现的那样,实际上 SetData 大量发行,而不是大量发行 设置数据 电话。确定“块”的理想大小在GPU之间有所不同,但它比单个像素大一点。

    此外,从原始性能的角度来看,创建纹理要比重用纹理慢得多(如果忽略我刚才描述的管道效果);所以重复使用该纹理。

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

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