Introduction
WPF与WinForm, DirectX与GDI
众所周知, WPF使用了DirectX作为底层的渲染技术, 截至今日, 仍然使用着DirectX 9 (.Net和.Net Core实现均是如此).
作为对比, Windows Form使用的是GDI/GDI+技术.
GDI/GDI+ 全称是 Graphics Device Interface
, 有着30+年的历史, 它是一个用于操作图像和执行绘图的API, 几乎在所有的windows应用程序中都使用. 其中GDI+是GDI的升级版本, 出现在Windows XP版本中, 增加了渐变笔刷、样条、多种图片格式支持等等.
GDI/GDI+在.NET中,封装存在于System.Drawing.dll
程序集中. GDI/GDI+是2D渲染API, 基于cpu实现, 假设你要画一个Cube,你必须在cpu上先处理好Cube的图片数据,然后才能指挥驱动进行在画布上绘制.
而DirectX(和OpenGL)则完全依赖于显卡做图形图像运算, 他们从计算单元的设计理念就不同. CPU是通用指令,能干许多复杂的运算(包括3D运算), 只是支持的多考虑的多显得效率好像“差“了; GPU只有有限的专用指令,它的涉及是通过并行方式执行大量的重复运算, 且浮点运算是强项, 在像素运算效率上比CPU高几个数量级, 但它并不通用.
WPF 3D
在我看来, WPF 3D更像是一个为了证明.Net能力的炫酷玩具, 并不适合用在模型渲染这个场景中. 由于大量使用了依赖属性, 在需要频繁更新的场景性能并不好. 同时 WPF只支持自定义PixelShader和不支持自定义Brush, 很多效果实现过程会非常曲折.
WPF 3D中比较重要的概念有 Viewport3D
视口, Camera
相机, Model3D
模型. 这里提供了一个小 Demo, 仅做示意, 更多的内容参见 WPF文档.
<Window x:Class="WpfApp.WPF3D"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp2"
mc:Ignorable="d"
Title="WPF3D" Height="450" Width="800">
<Grid>
<Viewport3D >
<Viewport3D.Camera>
<PerspectiveCamera Position="6 5 4" LookDirection="-6 -5 -4">
</PerspectiveCamera>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Direction="-1,-1,-1">
</DirectionalLight>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="0 0 0 1 0 0 0 1 0 1 1 0 0 0 1 1 0 1 0 1 1 1 1 1"
TriangleIndices="2 3 1 2 1 0 7 1 3 7 5 1 6 5 7 6 4 5 6 2 0 2 0 4 2 7 3 2 6 7 0 1 5 0 5 4">
</MeshGeometry3D>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush Color="Red"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Grid>
</Window>
Helix Toolkit
Helix Toolkit 是一个用于.NET框架的3D组件集合. Helix Toolkit被设计为在XAML上提供模型级属性的绑定 (类似于WPF 3D的工作方式,比如用XAML创建一个场景图 ), 这与一般的游戏引擎设计并不相同. 游戏引擎通常提供自己的编辑器供用户使用,并直接抽象出使用引擎的复杂性. 简单来说 Helix Toolkit是为了提供便捷的 3D 渲染能力, 而非为了追求制作庞大繁杂的交互程序.
Helix Toolkit分为许多个类库, 大致可划分为:
- HelixToolkit
- DX9 Backend (.NET WPF)
- HelixToolkit.WPF
- DX11 Backend (Sharpdx)
- .NET WPF
- HelixToolkit.WPF.SharpDX (文章围绕这点)
- UWP
- Helixtoolkit.UWP
- .NET CORE
- HelixToolkit.SharpDX.Core
- HelixToolkit.SharpDX.Core.Wpf
- HelixToolkit.SharpDX.Core
- HelixToolkit.Assimp
- .NET WPF
- DX9 Backend (.NET WPF)
SharpDX
SharpDX (不再维护) 使用 C# 封装了提供完整的 DirectX API, 供开发高性能的游戏、2D和3D图形渲染以及实时声音应用. 截止到停止维护前, SharpDX 已经支持 DX12 的相关API.
由于 WPF 提供了一个 D3DImage
可以把 DirectX 的渲染的结果画到WPF的窗体里, Helix Toolkit 通过 SharpDX 封装的API, 使用DX11做渲染, 配合XAML和依赖属性数据绑定, 提供了相当舒适的开发体验.
Get Start
这里同样用一个简单的Demo来说明:
<Window x:Class="WpfApp.WPF3D"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp2"
xmlns:hx="http://helix-toolkit.org/wpf/SharpDX"
mc:Ignorable="d"
Title="WPF3D" Height="450" Width="800">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<Grid>
<hx:Viewport3DX Camera="{Binding Camera}" EffectsManager="{Binding EffectsManager}">
<hx:GroupModel3D>
<hx:DirectionalLight3D Direction="0, 0, -1" Color="White" />
<hx:DirectionalLight3D Direction="0, -1, 0" Color="White"/>
<hx:DirectionalLight3D Direction="-1, -1, 0" Color="White"/>
</hx:GroupModel3D>
<hx:GroupModel3D>
<hx:SpotLight3D Direction="0, 1, 0" Color="Red" Position="0, -2, 0"/>
<hx:PointLight3D Position="3, 0, 0" Color="Green"/>
</hx:GroupModel3D>
<hx:MeshGeometryModel3D Geometry="{Binding CubeMesh}" Material="{Binding Red}" />
</hx:Viewport3DX>
</Grid>
</Window>
public class ViewModel
{
public EffectsManager EffectsManager { get; }
public Camera Camera { get; }
public Geometry3D CubeMesh { get; }
public Material Red { get; }
public ViewModel()
{
EffectsManager = new DefaultEffectsManager();
Camera = new PerspectiveCamera();
var builder = new MeshBuilder();
builder.AddCube();
CubeMesh = builder.ToMesh();
Red = PhongMaterials.Red;
}
}
EffectsManager
EffectsManager
包含并处理所有共享的DirectX资源, 如网格缓冲区和纹理. 通常情况下 DefaultEffectsManager
已经足够满足简单的渲染需求. 使用 EffectsManager 时应注意:
- 在每个 UI 线程中使用EffectsManager, 不要在不同的线程之间共享EffectsManager
- 如果不再需要EffectsManager, 必须调用
EffectsManager.Dispose()
来释放所有资源. 如果不处置EffectsManager,会导致严重的内存泄漏问题.
Viewport3DX
Viewport3DX支持非常多的DX特性, 像D2DRendering
SwapChainRendering
FXAA
MSAA
SSAO
等.
SwapChainRendering
在渲染的过程中, 显卡有一个被称为
front buffer
的区域存放着屏幕正在显示的图像, 随着屏幕不断刷新, 显卡会不断将front buffer
的内容发送给屏幕显示. 但是由于屏幕的刷新频率往往慢于电脑的后台计算, 如果在屏幕刷新过程中更新front buffer
, 显示的图像将会一部分包含旧图像, 一部分包含新图像. 这个问题被称为撕裂.为了解决撕裂问题, 产生了后台缓冲技术. 后台缓冲技术除了
front buffer
区域, 同时还有back buffer
区域, 显卡不直接更新front buffer
, 而是通过在空闲时渲染至back buffer
, 在需要时通过交换两个buffer的指针, 来达到刷新屏幕的效果.
ModelUpDirection
在计算机渲染中, 通常采用y轴向上的坐标系 (左手坐标系). 而在建筑模型中, 更常用的是z轴向上的坐标系 (右手坐标系). Viewport3DX中提供了一个属性做全局设置坐标系方向.
Camera
Helix Toolkit 同样默认提供正交相机OrthographicCamera
和透视相机PerspectiveCamera
两种.
Material
Helix Toolkit 支持多种材质:
- Normal Material
- Phong Material
- Diffuse Material
- Point Material
- Line Material
- PBR Material
- etc.
Geometry
Helix Toolkit 内置多种几何对象:
- GeometryModel3D
- MeshGeometryModel3D
- CameraModel3D
- GroupModel3D
- ViewBoxModel3D
- etc.
其中最常用的就是 MeshGeometryModel3D
, MeshGeometryModel3D需要构造一个Mesh
和赋予一个 Material
, Mesh为常见的三角面片结构.
Shader
Helix Toolkit 有着完整的Shader Pipeline支持 (VS, HS, DS, GS, PS, CS).