尝试在最近使用SpriteBatch的Draw() - n的Texture2D上执行SetData()会导致以下异常:
操作已中止。您不能修改已在设备上设置的资源,也不能修改在平铺括号中使用的资源。
我可以事先确定执行SetData()是否会抛出此异常吗?
答案 0 :(得分:1)
基本上,您有三种选择:
1)看看SpriteBatch是否完成了它的操作,然后调用了SetData()。绘图方法通常是异步的。这意味着,它们只是被添加到please-render-me队列中,并且该方法立即返回。您需要的是绘图完成时的回调通知或Draw()的同步调用。
2)避免SetData()被中断。你可以把它放到一个我不推荐的关键部分。应该可以锁定纹理数据。它在Direct3D中称为LockRect(),它在XNA中应该类似。
3)应该有一些像Flush()这样的方法,等待所有与图形相关的操作完成。
对于相当含糊的帮助感到抱歉,但您应该能够从XNA文档中找到方法名称。
答案 1 :(得分:1)
基本上没有。
最简单的方法是只在SetData
方法中拨打Update
。
在SetData
方法中使用Draw
是不好的做法,因为该设备可能会使用旧数据执行各种巫毒魔法。详细解释了in the "Caution" box on its MSDN page。
现在,直到XNA 3.1,您可以将SetDataOptions
与Texture2D.SetData
一起使用。但看起来纹理的功能已经removed in XNA 4.0。
Shawn Hargreaves explains here如何使用SetDataOptions
告诉GPU“实际上是的,我做想要覆盖您可能正在使用的数据,不要抱怨”。为什么很难做对。
答案 2 :(得分:1)
我通过创建两个纹理并在活动的纹理之间切换来解决这样的问题,基本上是双缓冲:
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之外,但我认为这是最好的方法。