RenderTargetBitmap和Viewport3D - 质量问题 [英] RenderTargetBitmap and Viewport3D - Quality Issues
问题描述
我想从一个Viewport3D导出3D场景为位图。
最明显的方式做,这是使用RenderTargetBitmap - 但是当我这个导出的位图的质量比屏幕上的图像显著降低。环顾在互联网上,似乎RenderTargetBitmap不会利用硬件渲染的优势。这意味着,渲染完成的 0层。这意味着没有MIP映射等,导出图像的,因此质量下降。
有谁知道如何导出Viewport3D的位图在屏幕上的质量?
澄清
虽然下面给出的例子并没有显示这一点,我需要的Viewport3D的位图,最终导出到文件中。据我了解这样做的唯一方法是让图像分割成事情源于的BitmapSource。下面Cplotts表明,增加使用RenderTargetBitmap出口的质量提高了图像,但作为呈现在软件仍然完成,它非常慢。
有没有办法来渲染3D场景导出到文件,使用硬件渲染?当然,这应该是可能的吗?
下面是一个例子......屏幕上的品质:
RenderTargetBitmapQuality:
您可以看到问题与此XAML:
<窗口x:类=RenderTargetBitmapProblem.Window1
的xmlns =http://schemas.microsoft.com/winfx/2006/xaml/$p$psentation
的xmlns:X =http://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>
< DiffuseMaterial>
< DiffuseMaterial.Brush>
<的ImageBrush的ImageSource =http://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设备如下:
- 电话
Visual.PointToScreen
关于在您的屏幕上的图像点 - 电话
MonitorFromPoint
在的User32.dll
获得HMONITOR - 电话
Direct3DCreate9
在d3d9.dll
来获得pD3D - 电话
pD3D-> GetAdapterCount()
来算适配器 - 在迭代从0开始计数1,并呼吁
pD3D-> GetAdapterMonitor()
和pviously检索HMONITOR的$ P $比较,以确定适配器指数李> - 电话
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:
- Calling
Visual.PointToScreen
on a point within your onscreen image - Calling
MonitorFromPoint
inUser32.dll
to get the hMonitor - Calling
Direct3DCreate9
ind3d9.dll
to get a pD3D - Calling
pD3D->GetAdapterCount()
to count adapters - Iterating from 0 to count-1 and calling
pD3D->GetAdapterMonitor()
and comparing with the previously retrieved hMonitor to determine the adapter index - 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屋!