WPF實現繪制3D圖形的示例代碼
WPF的3D功能可以在不編寫任何c#代碼的情況下進行繪制,隻需要使用xaml即可完成3D圖形的渲染。本文主要講述瞭WPF-3D中的關鍵概念, 以及常用到的命中測試、2d控件如何在3D對象中進行渲染,除此之外,還演示瞭如何導入外部3D模型。
關鍵概念
視口
視口指的是圖像要展示在哪裡,可以理解為展示圖形的舞臺。在WPF中視口使用Viewport3D
標簽表示。
相機
如果把視口比作舞臺,那相機就可以理解為觀眾的眼睛,不同的眼睛位置會看到不同的角度。
<Viewport3D> <!--相機--> <Viewport3D.Camera> <!--透視相機--> <PerspectiveCamera Position="8,5,10" LookDirection="-7,-2,-10" FarPlaneDistance="40" NearPlaneDistance="10" FieldOfView="60"> <PerspectiveCamera.Transform> <RotateTransform3D CenterX="1.5" CenterY="1" CenterZ="0.5"> <RotateTransform3D.Rotation> <AxisAngleRotation3D Angle="45" Axis="0,1,0"/> </RotateTransform3D.Rotation> </RotateTransform3D> </PerspectiveCamera.Transform> </PerspectiveCamera> <!--正交相機,用法類似--> <!--<OrthographicCamera/>--> </Viewport3D.Camera>
光源
沒有光源也就看不到3D對象
<!--光線--> <ModelVisual3D> <ModelVisual3D.Content> <Model3DGroup> <!--散射光線--> <AmbientLight Color="#FFF"/> <!--平行光--> <!--<DirectionalLight Color="#FFF" Direction="0,-1,0"/>--> <!--點光源--> <!--<PointLight Position="0,0,0"/>--> <!--錐形輻射光:手電筒--> <!--<SpotLight Position="0,0,0" Direction="0,0,-3"/>--> </Model3DGroup> </ModelVisual3D.Content> </ModelVisual3D>
材質
3D幾何對象隻是將輪廓定義出來,表面是沒有定義的,所以需要使用材質來展現出不同的物體表面。也可以理解為3D幾何對象隻是勾勒出物體的輪廓,而材質則是上顏色。
<ModelUIElement3D > <ModelUIElement3D.Model> <GeometryModel3D> <!--材質--> <GeometryModel3D.Material> <!--散射材質--> <DiffuseMaterial Brush="Blue"/> <!--鏡面材質--> <!--<SpecularMaterial SpecularPower="1" Brush="Blue"/>--> <!--自發光材質--> <!--<EmissiveMaterial Color="Green" />--> </GeometryModel3D.Material> <GeometryModel3D.Geometry> <MeshGeometry3D Positions="0,0,1 0,2,1 3,2,1 3,0,1 0,0,0 0,2,0 3,2,0 3,0,0" TriangleIndices="2,3,7 7,6,2 1,5,4 0,1,4"/> </GeometryModel3D.Geometry> </GeometryModel3D> </ModelUIElement3D.Model> </ModelUIElement3D>
3D對象
3D對象則是具體的對象,在WPF中視口使用<ModelUIElement3D>
標簽表示。在WPF中,圖形是以三角面片作為最基本的展示單元,因為三角形是最穩定的即三個點可以確定出唯一的一個平面,任何復雜的圖形都是由多個三角面片組成的。在給TriangleIndices
屬性賦值時,一定註意三個點的順序。
命中測試(鼠標交互)
想要使用鼠標點擊得到某個圖形,可以在具體的某個3D對象中,增加MouseLeftButtonDown
事件
<ModelUIElement3D MouseLeftButtonDown="ModelUIElement3D_MouseLeftButtonDown">
事件中可以進行改變顏色等操作
private void ModelUIElement3D_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { ModelUIElement3D mui3d = sender as ModelUIElement3D; var model = mui3d.Model as GeometryModel3D; (model.Material as DiffuseMaterial).Brush = Brushes.Orange; }
如果有很多3D對象,在每個具體的對象上面增加事件會很麻煩,也可以直接在Viewport3D
中增加事件
<Viewport3D MouseLeftButtonDown="Viewport3D_MouseLeftButtonDown">
在時間中急性轉換處理
private void Viewport3D_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Viewport3D viewport3D=sender as Viewport3D; Point location=e.GetPosition(viewport3D); HitTestResult hitTestResult=VisualTreeHelper.HitTest(viewport3D, location); if (hitTestResult != null) { ...//具體操作 } }
3D對象中2D控件渲染
如果要在3D對象中增加控件,可以使用Viewport2DVisual3D
標簽,實現如下圖所示的效果。
<Viewport3D> <Viewport2DVisual3D> <Viewport2DVisual3D.Geometry> <MeshGeometry3D Positions="0,0,1 0,2,1 3,2,1 3,0,1 0,0,0 0,2,0 3,2,0 3,0,0" TriangleIndices="0,2,1 0,3,2 6,4,5 6,7,4" TextureCoordinates="0,1 0,0 1,0 1,1"/> <!--TextureCoordinates:表示的二維平面坐標,原點:左上角--> </Viewport2DVisual3D.Geometry> <Viewport2DVisual3D.Material> <DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" Brush="White"/> </Viewport2DVisual3D.Material> <Viewport2DVisual3D.Visual> <Border BorderThickness="1" BorderBrush="Yellow"> <StackPanel> <TextBlock Text="Hello World" Foreground="Green" /> <Button Content="Button" Click="Button_Click"/> </StackPanel> </Border> </Viewport2DVisual3D.Visual> </Viewport2DVisual3D> <Viewport3D>
外部導入3D模型
在wpf中繪制3D模型還是非常麻煩的,在實際工作中用的比較多的是從外部導入已有的3d模型。推薦一個比較好的第三方庫HelixToolKit
<Window x:Class="WpfApp2.MainWindow" 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:helix="http://helix-toolkit.org/wpf" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <helix:HelixViewport3D Name="viewPort3d" ShowViewCube="True" ViewCubeBackText="後" ViewCubeFrontText="前" ViewCubeHeight="100" ViewCubeWidth="100" ViewCubeVerticalPosition="Bottom" ViewCubeHorizontalPosition="Right" ShowCoordinateSystem="True" CoordinateSystemLabelForeground="Red" CoordinateSystemHorizontalPosition="Left" CoordinateSystemVerticalPosition="Bottom" ShowFrameRate="True" IsViewCubeEdgeClicksEnabled="False"> <helix:HelixViewport3D.Camera> <PerspectiveCamera FieldOfView="45" LookDirection="0,0,-414.387754871885" FarPlaneDistance="30000" NearPlaneDistance="0.1" Position="9.9475983006414E-14,91.037123633789,414.387754871885" UpDirection="0,1,0"/> </helix:HelixViewport3D.Camera> <helix:HelixViewport3D.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#444" Offset="0"/> <GradientStop Color="#EEE" Offset="1"/> </LinearGradientBrush> </helix:HelixViewport3D.Background> <helix:GridLinesVisual3D Width="16000" Length="16000" Thickness="2" MinorDistance="500" MajorDistance="500" Fill="Gray" /> <!--很重要,沒有燈光場景是黑的--> <helix:DefaultLights/> <ModelVisual3D x:Name="model"></ModelVisual3D> </helix:HelixViewport3D> </Grid> </Window>
namespace WpfApp2 { public partial class MainWindow : Window { List<string> modelPaths = new List<string>(); string basePath = AppDomain.CurrentDomain.BaseDirectory + "\\ModelFiles\\"; public MainWindow() { InitializeComponent(); modelPaths.Add("IRB4600_20kg-250_LINK1_CAD_rev04.stl"); modelPaths.Add("IRB4600_20kg-250_LINK2_CAD_rev04.stl"); modelPaths.Add("IRB4600_20kg-250_LINK3_CAD_rev005.stl"); modelPaths.Add("IRB4600_20kg-250_LINK4_CAD_rev04.stl"); modelPaths.Add("IRB4600_20kg-250_LINK5_CAD_rev04.stl"); modelPaths.Add("IRB4600_20kg-250_LINK6_CAD_rev04.stl"); modelPaths.Add("IRB4600_20kg-250_LINK3_CAD_rev04.stl"); modelPaths.Add("IRB4600_20kg-250_CABLES_LINK1_rev03.stl"); modelPaths.Add("IRB4600_20kg-250_CABLES_LINK2_rev03.stl"); modelPaths.Add("IRB4600_20kg-250_CABLES_LINK3_rev03.stl"); modelPaths.Add("IRB4600_20kg-250_BASE_CAD_rev04.stl"); this.Loaded += MainWindow_Loaded; viewPort3d.RotateGesture = new MouseGesture(MouseAction.RightClick); viewPort3d.PanGesture = new MouseGesture(MouseAction.LeftClick); } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { viewPort3d.Camera.LookDirection = new Vector3D(2038, -5200, -2930); viewPort3d.Camera.UpDirection = new Vector3D(-0.145, 0.372, 0.917); viewPort3d.Camera.Position = new Point3D(-1571, 4801, 3774); this.model.Content = InitializeModels(this.modelPaths); } private Model3DGroup InitializeModels(List<string> modelsNames) { Model3DGroup group = new Model3DGroup(); try { ModelImporter import = new ModelImporter(); foreach (string modelName in modelsNames) { var materialGroup = new MaterialGroup(); Color mainColor = Colors.White; //EmissiveMaterial emissMat = new EmissiveMaterial(new SolidColorBrush(mainColor)); DiffuseMaterial diffMat = new DiffuseMaterial(new SolidColorBrush(mainColor)); //SpecularMaterial specMat = new SpecularMaterial(new SolidColorBrush(mainColor), 2000); //materialGroup.Children.Add(emissMat); materialGroup.Children.Add(diffMat); //materialGroup.Children.Add(specMat); var link = import.Load(basePath + modelName); GeometryModel3D model = link.Children[0] as GeometryModel3D; model.Material = materialGroup; model.BackMaterial = materialGroup; group.Children.Add(link); } } catch (Exception e) { MessageBox.Show("未知異常:" + e.StackTrace); } return group; } } }
HelixToolKit使用文檔
以上就是WPF實現繪制3D圖形的示例代碼的詳細內容,更多關於WPF 3D圖形的資料請關註WalkonNet其它相關文章!