Gro*_*kys 16 .net c# 3d wpf rendertargetbitmap
我想将一个3D场景从Viewport3D导出到位图.
显而易见的方法是使用RenderTargetBitmap - 但是当我这样做时,导出的位图的质量明显低于屏幕上的图像.环顾四周,似乎RenderTargetBitmap没有利用硬件渲染.这意味着渲染在第0层完成.这意味着没有mip-mapping等,因此降低了导出图像的质量.
有谁知道如何以屏幕质量导出Viewport3D的位图?
澄清
虽然下面给出的示例没有显示这一点,但我最终需要将Viewport3D的位图导出到文件中.据我所知,唯一的方法是将图像转换为从BitmapSource派生的东西.下面的Cplotts显示使用RenderTargetBitmap提高导出质量可以改善图像,但由于渲染仍然在软件中完成,因此速度极慢.
有没有办法使用硬件渲染将渲染的3D场景导出到文件?当然应该可以吗?
你可以看到这个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>
Run Code Online (Sandbox Code Playgroud)
这段代码:
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;
}
Run Code Online (Sandbox Code Playgroud)
没有设置RenderTargetBitmap告诉它使用硬件进行渲染,因此您将不得不回归使用Win32或DirectX.我建议使用本文中给出的DirectX技术.本文中的以下代码显示了它是如何完成的(这是C++代码):
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();
}
Run Code Online (Sandbox Code Playgroud)
您可以创建与呈现WPF内容的位置对应的Direct3D设备,如下所示:
Visual.PointToScreen屏幕图像中的某个点MonitorFromPoint在User32.dll拿到HMONITORDirect3DCreate9在d3d9.dll获得pD3DpD3D->GetAdapterCount()数适配器pD3D->GetAdapterMonitor()并与之前检索的hMonitor进行比较以确定适配器索引pD3D->CreateDevice()创建设备本身我可能会在一个用C++/CLR编写的单独库中完成大部分工作,因为我很熟悉这种方法,但您可能会发现使用SlimDX将其转换为纯C#和托管代码很容易. 我还没有尝试过.