WPF开发快速入门【8】WPF进行简单的3D开发

  • WPF开发快速入门【8】WPF进行简单的3D开发已关闭评论
  • 174 次浏览
  • A+
所属分类:.NET技术
摘要

概述 本文介绍采用WPF进行3D开发的一些基础知识,还有HelixToolkit控件的介绍以及在MVVM模式下使用3D框架。

概述

本文介绍采用WPF进行3D开发的一些基础知识,还有HelixToolkit控件的介绍以及在MVVM模式下使用3D框架。

 

3D开发入门

官方文档对3D开发的一些基础知识已经描述的比较详细了,地址:三维图形概述 - WPF .NET Framework | Microsoft Docs

在学习WPF 3D应首先了解文档中介绍的一些基本概念。

通过以下,代码我们创建了一个基本的立方体

WPF开发快速入门【8】WPF进行简单的3D开发WPF开发快速入门【8】WPF进行简单的3D开发

    <Grid>         <Border  Grid.Column="0" BorderThickness="1" BorderBrush="Gray">             <Viewport3D >                 <Viewport3D.Camera>                     <PerspectiveCamera Position="6 5 4" LookDirection="-6 -5 -4"/>                 </Viewport3D.Camera>                 <ModelVisual3D>                     <ModelVisual3D.Content>                         <DirectionalLight  Direction="-1,-1,-1"/>                     </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>         </Border>     </Grid>

View Code

 可以先拷贝并修改以上代码查看效果。

 

HelixToolkit框架

采用原生的框架进行开发是比较困难或麻烦的,所以考虑采用第三方框架进行开发。

HelixToolkit提供一些3D模型组件,可以方便用户使用

开源项目地址:GitHub - helix-toolkit/helix-toolkit: Helix Toolkit is a collection of 3D components for .NET

先看一段设计代码:

        <HelixToolkit:HelixViewport3D ShowFrameRate="True" 
                       ZoomExtentsWhenLoaded="True"
                        ZoomAroundMouseDownPoint="True"
                        RotateAroundMouseDownPoint="True"
                        IsTopBottomViewOrientedToFrontBack="True"
                        IsViewCubeEdgeClicksEnabled="True"> <HelixToolkit:SunLight /> <ModelVisual3D x:Name="model"></ModelVisual3D> <!-- You can also add elements here in the xaml --> <HelixToolkit:GridLinesVisual3D Width="180" Length="180" MajorDistance="10" MinorDistance="10" Thickness="0.1" /> </HelixToolkit:HelixViewport3D>

 控件要求所有内容应包含在HelixToolkit:HelixViewport3D标签内,包括:光照、地平线和其他模型。

模型一般采用ModelVisual3D 标签,定义模型的方式有两种:标签或代码:

用标签定义:

            <ModelVisual3D>                 <ModelVisual3D.Content>                     <GeometryModel3D>                         <GeometryModel3D.Geometry>                             <MeshGeometry3D x:Name="meshMain"                                  Positions="50 50 50  71 60 60  60 71 60  71 71 60  60 60 71  71 60 71  60 71 71  71 71 71"                                  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 x:Name="matDiffuseMain">                                 <DiffuseMaterial.Brush>                                     <SolidColorBrush Color="LightPink"/>                                 </DiffuseMaterial.Brush>                             </DiffuseMaterial>                         </GeometryModel3D.Material>                     </GeometryModel3D>                 </ModelVisual3D.Content>             </ModelVisual3D>

 用代码定义:

设计端:   <ModelVisual3D x:Name="model"/>  代码端:     public partial class MainWindow : Window     {         public MainWindow()         {             InitializeComponent();             this.Loaded += MainWindow_Loaded;         }          private void MainWindow_Loaded(object sender, RoutedEventArgs e)         {             // Create a model group                        Model3DGroup modelGroup = new Model3DGroup();              MeshBuilder meshBoxBuilder = new MeshBuilder(false, false);             meshBoxBuilder.AddBox(new Point3D(0, 0, 0), 40, 40, 40);             MeshGeometry3D meshBox = meshBoxBuilder.ToMesh(true);             var whiteMaterial = MaterialHelper.CreateMaterial(Colors.Green);             var insideMaterial = MaterialHelper.CreateMaterial(Colors.Gray);             modelGroup.Children.Add(new GeometryModel3D { Geometry = meshBox, Material = whiteMaterial, BackMaterial = insideMaterial });              this.model.Content = modelGroup;         }     }

 框架也支持MVVM模式

设计端: <Window x:Class="Learn3D.Helix.MainWindow">     <Window.DataContext>         <local:MainViewModel />     </Window.DataContext>     <Grid>         <HelixToolkit:HelixViewport3D >                        <!--  The content of this visual is defined in MainViewModel.cs  -->             <ModelVisual3D Content="{Binding Model}" />          </HelixToolkit:HelixViewport3D>     </Grid> </Window>  代码端:  public class MainViewModel     {         public Model3D Model { get; set; }         public MainViewModel()         {             // Create a model group                 Model3DGroup modelGroup = new Model3DGroup();              // Create a mesh builder and add a box to it                 MeshBuilder meshBuilder = new MeshBuilder(false, false);             meshBuilder.AddBox(new Point3D(0, 0, 0), 20, 10, 5);              // Create a mesh from the builder (and freeze it)                 MeshGeometry3D mesh = meshBuilder.ToMesh(true);              // Create some materials                        var blueMaterial = MaterialHelper.CreateMaterial(Colors.Red);             var insideMaterial = MaterialHelper.CreateMaterial(Colors.Yellow);              // Add model to the group (using the same mesh, that's why we had to freeze it)                     modelGroup.Children.Add(new GeometryModel3D { Geometry = mesh, Transform = new TranslateTransform3D(60, 0, 60), Material = blueMaterial, BackMaterial = insideMaterial });              // Set the property, which will be bound to the Content property of the ModelVisual3D (see MainWindow.xaml)                 this.Model = modelGroup;         }     }

 基本上我们一般不会采用这种方式,和Stylet框架结合更加方便。

 

HelixToolkit和Stylet框架结合

和Stylet框架相关的知识这里就不重复介绍了,不了解的可以去看我博客内的相关文章。

这里主要演示使用Stylet框架实现模型的变化。

基本原理如下:

首先建立一个模型,并绑定到ViewModel内的一个对象

前端: <ModelVisual3D Content="{Binding ModelDynamic}" />  后端: public Model3D ModelDynamic { get; set; }

 当用户通过界面上的控件修改模型的属性时,将触发事件,

        public byte Color_R { get; set; } = 0;         public byte Color_G { get; set; } = 0;         public byte Color_B { get; set; } = 0;          private void InitColorBind()         {             this.Bind(s => Color_R, (o, e) => ColorChanged());             this.Bind(s => Color_G, (o, e) => ColorChanged());             this.Bind(s => Color_B, (o, e) => ColorChanged());         }          public void ColorChanged()         {             LoadDynamicModel();         }

 在事件内重新构造模型:

          public Model3D ModelDynamic { get; set; }         public void LoadDynamicModel()         {             // Create some materials                            var redMaterial = MaterialHelper.CreateMaterial(Color.FromRgb(Color_R, Color_G, Color_B));             var insideMaterial = MaterialHelper.CreateMaterial(Colors.Gray);              // Create a model group                 Model3DGroup modelDynamic = new Model3DGroup();              //模型                 MeshBuilder meshBoxBuilder = new MeshBuilder(false, false);             meshBoxBuilder.AddEllipsoid(new Point3D(20, 20, 10), 5, 5, 5);             MeshGeometry3D meshBox = meshBoxBuilder.ToMesh(true);             modelDynamic.Children.Add(new GeometryModel3D { Geometry = meshBox, Material = redMaterial, BackMaterial = insideMaterial });              this.ModelDynamic = modelDynamic;         }

  

加载模型

全部通过代码来实现模型是非常困难的,特别是一些较复杂的模型,可以通过3D软件进行设计,并把设计好的模型导入进来,这样就比较愉快了。

          public Model3DGroup ModelBase { get; set; }         private void LoadBaseModel()         {             model_1 = LoadModel(@"D:3DModel1.stl");                ModelBase = new Model3DGroup();             ModelBase.Children.Add(model_1);                    }

 LoadModel方法如下:

WPF开发快速入门【8】WPF进行简单的3D开发WPF开发快速入门【8】WPF进行简单的3D开发

        private Model3DGroup LoadModel(string path)         {             if (path == null)             {                 return null;             }              string ext = System.IO.Path.GetExtension(path).ToLower();              Model3DGroup model;             switch (ext)             {                 case ".3ds":                     {                         var r = new HelixToolkit.Wpf.StudioReader();                         model = r.Read(path);                         break;                     }                  case ".lwo":                     {                         var r = new HelixToolkit.Wpf.LwoReader();                         model = r.Read(path);                          break;                     }                  case ".obj":                     {                         var r = new HelixToolkit.Wpf.ObjReader();                         model = r.Read(path);                         break;                     }                  case ".objz":                     {                         var r = new HelixToolkit.Wpf.ObjReader();                         model = r.ReadZ(path);                         break;                     }                  case ".stl":                     {                         var r = new HelixToolkit.Wpf.StLReader();                         model = r.Read(path);                         break;                     }                  case ".off":                     {                         var r = new HelixToolkit.Wpf.OffReader();                         model = r.Read(path);                         break;                     }                  default:                     throw new InvalidOperationException("File format not supported.");             }              return model;         }

View Code

方法支持的格式比较多,推荐stl格式。

在实际件使用时,组件内是可以加入多个模型的,可以把不会变化的模型采用导入的方式来实现,有些变化的模型(尺寸、位置、颜色等)通过代码来实现。

最后需要说明的是,采用WPF进行3D开发,其功能是很有限的,很难实现较复杂的效果和交互功能,想要更好的效果可能采用Unity更加合适了。

 

资源

系列目录:WPF开发快速入门【0】前言与目录 

代码下载:Learn WPF: WPF学习笔记 (gitee.com)