XNA Creators Club Online
Page 1 of 1 (9 items)
Sort Posts: Previous Next

Sanity check on output grab for RenderTarget2D

Last post 10/23/2009 9:00 PM by klempie. 8 replies.
  • 10/15/2009 12:10 PM

    Sanity check on output grab for RenderTarget2D

    I'm wanting to take a "screenshot" of my XNA output and want to double check my approach before I continue. Is the following correct?

    1. Get RenderTarget2D from GraphicsDevice object using GraphicsDevice.GetRenderTarget()
    2. Get Texture2D from RenderTarget2D object using RenderTarget2D.GetTexture()
    3. In my case, I want to copy the data into a System.Drawing.Bitmap but I can't see a function for simply setting the buffer array. It only has Bitmap.SetPixel() so it looks like I will have to copy data into a Color buffer using Texture2D and then iterate through the image and set the values using Bitmap.SetPixel().

    The ideal scenario would be just supplying the byte array in the Bitmap to RenderTarget2D.GetTexture() (assuming I use the right SurfaceFormat) and set it once. Is there a way to do this to avoid Bitmap.SetPixel()?

    TIA.
  • 10/15/2009 1:32 PM In reply to

    Re: Sanity check on output grab for RenderTarget2D

  • 10/15/2009 1:39 PM In reply to

    Re: Sanity check on output grab for RenderTarget2D

    Answer
    Reply Quote
    klempie:
    I'm wanting to take a "screenshot" of my XNA output and want to double check my approach before I continue. Is the following correct?

    1. Get RenderTarget2D from GraphicsDevice object using GraphicsDevice.GetRenderTarget()
    2. Get Texture2D from RenderTarget2D object using RenderTarget2D.GetTexture()
    3. In my case, I want to copy the data into a System.Drawing.Bitmap but I can't see a function for simply setting the buffer array. It only has Bitmap.SetPixel() so it looks like I will have to copy data into a Color buffer using Texture2D and then iterate through the image and set the values using Bitmap.SetPixel().

    The ideal scenario would be just supplying the byte array in the Bitmap to RenderTarget2D.GetTexture() (assuming I use the right SurfaceFormat) and set it once. Is there a way to do this to avoid Bitmap.SetPixel()?

    TIA.

    1. Create a RenderTarget with new RenderTarget2D(<parameters>). Render to it with GraphicsDevice.SetRenderTarget(rendertarget). After rendering unhook it with SetRenderTarget(null).
    2. yup.
    3. Unless you want to output video, setpixel works fine. if you want more performance, you can write large portions of data using the LockBits() functionality. You have to do a GetData() from the texture at least once, because the texture is on the graphics card but the bitmap is not.

  • 10/16/2009 4:17 PM In reply to

    Re: Sanity check on output grab for RenderTarget2D

     public static unsafe System.Drawing.Bitmap GetBmp(Texture2D t) 
            { 
                int width, height; 
                width = t.Width; 
                height = t.Height; 
                uint[] d = new uint[width * height]; 
                t.GetData<uint>(d, 0, d.Length); 
     
                System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(t.Width, t.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); 
                System.Drawing.Imaging.BitmapData bmpd = bmp.LockBits(new System.Drawing.Rectangle(0, 0, width, height), 
                                                                        System.Drawing.Imaging.ImageLockMode.WriteOnly, 
                                                                        System.Drawing.Imaging.PixelFormat.Format32bppArgb); 
     
                uint* ptr = (uint*)bmpd.Scan0.ToPointer(); 
                for (int x = 0; x < width; x++) 
                    for (int y = 0; y < height; y++) 
                    { 
                        ptr[x + y * width] = d[x + y * width]; 
                    } 
                bmp.UnlockBits(bmpd); 
                return bmp; 
            } 

    I am not aware that there exists a blit operation so you will have to do it per pixel but unless you have a lot of huge textures per second that's not a problem.
    Of course you have to check the format and adjust.

    HTH
    Riki
  • 10/23/2009 7:32 PM In reply to

    Re: Sanity check on output grab for RenderTarget2D

    Thanks everyone. Sorry I've taken so long to get back to you all but I had some other stuff to implement before I got to this screengrab.

    I've gone with a derivative of Korenn's code and this works nicely. I prefer Eriba's method in terms of performance but for other developers who aren't familiar with unsafe code who may work on it in the future, I decided to go with the simpler managed version.

    Anyway, I'm successfully drawing to a second render target and saving it as a bitmap. Only problem is that I'm restricted by the fact that all the render targets have to have the same dimensions. The on screen target resolution is too low to look any good on blown up print out so what I want is to create a bigger render target with the same aspect ratio and save that as the bitmap. Is there anyway I can do this programmatically behind the scenes or will I have to resort to replicating the output in a bigger onscreen "preview" window (not ideal in our application)?

  • 10/23/2009 7:37 PM In reply to

    Re: Sanity check on output grab for RenderTarget2D

    Rendertargets don't have to be the same size as the screen or backbuffer. You can make them any size up to the max supported by your graphics cards (typically 2048, although some cards can go higher).
    XNA Framework Developer - blog - homepage
  • 10/23/2009 7:44 PM In reply to

    Re: Sanity check on output grab for RenderTarget2D

    Shawn Hargreaves:
    Rendertargets don't have to be the same size as the screen or backbuffer. You can make them any size up to the max supported by your graphics cards (typically 2048, although some cards can go higher).


    Thanks for the speedy reply Shawn.

    When I execute this code

     

     

    RenderTarget2D target = new RenderTarget2D(GraphicsDevice, 600,(int) (600 / GraphicsDevice.Viewport.AspectRatio), 1, GraphicsDevice.PresentationParameters.BackBufferFormat);  
     
    GraphicsDevice.SetRenderTarget(0, target);  
     
    GraphicsDevice.Clear(Microsoft.Xna.Framework.Graphics.Color.White);  
     

    I get an exception on the call to Clear saying "All active render targets must be the same size with the same multisample type." Given your reply, I'm obviously doing something wrong in setting up the render target. Can you spot what it is?

  • 10/23/2009 8:41 PM In reply to

    Re: Sanity check on output grab for RenderTarget2D

    You need to make a depth buffer the same size as your rendertarget, or clear the depth buffer to null.
    XNA Framework Developer - blog - homepage
  • 10/23/2009 9:00 PM In reply to

    Re: Sanity check on output grab for RenderTarget2D

    That, sir, works great. Thanks very much. One last question for my own edification. Does "active render targets" refer to the screen and backbuffer targets only?
Page 1 of 1 (9 items) Previous Next