How to save a scene in higher resolution?

Started by
20 comments, last by hlee 10 years, 7 months ago


D3D definitely supports rendering to targets that are bigger than the screen. I suspect your problem is one of:

You are absolutely right about the depth buffer. After creating a depth stencil surface that matches the render target I can now get the full frame. Thank you so much!

However, MultiSampleType must be set to D3DMULTISAMPLE_NONE for the render target, otherwise the GetRenderTargetData would return D3DERR_INVALIDCALL. Without multisample I might as well just capture the screen with a lower resolution but with anti-aliasing. Is there a way to use multisample in this method?

Advertisement

Well, I don't know what extra advice to give you that hasn't been said before, but you have inspired me to add a super screenshot mode to my engine. A special hotkey that when pressed will save a superb quality screenshot with normal or super-high quality/resolution. I'm estimating that at the highest quality setting the engine will consume about 2 GiB or RAM and spend 5-10 second creating one screenshot smile.png.

I'll let you know how it turns out.

Great. Let me know how you do it and if you can turn on anti-aliasing in the high resolution screenshot.

If you look at the documentation for GetRenderTargetData() you'll see:

This method will fail if:

  • The render target is multisampled.

The standard solution to that is to use StretchRect() to copy it to a non-multisampled render target.

However in your case I'd just increase the resolution and downsize the result in some image editing software - you'll get better quality that way.


The standard solution to that is to use StretchRect() to copy it to a non-multisampled render target.

That's it! This is what works:

1. Create a large multisampled RT, called it RT1, along with a depth buffer

2. Render the scene to RT1

3. Create a non-multisampled RT, called it RT2, the same size as RT1

4. StretchRect RT1 to RT2

5. Use GetRenderTargetData to copy RT2 to an OffscreenPlainSurce

6. Use D3DXSaveSurfaceToFile to save the OffscreenPlainSurce

Now I get a high resolution, multiampled scene. Thanks so much, Adam!

But why does it have to be so cumbersome? Why can't D3DXSaveSurfaceToFile save a mutisampled RT directly?

The way multisampling works is that D3D internally creates an extra large render target and depth buffer (e.g. for 4X it's double the width and height).

However, when rendering to it the pixel shader isn't re-run for each extra pixel, but the depth test is. That gives significantly better performance than rendering to a double sized render target, at the cost of a bit of quality - it won't solve aliasing that's caused by the shader, which manually rendering at double the size then downsizing will do.

There's usually also some hardware trickery in there to accelerate the common case where all of the antialiased samples for one output pixel are identical by storing the data a bit differently.

The shader aliasing is why I said you want to just render to a bigger texture and downsize it yourself. Doing that also means you need less GPU memory.

The reason you need the StretchRect() step is that the GPU needs to decode and downsize the extra large render target to an antialiased one of the right size before you can read it back with either a shader or the CPU.

StrechRect will work, but will probably perform poorly. You are effectively using SSAA at this point and there is a good reason most games don't offer this option.

But since you want to capture screenshots, I would recommend rendering your high resolution texture as a full screen quad and using high quality down-sampling filter implemented in the pixel shader. Or do it in an external program once the screenshot is saved.

5. Use D3DXSaveTextureToFile to save RT2 directly to a file

5. Use D3DXSaveTextureToFile to save RT2 directly to a file

D3DXSaveTextureToFile complains that RT2 is not a texture. If I'd created RT2 as a texture then StrectRec would complain that RT2 is not a IDirect3DSurface9. How can I make it to work?

How about using D3DXSaveSurfaceToFile wink.png

This topic is closed to new replies.

Advertisement