C#?WPF實(shí)現(xiàn)3D操作幾何體效果
操作幾何體
據(jù)說(shuō)我的世界是三個(gè)程序員用一周開(kāi)發(fā)出來(lái)的,那一個(gè)程序員用半天開(kāi)發(fā)出一個(gè)乞丐版的我的世界,講道理是完全沒(méi)有問(wèn)題的。
而眾所周知,我的世界就是無(wú)數(shù)個(gè)像素塊的集合,而像素塊也就是立方體。關(guān)于新建立方體,這個(gè)大家已經(jīng)非常熟練了,不僅能新建一個(gè)立方體,甚至能新建要多少有多少的立方體。
新建正方體
但目前并不能用手新建,所以接下來(lái)添加一個(gè)快捷方式Ctrl+N來(lái)快速創(chuàng)建立方體。當(dāng)按下Ctrl+N時(shí)效果為
這對(duì)于已經(jīng)能生成一排立方體的人來(lái)說(shuō)絕對(duì)是小意思了,首先在構(gòu)造函數(shù)中綁定快捷方式
public MainWindow() { InitializeComponent(); KeyDown += MainWindow_KeyDown; }
MainWindow_KeyDown定義為
private void MainWindow_KeyDown(object sender, KeyEventArgs e) { if ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.N)) { MeshGeometry3D mesh = MakeCubeMesh(0, 0, 0, 1); Color color = Color.FromArgb(255, 0, 255, 0); DiffuseMaterial material = new DiffuseMaterial(new SolidColorBrush(color)); GeometryModel3D model = new GeometryModel3D(mesh, material); group3d.Children.Add(model); } }
其中MakeCubeMesh為自定義的函數(shù),早在本系列第一篇博客就已經(jīng)寫(xiě)過(guò)了,其他諸如光效等亦然。唯一的區(qū)別是這次并不一開(kāi)始就生成多個(gè)立方體,所以無(wú)需DefineModel函數(shù)。
設(shè)置立方體位置
剛剛雖然新建了一個(gè)立方體,但并不能確定立方體的位置,接下來(lái)就要新建一個(gè)對(duì)話框,用以設(shè)置新建立方體的位置。
右鍵項(xiàng)目,新建窗口,名為ParaDialog,其xaml為
<Window x:Class="MyWord.ParaDialog" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="輸入?yún)?shù)" Height="180" Width="300"> <DockPanel LastChildFill="True"> <StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right"> <Button Content="設(shè)置" Click="okButton_Click" Margin="5" Width="60" Height="25"/> <Button Content="取消" IsCancel="True" Margin="5" Width="60" Height="25"/> </StackPanel> <UniformGrid Columns="1" Margin="5" x:Name="ufgLabel"/> <UniformGrid Columns="1" Margin="5" x:Name="ufgTextBox"/> ??????? </DockPanel> </Window>
其cs的核心代碼為
public partial class ParaDialog : Window { static readonly string[] labels = new string[4] { "x坐標(biāo)", "y坐標(biāo)", "z坐標(biāo)", "邊長(zhǎng)" }; List<TextBox> paraBoxes = new List<TextBox>(); public double[] para; public ParaDialog(double[] para) { this.para = para; InitializeComponent(); string tmp; for (int i = 0; i < 4; i++) { //向UniformGrid中歐給填充文字塊 ufgLabel.Children.Add(new TextBlock() { Text = labels[i] }); paraBoxes.Add(new TextBox()); ufgTextBox.Children.Add(paraBoxes[i]); } } private void okButton_Click(object sender, RoutedEventArgs e) { for (int i = 0; i < 4; i++) para[i] = double.Parse(paraBoxes[i].Text); DialogResult = true; } }
最后,更改Ctrl+N的響應(yīng)代碼
//...前面不用改 if ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.N)) { double[] para = new double[4]; ParaDialog pDialog = new ParaDialog(para); pDialog.ShowDialog(); if (pDialog.DialogResult != true) return; MeshGeometry3D mesh = MakeCubeMesh(para[0],para[1],para[2],para[3]); //...后面不用改 }
選中立方體
若想操作幾何體,前提是選中它,接下來(lái)就綁定一個(gè)鼠標(biāo)動(dòng)作,來(lái)完成選中的操作,先更改xaml代碼,將Viewport3D放到一個(gè)border中
<Border Name="mainBorder" Background="White" MouseDown="mainBorder_MouseDown"> <Viewport3D x:Name="v3dMain"> </Viewport3D> </Border>
然后新建mainBorder_MouseDown函數(shù)
private void mainBorder_MouseDown(object sender, MouseButtonEventArgs e) { if (e.LeftButton == MouseButtonState.Released) return; Color color = Color.FromArgb(255, 0, 255, 0); var material = new DiffuseMaterial(new SolidColorBrush(color)); //獲取鼠標(biāo)在對(duì)象中的位置 Point mousePos = e.GetPosition(v3dMain); // 執(zhí)行點(diǎn)擊操作 HitTestResult result = VisualTreeHelper.HitTest(v3dMain, mousePos); //此即鼠標(biāo)點(diǎn)擊到曲面上的結(jié)果 var meshResult = result as RayMeshGeometry3DHitTestResult; GeometryModel3D model = null; if ((meshResult != null) && (meshResult.ModelHit is GeometryModel3D)) model = meshResult.ModelHit as GeometryModel3D; //如果剛才選了別的模型,則使之恢復(fù)綠色 if (SelectedModel != null) SelectedModel.Material = material; //選擇新的模型 SelectedModel = model; if (model != null) model.Material = new DiffuseMaterial(Brushes.Fuchsia); }
其效果為
挪動(dòng)幾何體
既然已經(jīng)可以選中了,那么挪動(dòng)什么的絕對(duì)就是小意思了。
回顧此前的鼠標(biāo)操作攝像機(jī),其基本流程是,鼠標(biāo)點(diǎn)擊之后,綁定另一個(gè)函數(shù),當(dāng)松開(kāi)鼠標(biāo)時(shí)解綁。
在WPF 3D中,提供了Tranform成員,可用于移動(dòng)幾何體,所以在新建幾何體時(shí),務(wù)必注意添加一行
//MainWindow_KeyDown函數(shù) model.Transform = new TranslateTransform3D(0, 0, 0);
然后添加全局變量用以保存舊的位置
private Point3D oldPoint;
然后修改mainBorder_MouseDown,其實(shí)只需在末尾添加
mainBorder.CaptureMouse(); mainBorder.MouseMove += MainBorder_MouseMove; mainBorder.MouseUp += MainBorder_MouseUp;
接下來(lái)是鼠標(biāo)挪動(dòng)和彈起時(shí)的動(dòng)作,其中彈起時(shí)非常簡(jiǎn)單,無(wú)非是解綁鼠標(biāo)動(dòng)作;而鼠標(biāo)挪動(dòng)時(shí),則需更改幾何體的變化參數(shù)。
private void MainBorder_MouseUp(object sender, MouseButtonEventArgs e) { mainBorder.ReleaseMouseCapture(); mainBorder.MouseMove -= MainBorder_MouseMove; mainBorder.MouseUp -= MainBorder_MouseUp; } private void MainBorder_MouseMove(object sender, MouseEventArgs e) { Point newPoint = e.GetPosition(mainBorder); var res = VisualTreeHelper.HitTest(v3dMain, newPoint); if (res == null) return; var newResult = res as RayMeshGeometry3DHitTestResult; var deltaPt = newResult.PointHit - oldPoint; var trans = SelectedModel.Transform as TranslateTransform3D; trans.OffsetX += deltaPt.X; trans.OffsetY += deltaPt.Y; trans.OffsetZ += deltaPt.Z; oldPoint = newResult.PointHit; }
效果為
以上就是C# WPF實(shí)現(xiàn)3D操作幾何體效果的詳細(xì)內(nèi)容,更多關(guān)于C# WPF 3D操作幾何體的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#用RabbitMQ實(shí)現(xiàn)消息訂閱與發(fā)布
在消息隊(duì)列模型中,如何將消息廣播到所有的消費(fèi)者,這種模式成為“發(fā)布/訂閱”。本文主要以一個(gè)簡(jiǎn)單的小例子,簡(jiǎn)述通過(guò)fanout交換機(jī),實(shí)現(xiàn)消息的發(fā)布與訂閱,僅供學(xué)習(xí)分享使用,如有不足之處,還請(qǐng)指正。2021-05-05C#獲取串口列表實(shí)現(xiàn)實(shí)時(shí)監(jiān)控串口
本文主要介紹兩種獲取串口列表的方法,比較簡(jiǎn)單,方便大家使用,另外分享了一個(gè)已封裝的API,需要的朋友可以參考下。2016-05-05C#值類型、引用類型中的Equals和==的區(qū)別淺析
這篇文章主要介紹了C#值類型、引用類型中的Equals和==的區(qū)別淺析,本文分別對(duì)C#值類型和引用類型中的Equals和==做了講解和給出了實(shí)例,需要的朋友可以參考下2015-01-01C# Newtonsoft.Json 解析多嵌套json 進(jìn)行反序列化的實(shí)例
這篇文章主要介紹了C# Newtonsoft.Json 解析多嵌套json 進(jìn)行反序列化的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-01-01Unity中的RegisterPlugins實(shí)用案例深入解析
這篇文章主要為大家介紹了Unity中的RegisterPlugins實(shí)用案例深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05listview控件實(shí)現(xiàn)點(diǎn)擊列表頭進(jìn)行l(wèi)istview排序示例分享
這篇文章主要介紹了listview控件實(shí)現(xiàn)點(diǎn)擊列表頭進(jìn)行l(wèi)istview排序示例分享,需要的朋友可以參考下2014-03-03