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>

WPF 3D Demo

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.Assimp

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;
    }
}

Helix Toolkit Demo

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的指针, 来达到刷新屏幕的效果.

SwapChain

  • 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).