RenderTargetBitmap和Viewport3D - 质量问题 [英] RenderTargetBitmap and Viewport3D - Quality Issues

查看:406
本文介绍了RenderTargetBitmap和Viewport3D - 质量问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从一个Viewport3D导出3D场景为位图。

最明显的方式做,这是使用RenderTargetBitmap - 但是当我这个导出的位图的质量比屏幕上的图像显著降低。环顾在互联网上,似乎RenderTargetBitmap不会利用​​硬件渲染的优势。这意味着,渲染完成的 0层。这意味着没有MIP映射等,导出图像的,因此质量下降。

有谁知道如何导出Viewport3D的位图在屏幕上的质量?

澄清

虽然下面给出的例子并没有显示这一点,我需要的Viewport3D的位图,最终导出到文件中。据我了解这样做的唯一方法是让图像分割成事情源于的BitmapSource。下面Cplotts表明,增加使用RenderTargetBitmap出口的质量提高了图像,但作为呈现在软件仍然完成,它非常慢。

有没有办法来渲染3D场景导出到文件,使用硬件渲染?当然,这应该是可能的吗?

下面是一个例子......屏幕上的品质:

RenderTargetBitmapQuality:

您可以看到问题与此XAML:

 <窗​​口x:类=RenderTargetBitmapProblem.Window1
    的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml/$p$psentation
    的xmlns:X =htt​​p://schemas.microsoft.com/winfx/2006/xaml高度=400宽度=500>
    <电网>
        < Grid.RowDefinitions>
            < RowDefinition />
            < RowDefinition高度=自动/>
        < /Grid.RowDefinitions>
        < Viewport3D名称=viewport3D>
            < Viewport3D.Camera>
                < PerspectiveCamera位置=0,0,3/>
            < /Viewport3D.Camera>
            < ModelVisual3D>
                < ModelVisual3D.Content>
                    < AmbientLight颜色=白/>
                < /ModelVisual3D.Content>
            < / ModelVisual3D>
            < ModelVisual3D>
                < ModelVisual3D.Content>
                    < GeometryModel3D>
                        < GeometryModel3D.Geometry>
                            < MeshGeometry3D位置= -  1,-10,0 1,-10,0 -1,20,0 1,20,0
                                            TextureCoordinates =0,1 0,0 1,1 1,0
                                            TriangleIndices =0,1,2 1,3,2/>
                        < /GeometryModel3D.Geometry>
                        < GeometryModel3D.Material>
                            < D​​iffuseMaterial>
                                < D​​iffuseMaterial.Brush>
                                    <的ImageBrush的ImageSource =htt​​p://www.wyrmcorp.com/galleries/illusions/Hermann%20Grid.png
                                                TILEMODE =瓷砖视口=0,0,0.25,0.25/>
                                < /DiffuseMaterial.Brush>
                            < / DiffuseMaterial>
                        < /GeometryModel3D.Material>
                    < / GeometryModel3D>
                < /ModelVisual3D.Content>
                < ModelVisual3D.Transform>
                    < RotateTransform3D>
                        < RotateTransform3D.Rotation>
                            < AxisAngleRotation3D轴=1,0,0角= -  82/>
                        < /RotateTransform3D.Rotation>
                    < / RotateTransform3D>
                < /ModelVisual3D.Transform>
            < / ModelVisual3D>
        < / Viewport3D>
        <图像名称=rtbImage能见度=坍塌/>
        <按钮Grid.Row =1点击=Button_Click> RenderTargetBitmap<!/按钮>
    < /网格>
< /窗>
 

这code:

 私人无效Button_Click(对象发件人,RoutedEventArgs E)
    {
        RenderTargetBitmap BMP =新RenderTargetBitmap((INT)viewport3D.ActualWidth,
            (INT)viewport3D.ActualHeight,96,96,PixelFormats.Default);
        bmp.Render(viewport3D);
        rtbImage.Source = BMP;
        viewport3D.Visibility = Visibility.Collapsed;
        rtbImage.Visibility = Visibility.Visible;
    }
 

解决方案

目前在 RenderTargetBitmap 没有设置来告诉它使用硬件渲染,这样你才会有回落回到使用Win32或DirectX。我会建议使用这篇文章给出了DirectX技术。从文章下面的code和展示它是如何可以做到(这是C ++ code):

 的extern的IDirect3DDevice9 * g_pd3dDevice;
虚空CaptureScreen()
{
    IDirect3DSurface9 * pSurface;
    g_pd3dDevice-> CreateOffscreenPlainSurface(屏幕宽度,ScreenHeight,
        D3DFMT_A8R8G8B8,D3DPOOL_SCRATCH,&安培; pSurface,NULL);
    g_pd3dDevice-> GetFrontBufferData(0,pSurface);
    D3DXSaveSurfaceToFile(Desktop.bmp,D3DXIFF_BMP,pSurface,NULL,NULL);
    pSurface->发行();
}
 

您可以创建对应于其中WPF内容所呈现的地方Direct3D设备如下:

  1. 电话 Visual.PointToScreen 关于在您的屏幕上的图像点
  2. 电话 MonitorFromPoint 的User32.dll 获得HMONITOR
  3. 电话 Direct3DCreate9 d3d9.dll 来获得pD3D
  4. 电话 pD3D-> GetAdapterCount()来算适配器
  5. 在迭代从0开始计数1,并呼吁 pD3D-> GetAdapterMonitor()和pviously检索HMONITOR的$ P $比较,以确定适配器指数
  6. 电话 pD3D-> CreateDevice的()以创建设备本身

我可能会做这个最独立的库codeD在C ++ / CLR,因为这种方法是我熟悉的,但你会发现它很容易将其转换为纯C#和使用使用管理code SlimDX。我还没有尝试过呢。

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?

Here's an example... on-screen quality:

RenderTargetBitmapQuality:

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>
                    <AmbientLight Color="White"/>
                </ModelVisual3D.Content>
            </ModelVisual3D>
            <ModelVisual3D>
                <ModelVisual3D.Content>
                    <GeometryModel3D>
                        <GeometryModel3D.Geometry>
                            <MeshGeometry3D Positions="-1,-10,0  1,-10,0  -1,20,0  1,20,0"
                                            TextureCoordinates="0,1 0,0 1,1 1,0"
                                            TriangleIndices="0,1,2 1,3,2"/>
                        </GeometryModel3D.Geometry>
                        <GeometryModel3D.Material>
                            <DiffuseMaterial>
                                <DiffuseMaterial.Brush>
                                    <ImageBrush ImageSource="http://www.wyrmcorp.com/galleries/illusions/Hermann%20Grid.png"
                                                TileMode="Tile" Viewport="0,0,0.25,0.25"/>
                                </DiffuseMaterial.Brush>
                            </DiffuseMaterial>
                        </GeometryModel3D.Material>
                    </GeometryModel3D>
                </ModelVisual3D.Content>
                <ModelVisual3D.Transform>
                    <RotateTransform3D>
                        <RotateTransform3D.Rotation>
                            <AxisAngleRotation3D Axis="1,0,0" Angle="-82"/>
                        </RotateTransform3D.Rotation>
                    </RotateTransform3D>
                </ModelVisual3D.Transform>
            </ModelVisual3D>
        </Viewport3D>
        <Image Name="rtbImage" Visibility="Collapsed"/>
        <Button Grid.Row="1" Click="Button_Click">RenderTargetBitmap!</Button>
    </Grid>
</Window>

And this code:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        RenderTargetBitmap bmp = new RenderTargetBitmap((int)viewport3D.ActualWidth, 
            (int)viewport3D.ActualHeight, 96, 96, PixelFormats.Default);
        bmp.Render(viewport3D);
        rtbImage.Source = bmp;
        viewport3D.Visibility = Visibility.Collapsed;
        rtbImage.Visibility = Visibility.Visible;
    }

解决方案

There is no setting on RenderTargetBitmap to tell it to render using hardware, so you will have to fall back to using Win32 or DirectX. I would recommend using the DirectX technique given in this article. The following code from the article and shows how it can be done (this is C++ code):

extern IDirect3DDevice9* g_pd3dDevice;
Void CaptureScreen()
{
    IDirect3DSurface9* pSurface;
    g_pd3dDevice->CreateOffscreenPlainSurface(ScreenWidth, ScreenHeight,
        D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pSurface, NULL);
    g_pd3dDevice->GetFrontBufferData(0, pSurface);
    D3DXSaveSurfaceToFile("Desktop.bmp",D3DXIFF_BMP,pSurface,NULL,NULL);
    pSurface->Release(); 
}

You can create the Direct3D device corresponding to the place where the WPF content is being rendered as follows:

  1. Calling Visual.PointToScreen on a point within your onscreen image
  2. Calling MonitorFromPoint in User32.dll to get the hMonitor
  3. Calling Direct3DCreate9 in d3d9.dll to get a pD3D
  4. Calling pD3D->GetAdapterCount() to count adapters
  5. Iterating from 0 to count-1 and calling pD3D->GetAdapterMonitor() and comparing with the previously retrieved hMonitor to determine the adapter index
  6. Calling pD3D->CreateDevice() to create the device itself

I would probably do most of this in a separate library coded in C++/CLR because that approach is familiar to me, but you may find it easy to translate it to pure C# and managed code using using SlimDX. I haven't tried that yet.

这篇关于RenderTargetBitmap和Viewport3D - 质量问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆