尝试在最近由 SpriteBatch 进行 Draw()-n 的 Texture2D 上执行 SetData() 会导致以下异常:
操作被中止。您不得修改已在设备上设置的资源,或在平铺括号内使用该资源后的资源。
我可以提前判断执行SetData()是否会抛出这个异常吗?
基本上,您有三种选择:
1)查看SpriteBatch是否完成其操作,然后调用SetData()。绘图方法通常是异步的。这意味着,它们只是被添加到 please-render-me 队列中,并且该方法立即返回。您需要的是绘图完成时的回调通知或同步调用 Draw()。
2) 避免 SetData() 被中断。您可以通过将其放入我不推荐的关键部分来做到这一点。应该可以锁定纹理数据。在Direct3D中叫做LockRect(),在XNA中应该类似。
3)应该有一些像 Flush() 这样的方法等待所有与图形相关的操作完成。
抱歉提供了相当模糊的帮助,但您应该能够从 XNA 文档中找到方法名称。
我通过创建两个纹理并在活动纹理之间切换(本质上是双缓冲)解决了这样的问题:
void CreateTextures()
{
depth_1 = new Texture2D(this.GraphicsDevice, width, height, false, SurfaceFormat.Single);
depth_2 = new Texture2D(this.GraphicsDevice, width, height, false, SurfaceFormat.Single);
depth_current = depth_1;
...
}
void Draw(GameTime gt)
{
depth_current = depth_current == depth_1 ? depth_2 : depth_1;
Depth.SetData(this.DepthBuffer);
...
}
就我而言,无法将
SetData
移到 Draw 之外,但我认为这是最好的方法。
基本上没有。
最简单的方法是仅在
SetData
方法中调用 Update
。
在
SetData
方法中使用 Draw
是不好的做法,因为设备可能会使用旧数据执行各种巫毒魔法。 其 MSDN 页面上的“警告”框中对此进行了详细解释。
SetDataOptions
与 Texture2D.SetData
一起使用。但看起来该功能已在 XNA 4.0 中删除了纹理。
Shawn Hargreaves 在此解释 如何使用 SetDataOptions
告诉 GPU“实际上是的,我确实想要覆盖您可能正在使用的数据,请不要抱怨”。以及为什么很难做到正确。