How do I plot individual pixels using the XNA APIs?
If I wanted to fill my game screen with individually coloured pixels, how would I do this?
For example, if I wanted to write a 'game of life'-type game where each pixel was a cell, how would I achieve this using XNA?
I've tried just calling SetData()
on a Texture2D
object using a开发者_运维问答 screen-sized array of Color
values, but it complains with:
You may not call SetData on a resource while it is actively set on the GraphicsDevice.
Unset it from the device before calling SetData.
How do I do as it asks? Or better still... is there an alternative, better, efficient way to fill a screen with arbitrary pixels?
Regarding the error you're getting, it means you're attempting to modify the texture data while it is still bound to one of the sampler units on the device. Are you calling SetData inside of a SpriteBatch.Begin/End block? If you are, that's the problem (update your texture before you do any drawing). Otherwise are you setting your texture directly on one of the device's texture samplers, with GraphicsDevice.Textures[x] = yourTexture? If you are, set Textures[x] to null before you start changing the data.
As far as the efficiency of what you're doing, it's not ideal, but it probably doesn't matter for your purposes. Try to keep the image resolution reasonable and realize you're probably not going to hit 200 FPS with this approach, but I would try it and see if it's fast enough, before you start worrying about performance.
After setting the data on a Texture2D you cannot change it anymore. The way to get around this is by creating a 1x1 Texture2D and set its color to white. You will then draw it with a tint of what color you want the pixel to be. Since your texture is white, the desired color will come out shaded perfectly your color of choice.
Texture2D pixel = new Texture2D(App.GraphicsDevice, 1, 1);
colors = new Color[1];
colors[0] = Color.White;
pixel.SetData(colors);
This is a sample function to draw your pixel, using the pixel from above.
public void DrawPixel(SpriteBatch spriteBatch, Vector2 pos, Color tint)
{
spriteBatch.Draw(pixel, pos, tint);
}
Reuse this Texture2D for every pixel draw.
The most ideal approach would be to get your shader to do it for you. I've implemented a game of life simulation before using only shaders, and others have done the same with XNA http://www.xnainfo.com/content.php?content=21.
The idea is to use two textures, one for the old state and one for the new state. Set it up so that you render to your new texture and read from the old one. You can do your cellular autonoma directly in the shader :).
You can get great performance with this, I had about 300fps using a 1024x1024 grid.
You can use the technique I mention here to draw rectangles using SpriteBatch. You could then use that to draw 1x1 rectangles which cover the screen. I don't know how performant that would be but it should work.
This App Hub post seems to talk about the exact problem you're trying to solve.
精彩评论