Recap
- WPF 3D Preliminary
- Control camera perspective: keyboard ; mouse
- Textures: Make a 3D gallery for your two-dimensional wives ; rub a globe with C#
- light effect ; color
This article is the last blog in the WPF 3D series.
Source address: [C#] WPF 3D select and move geometry
Article directory
Manipulate Geometry
It is said that Minecraft was developed by three programmers in a week, and that one programmer developed a beggar's version of Minecraft in half a day. There is absolutely no problem in reasoning.
And as we all know, Minecraft is a collection of countless pixel blocks, and pixel blocks are cubes. As for creating a new cube, everyone is very proficient in this. Not only can you create a new cube, but you can even create as many cubes as you want.
New cube
But it is not currently possible to create by hand, so next add a shortcut Ctrl
+ N
to quickly create a cube. Ctrl
When + is pressed N
the effect is
This is definitely trivial for those who can already generate a row of cubes, first bind the shortcut in the constructor
public MainWindow()
{
InitializeComponent();
KeyDown += MainWindow_KeyDown;
}
MainWindow_KeyDown
defined as
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);
}
}
Among them MakeCubeMesh
are the custom functions, which have been written as early as the first blog in this series, as well as other functions such as light effects. The only difference is that this time it doesn't generate multiple cubes in the first place, so no DefineModel
function is needed.
Set the cube position
Although a new cube has been created just now, the position of the cube cannot be determined. Next, a dialog box must be created to set the position of the newly created cube.
Right-click the project, create a new window, name ParaDialog
it, it xaml
is
<Window x:Class="MyWord.ParaDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="输入参数" Height="180" Width="300">
<DockPanel LastChildFill="True">
<StackPanel DockPanel.Dock="Bottom"
Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="设置" 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>
Its cs
core code is
public partial class ParaDialog : Window
{
static readonly string[] labels = new string[4] {
"x坐标", "y坐标", "z坐标", "边长" };
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;
}
}
Finally, change the response code for Ctrl
+N
//...前面不用改
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]);
//...后面不用改
}
selected cube
If you want to operate the geometry, the premise is to select it, then bind a mouse action to complete the selected operation, change the xaml
code first, and Viewport3D
put border
it in a
<Border Name="mainBorder" Background="White" MouseDown="mainBorder_MouseDown">
<Viewport3D x:Name="v3dMain">
</Viewport3D>
</Border>
Then create a new mainBorder_MouseDown
function
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));
//获取鼠标在对象中的位置
Point mousePos = e.GetPosition(v3dMain);
// 执行点击操作
HitTestResult result = VisualTreeHelper.HitTest(v3dMain, mousePos);
//此即鼠标点击到曲面上的结果
var meshResult = result as RayMeshGeometry3DHitTestResult;
GeometryModel3D model = null;
if ((meshResult != null) && (meshResult.ModelHit is GeometryModel3D))
model = meshResult.ModelHit as GeometryModel3D;
//如果刚才选了别的模型,则使之恢复绿色
if (SelectedModel != null)
SelectedModel.Material = material;
//选择新的模型
SelectedModel = model;
if (model != null)
model.Material = new DiffuseMaterial(Brushes.Fuchsia);
}
Its effect is
move geometry
Since it can be selected, it is absolutely trivial to move something.
Looking back at the previous mouse-operated cameras, the basic process is that after the mouse is clicked, another function is bound, and when the mouse is released, it is unbound.
In WPF 3D
, Tranform
members are provided that can be used to move the geometry, so when creating a new geometry, be sure to add a line
//MainWindow_KeyDown函数
model.Transform = new TranslateTransform3D(0, 0, 0);
Then add a global variable to hold the old location
private Point3D oldPoint;
Then modify mainBorder_MouseDown
, in fact, just add at the end
mainBorder.CaptureMouse();
mainBorder.MouseMove += MainBorder_MouseMove;
mainBorder.MouseUp += MainBorder_MouseUp;
Next is the action when the mouse is moved and bounced. The bounce is very simple, it is nothing more than unbinding the mouse action; and when the mouse is moved, the change parameters of the geometry need to be changed.
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;
}
The effect is
Well, the super beggar version of Minecraft is ready →_→Is it listed in the United States or in Hong Kong?