如何在XNA中逐个像素地绘制?

时间:2011-01-29 14:46:53

标签: c# xna 2d

我正在尝试使用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<UInt32>(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。看起来我正试图以错误的方式做到这一点,我还有什么其他选择才能让它发挥作用?

2 个答案:

答案 0 :(得分:6)

在调用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<UInt32>(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);
}

答案 1 :(得分:3)

你基本上需要在异常中提出要求:

为确保未在图形设备上设置纹理,请将其放在Draw的末尾:

GraphicsDevice.Textures[0] = null;

为确保您没有在平铺括号内绘图,请不要在SetData内使用Draw。将来电SetData移至Update


奖励信息:您的内存不足错误是因为您没有释放Texture2D分配的非托管资源(垃圾收集器无法跟踪它们,所以它不知道您已经用完了记忆)。您需要在纹理上调用Dispose。然而,无论如何都要在每个帧中创建一个新的纹理(没有办法避免它导致的性能和内存碎片问题)。