如何在XNA中逐个像素地绘制?
我正在尝试使用XNA逐个像素地在屏幕上绘图,但是我遇到了资源问题。 我认为最好的方法是使用1个纹理来更新每一帧,但是我无法更新它。 这是我到目前为止所做的,就像测试一样:
Texture2D canvas; Rectangle tracedSize; UInt32[] pixels; protected override void Initialize() { tracedSize = GraphicsDevice.PresentationParameters.Bounds; canvas = new Texture2D(GraphicsDevice, tracedSize.Width, tracedSize.Height, false, SurfaceFormat.Color); pixels = new UInt32[tracedSize.Width * tracedSize.Height]; base.Initialize(); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); pixels[100] = 0xFF00FF00; canvas.SetData(pixels, 0, tracedSize.Width * tracedSize.Height); spriteBatch.Begin(); spriteBatch.Draw(canvas, new Rectangle(0, 0, tracedSize.Width, tracedSize.Height), Color.White); spriteBatch.End(); base.Draw(gameTime); }
当第二次调用Draw()时,我收到以下错误:
“操作已中止。您不能修改已在设备上设置的资源,也不能修改在平铺括号内使用的资源。”
如果我尝试在Draw()中创建一个新的Texture2D,我很快就会出现内存不足错误。 这适用于Windows Phone。 似乎我试图以错误的方式做到这一点,我还有什么其他选择才能让它发挥作用?
在调用SetData之前,请尝试设置GraphicsDevice.Textures[0] = null
。 根据您之后可能有更高效的方法的效果,您还可以考虑Silverlight WriteableBitmap。
编辑:这是我在模拟器中测试的代码:
Texture2D canvas; Rectangle tracedSize; UInt32[] pixels; protected override void Initialize() { tracedSize = GraphicsDevice.PresentationParameters.Bounds; canvas = new Texture2D(GraphicsDevice, tracedSize.Width, tracedSize.Height, false, SurfaceFormat.Color); pixels = new UInt32[tracedSize.Width * tracedSize.Height]; base.Initialize(); } Random rnd = new Random(); protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); GraphicsDevice.Textures[0] = null; pixels[rnd.Next(pixels.Length)] = 0xFF00FF00; canvas.SetData(pixels, 0, tracedSize.Width * tracedSize.Height); spriteBatch.Begin(); spriteBatch.Draw(canvas, new Rectangle(0, 0, tracedSize.Width, tracedSize.Height), Color.White); spriteBatch.End(); base.Draw(gameTime); }
你基本上需要在exception中提出要求:
要确保未在图形设备上设置纹理,请将其放在Draw
的末尾:
GraphicsDevice.Textures[0] = null;
为确保您没有在平铺括号内Draw
,请不要在Draw
中使用SetData
。 将调用SetData
移动到Update
。
额外信息:您的内存不足错误是因为您没有释放Texture2D
分配的非托管资源(垃圾收集器无法跟踪它们,因此它不知道您的内存不足)。 您需要在纹理上调用Dispose
。 然而,无论如何在每个帧中创建一个新的纹理是一个坏主意(没有办法避免它导致的性能和内存碎片问题)。