Alex Rivera | Logout

RenderTargetBitmap and Viewport3D - Quality Issues

Asked 2010-02-01T18:24:44.487
16

I'm wanting to export a 3D scene from a Viewport3D to a bitmap.

The obvious way to do this would be to use RenderTargetBitmap -- however when I this the quality of the exported bitmap is significantly lower than the on-screen image. Looking around on the internet, it seems that RenderTargetBitmap doesn't take advantage of hardware rendering. Which means that the rendering is done at Tier 0. Which means no mip-mapping etc, hence the reduced quality of the exported image.

Does anyone know how to export a bitmap of a Viewport3D at on-screen quality?

Clarification

Though the example given below doesn't show this, I need to eventually export the bitmap of the Viewport3D to a file. As I understand the only way to do this is to get the image into something that derives from BitmapSource. Cplotts below shows that increasing the quality of the export using RenderTargetBitmap improves the image, but as the rendering is still done in software, it is prohibitively slow.

Is there a way to export a rendered 3D scene to a file, using hardware rendering? Surely that should be possible?

You can see the problem with this xaml:

<Window x:Class="RenderTargetBitmapProblem.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="400" Width="500">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Viewport3D Name="viewport3D">
            <Viewport3D.Camera>
                <PerspectiveCamera Position="0,0,3"/>
            </Viewport3D.Camera>
            <ModelVisual3D>
                <ModelVisual3D.Content>
            
Edit
Report

2 Answers

0

Using SlimDX, try accessing the DirectX surface that the ViewPort3D renders to,
then performing a read-pixel to read the buffer from the graphics card's pixel buffer into regular memory.
Once you have the (unmanaged) buffer, copy it into an existing writable bitmap using unsafe code or marshalling.

answered 2010-02-17T07:40:12.390
0

I've also had a few useful answers to this question over at the Windows Presentation Foundation forums at http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/50989d46-7240-4af5-a8b5-d034cb2a498b/.

In particular, I'm going to try these two answers, both from Marco Zhou:

Or you could try rendering the Viewport3D into a off-screen HwndSource, and then grab its HWND, and feed it into Bitblt function . The Bitblt will copy what's already rendered by the hardware rasterizer back to your own in memory buffer. I am not trying this method myself, but it's worth trying, and theoretically speaking, it should work.

and

I think one easy way without pinvoking into the WIN32 API is to place the Viewport3D into ElementHost, and call its ElementHost.DrawToBitmap(), one caveat here is that you need to call the DrawToBitmap() at the right time after the Viewport3D is "fully rendered", you could manually pump the messages by calling System.Windows.Forms.Application.DoEvents(), and hook up CompositionTarget.Rendering event to get callback from the composition thread (This might work since I am not exactly sure if the Rendering event is reliable in this typical circumstance). BTW, the above method is based on the assumption that you don't need to display the ElementHost on the screen. The ElementHost will be displayed on the screen, you could directly call the DrawToBitmap() method.

answered 2010-02-20T11:55:34.170

Your Answer