使用WPF做一个3D正方体
1. 准备工作
安装Visual Studio
- 下载Visual Studio安装包
- 打开安装包,选择"使用C++的桌面开发"进行安装
- 安装完成后打开Visual Studio,选择"新建项目",选择WPF应用程序
- 在项目中添加3D空间,具体操作可以参考Microsoft官方文档
创建WPF项目
- 在Visual Studio中创建一个WPF应用程序项目。
- 在MainWindow.xaml中添加Viewport3D控件。
- 在MainWindow.xaml.cs中添加代码以创建一个3D正方体,并将其添加到Viewport3D中。
// 创建一个3D正方体
MeshGeometry3D mesh = new MeshGeometry3D();
mesh.Positions = new Point3DCollection()
{
new Point3D(-1, 1, 1),
new Point3D(1, 1, 1),
new Point3D(-1, -1, 1),
new Point3D(1, -1, 1),
new Point3D(-1, 1, -1),
new Point3D(1, 1, -1),
new Point3D(-1, -1, -1),
new Point3D(1, -1, -1),
};
mesh.TriangleIndices = new Int32Collection()
{
0, 1, 2,
1, 3, 2,
1, 5, 3,
5, 7, 3,
5, 4, 7,
4, 6, 7,
4, 0, 6,
0, 2, 6,
2, 3, 6,
3, 7, 6,
4, 5, 0,
5, 1, 0,
};
// 创建一个材质
DiffuseMaterial material = new DiffuseMaterial(new SolidColorBrush(Colors.Blue));
// 创建一个模型
GeometryModel3D model = new GeometryModel3D(mesh, material);
// 创建一个模型组
Model3DGroup group = new Model3DGroup();
group.Children.Add(model);
// 将模型组添加到Viewport3D中
viewport3D.Children.Add(new ModelVisual3D() {
Content = group });
引入Helix Toolkit NuGet包- 在Visual Studio中打开项目解决方案。
- 右键点击项目名称,选择“管理NuGet程序包”。
- 在搜索框中输入“Helix Toolkit”。
- 选择最新版本的“Helix Toolkit WPF”并安装。
- 在MainWindow.xaml文件中添加以下代码:
<Window x:Class="Wpf3DCube.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:h="http://helix-toolkit.org/wpf"
Title="MainWindow" Height="450" Width="800">
<Grid>
<h:HelixViewport3D>
<!-- 3D模型将在此处添加 -->
</h:HelixViewport3D>
</Grid>
</Window>
2. 实现3D正方体
- 创建3D场景
创建Viewport3D对象
- 使用XAML创建Viewport3D对象
<Viewport3D>
<!-- 3D场景内容 -->
</Viewport3D>
-
使用C#代码创建Viewport3D对象
Viewport3D viewport = new Viewport3D(); // 添加3D场景内容 // ...
-
在窗口中添加Viewport3D对象
<Grid> <Viewport3D> <!-- 3D场景内容 --> </Viewport3D> </Grid>
设置相机位置
2. 创建正方体模型
- 设置相机位置:
PerspectiveCamera camera = new PerspectiveCamera();
camera.Position = new Point3D(0, 0, 5);
camera.LookDirection = new Vector3D(0, 0, -1);
camera.FieldOfView = 60;
viewport.Camera = camera;
-
创建正方体模型:
MeshGeometry3D mesh = new MeshGeometry3D(); mesh.Positions.Add(new Point3D(-1, -1, 1)); mesh.Positions.Add(new Point3D(1, -1, 1)); mesh.Positions.Add(new Point3D(1, 1, 1)); mesh.Positions.Add(new Point3D(-1, 1, 1)); mesh.Positions.Add(new Point3D(-1, -1, -1)); mesh.Positions.Add(new Point3D(1, -1, -1)); mesh.Positions.Add(new Point3D(1, 1, -1)); mesh.Positions.Add(new Point3D(-1, 1, -1)); mesh.TriangleIndices.Add(0); mesh.TriangleIndices.Add(1); mesh.TriangleIndices.Add(2); mesh.TriangleIndices.Add(2); mesh.TriangleIndices.Add(3); mesh.TriangleIndices.Add(0); mesh.TriangleIndices.Add(1); mesh.TriangleIndices.Add(5); mesh.TriangleIndices.Add(6); mesh.TriangleIndices.Add(6); mesh.TriangleIndices.Add(2); mesh.TriangleIndices.Add(1); mesh.TriangleIndices.Add(7); mesh.TriangleIndices.Add(6); mesh.TriangleIndices.Add(5); mesh.TriangleIndices.Add(5); mesh.TriangleIndices.Add(4); mesh.TriangleIndices.Add(7); mesh.TriangleIndices.Add(4); mesh.TriangleIndices.Add(0); mesh.TriangleIndices.Add(3); mesh.TriangleIndices.Add(3); mesh.TriangleIndices.Add(7); mesh.TriangleIndices.Add(4); mesh.TriangleIndices.Add(3); mesh.TriangleIndices.Add(2); mesh.TriangleIndices.Add(6); mesh.TriangleIndices.Add(6); mesh.TriangleIndices.Add(7); mesh.TriangleIndices.Add(3); mesh.TriangleIndices.Add(4); mesh.TriangleIndices.Add(5); mesh.TriangleIndices.Add(1); mesh.TriangleIndices.Add(1); mesh.TriangleIndices.Add(0); mesh.TriangleIndices.Add(4); GeometryModel3D model = new GeometryModel3D(); model.Geometry = mesh; model.Material = new DiffuseMaterial(new SolidColorBrush(Colors.Blue)); model.BackMaterial = new DiffuseMaterial(new SolidColorBrush(Colors.Green)); ModelVisual3D visual = new ModelVisual3D(); visual.Content = model; viewport.Children.Add(visual);
创建MeshBuilder对象
- 使用以下代码创建MeshBuilder对象:
MeshBuilder meshBuilder = new MeshBuilder();
添加顶点
- 在代码中定义顶点坐标数组,例如:
Point3D[] vertices = new Point3D[]
{
new Point3D(-1, 1, 1),
new Point3D(1, 1, 1),
new Point3D(1, -1, 1),
new Point3D(-1, -1, 1),
new Point3D(-1, 1, -1),
new Point3D(1, 1, -1),
new Point3D(1, -1, -1),
new Point3D(-1, -1, -1)
};
-
创建MeshGeometry3D对象,并将定义的顶点坐标数组赋值给它的Positions属性,例如:
MeshGeometry3D mesh = new MeshGeometry3D(); mesh.Positions = new Point3DCollection(vertices);
-
将MeshGeometry3D对象赋值给Geometry属性,例如:
Geometry = mesh;
添加三角形
- 在场景中添加一个MeshGeometry3D对象,用于存储三角形的顶点信息:
MeshGeometry3D mesh = new MeshGeometry3D();
-
添加三个顶点,构成一个三角形:
mesh.Positions.Add(new Point3D(0, 0, 0)); mesh.Positions.Add(new Point3D(1, 0, 0)); mesh.Positions.Add(new Point3D(0, 1, 0));
-
定义三角形的法线向量:
Vector3D normal = new Vector3D(0, 0, 1);
-
添加三角形的法线向量:
mesh.Normals.Add(normal); mesh.Normals.Add(normal); mesh.Normals.Add(normal);
-
添加三角形的索引:
mesh.TriangleIndices.Add(0); mesh.TriangleIndices.Add(1); mesh.TriangleIndices.Add(2);
-
创建一个GeometryModel3D对象,设置其Geometry属性为刚才创建的MeshGeometry3D对象:
GeometryModel3D model = new GeometryModel3D(); model.Geometry = mesh;
-
创建一个MaterialGroup对象,用于设置三角形的颜色:
MaterialGroup materials = new MaterialGroup(); materials.Children.Add(new DiffuseMaterial(new SolidColorBrush(Colors.Red)));
-
将MaterialGroup对象设置为GeometryModel3D对象的Material属性:
model.Material = materials;
-
将GeometryModel3D对象添加到场景中:
scene.Children.Add(model);
创建GeometryModel3D对象
- 使用MeshGeometry3D类创建立方体的顶点坐标和索引数据:
MeshGeometry3D mesh = new MeshGeometry3D();
mesh.Positions = new Point3DCollection()
{
new Point3D(-0.5, -0.5, -0.5),
new Point3D(0.5, -0.5, -0.5),
new Point3D(0.5, 0.5, -0.5),
new Point3D(-0.5, 0.5, -0.5),
new Point3D(-0.5, -0.5, 0.5),
new Point3D(0.5, -0.5, 0.5),
new Point3D(0.5, 0.5, 0.5),
new Point3D(-0.5, 0.5, 0.5)
};
mesh.TriangleIndices = new Int32Collection()
{
0, 1, 2, 2, 3, 0, // front face
1, 5, 6, 6, 2, 1, // right face
5, 4, 7, 7, 6, 5, // back face
4, 0, 3, 3, 7, 4, // left face
3, 2, 6, 6, 7, 3, // top face
0, 4, 5, 5, 1, 0 // bottom face
};
-
创建GeometryModel3D对象并设置其Geometry属性为上一步创建的MeshGeometry3D对象:
GeometryModel3D model = new GeometryModel3D(); model.Geometry = mesh;
-
创建Material对象并设置其DiffuseColor属性为立方体的颜色:
SolidColorBrush brush = new SolidColorBrush(Colors.Blue); Material material = new DiffuseMaterial(brush);
-
创建ModelVisual3D对象并设置其Content属性为上一步创建的GeometryModel3D对象:
ModelVisual3D visual = new ModelVisual3D(); visual.Content = model;
-
将ModelVisual3D对象添加到Viewport3D的Children集合中:
viewport.Children.Add(visual);
设置材质
- 在XAML中添加材质:
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Red"/>
</GeometryModel3D.Material>
- 在代码中设置材质:
DiffuseMaterial material = new DiffuseMaterial(Brushes.Red); GeometryModel3D cubeModel = new GeometryModel3D(cubeMesh, material);
设置模型
3. 添加灯光
- 设置模型:
// 创建正方体模型
MeshGeometry3D cubeMesh = new MeshGeometry3D();
cubeMesh.Positions = new Point3DCollection()
{
new Point3D(-0.5, -0.5, -0.5),
new Point3D(0.5, -0.5, -0.5),
new Point3D(0.5, 0.5, -0.5),
new Point3D(-0.5, 0.5, -0.5),
new Point3D(-0.5, -0.5, 0.5),
new Point3D(0.5, -0.5, 0.5),
new Point3D(0.5, 0.5, 0.5),
new Point3D(-0.5, 0.5, 0.5)
};
cubeMesh.TriangleIndices = new Int32Collection()
{
0, 1, 2, 2, 3, 0,
1, 5, 6, 6, 2, 1,
5, 4, 7, 7, 6, 5,
4, 0, 3, 3, 7, 4,
3, 2, 6, 6, 7, 3,
0, 4, 5, 5, 1, 0
};
// 创建材质
DiffuseMaterial material = new DiffuseMaterial(new SolidColorBrush(Colors.Blue));
// 创建模型
GeometryModel3D model = new GeometryModel3D(cubeMesh, material);
// 创建模型容器
Model3DGroup modelGroup = new Model3DGroup();
modelGroup.Children.Add(model);
// 将模型容器添加到场景中
viewport.Children.Add(new ModelVisual3D() {
Content = modelGroup });
-
添加灯光:
// 创建点光源 PointLight light = new PointLight(Colors.White, new Point3D(0, 0, 0)); // 将光源添加到场景中 viewport.Children.Add(new ModelVisual3D() { Content = light });
创建AmbientLight对象
- 创建AmbientLight对象的代码如下:
AmbientLight myAmbientLight = new AmbientLight();
myAmbientLight.Color = Colors.White;
这段代码创建了一个白色的环境光,用于照亮整个场景。
创建DirectionalLight对象
- 创建DirectionalLight对象的代码示例:
DirectionalLight myDirectionalLight = new DirectionalLight();
myDirectionalLight.Color = Colors.White;
myDirectionalLight.Direction = new Vector3D(-0.61, -0.5, -0.61);
myViewport3D.Children.Add(myDirectionalLight);
这段代码创建了一个DirectionalLight对象,并设置了它的颜色和方向,最后将它添加到了Viewport3D中。
设置光照效果
4. 显示3D场景
- 设置光照效果:
// 创建一个平行光源
DirectionalLight light = new DirectionalLight(Colors.White, new Vector3D(-1, -1, -1));
// 将光源添加到场景中
myViewport3D.Children.Add(light);
-
显示3D场景:
// 创建一个Viewport3DVisualizer对象 Viewport3DVisualizer visualizer = new Viewport3DVisualizer(); // 设置Viewport3DVisualizer的Viewport3D属性 visualizer.Viewport3D = myViewport3D; // 将Viewport3DVisualizer添加到VisualTree中 this.Content = visualizer;
将Viewport3D对象添加到Grid中- 将Viewport3D对象添加到Grid中的代码实例:
<Grid>
<Viewport3D>
<!-- 添加3D场景内容 -->
</Viewport3D>
</Grid>
3. 实现旋转动画
- 创建动画
创建DoubleAnimation对象
- 创建DoubleAnimation对象的实例代码:
DoubleAnimation rotateAnimation = new DoubleAnimation();
rotateAnimation.From = 0;
rotateAnimation.To = 360;
rotateAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
rotateAnimation.RepeatBehavior = RepeatBehavior.Forever;
这段代码创建了一个DoubleAnimation对象rotateAnimation,将其起始值设为0,终止值设为360,动画时长为5秒,并且重复播放。
设置From和To属性
- 设置From和To属性的代码示例:
// 创建旋转动画
RotateTransform3D rotateTransform = new RotateTransform3D();
AxisAngleRotation3D axisAngleRotation = new AxisAngleRotation3D(new Vector3D(0, 1, 0), 0);
rotateTransform.Rotation = axisAngleRotation;
DoubleAnimation doubleAnimation = new DoubleAnimation();
doubleAnimation.From = 0;
doubleAnimation.To = 360;
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
// 将动画应用到旋转变换
axisAngleRotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, doubleAnimation);
设置Duration属性
- 在XAML中设置Duration属性:
<Storyboard x:Key="RotateAnimation">
<DoubleAnimation Storyboard.TargetName="myTransform" Storyboard.TargetProperty="Angle" From="0" To="360" Duration="0:0:1" RepeatBehavior="Forever" />
</Storyboard>
-
在代码中设置Duration属性:
DoubleAnimation animation = new DoubleAnimation(); animation.From = 0; animation.To = 360; animation.Duration = new Duration(TimeSpan.FromSeconds(1)); animation.RepeatBehavior = RepeatBehavior.Forever; Storyboard.SetTargetName(animation, "myTransform"); Storyboard.SetTargetProperty(animation, new PropertyPath(RotateTransform.AngleProperty)); Storyboard storyboard = new Storyboard(); storyboard.Children.Add(animation); storyboard.Begin(this);
设置RepeatBehavior属性
- 在XAML中设置RepeatBehavior属性:
<Storyboard x:Key="RotateAnimation">
<DoubleAnimation Storyboard.TargetName="myTransform"
Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:3"
RepeatBehavior="Forever" />
</Storyboard>
-
在代码中设置RepeatBehavior属性:
DoubleAnimation animation = new DoubleAnimation(); animation.From = 0; animation.To = 360; animation.Duration = new Duration(TimeSpan.FromSeconds(3)); animation.RepeatBehavior = RepeatBehavior.Forever; Storyboard.SetTargetName(animation, "myTransform"); Storyboard.SetTargetProperty(animation, new PropertyPath(RotateTransform.AngleProperty)); Storyboard storyboard = new Storyboard(); storyboard.Children.Add(animation); storyboard.Begin(this);
创建Storyboard对象
- 创建Storyboard对象的实例代码:
Storyboard storyboard = new Storyboard();
- 添加旋转动画的实例代码:
DoubleAnimation animation = new DoubleAnimation(); animation.From = 0; animation.To = 360; animation.Duration = new Duration(TimeSpan.FromSeconds(5)); animation.RepeatBehavior = RepeatBehavior.Forever; Storyboard.SetTarget(animation, cube); Storyboard.SetTargetProperty(animation, new PropertyPath("(UIElement.RenderTransform).(Transform3DGroup.Children)[0].(RotateTransform3D.Rotation.Angle)")); storyboard.Children.Add(animation);
其中,cube是表示正方体的UIElement对象,可以根据实际情况进行替换。
将DoubleAnimation添加到Storyboard中
2. 应用动画
- 将DoubleAnimation添加到Storyboard中:
DoubleAnimation rotateAnimation = new DoubleAnimation();
rotateAnimation.From = 0;
rotateAnimation.To = 360;
rotateAnimation.Duration = TimeSpan.FromSeconds(1);
rotateAnimation.RepeatBehavior = RepeatBehavior.Forever;
Storyboard.SetTarget(rotateAnimation, myModel);
Storyboard.SetTargetProperty(rotateAnimation, new PropertyPath(Model3D.TransformProperty));
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(rotateAnimation);
storyboard.Begin();
- 应用动画:
在窗口的Loaded事件中,将上面创建的Storyboard开始播放即可。
将Storyboard对象添加到Viewport3D对象的Resources中
- 将Storyboard对象添加到Viewport3D对象的Resources中:
<Viewport3D>
<Viewport3D.Resources>
<Storyboard x:Key="RotationStoryboard">
<DoubleAnimation From="0" To="360" Duration="0:0:5" RepeatBehavior="Forever"
Storyboard.TargetName="TransformRotation" Storyboard.TargetProperty="Angle" />
</Storyboard>
</Viewport3D.Resources>
...
</Viewport3D>
给旋转对象绑定动画- 给旋转对象绑定动画:
// 创建旋转动画
DoubleAnimation rotationAnimation = new DoubleAnimation();
rotationAnimation.From = 0;
rotationAnimation.To = 360;
rotationAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
rotationAnimation.RepeatBehavior = RepeatBehavior.Forever;
// 绑定旋转动画
RotateTransform3D rotateTransform = new RotateTransform3D();
rotateTransform.Rotation = new AxisAngleRotation3D(new Vector3D(0, 1, 0), 0);
cubeModel.Transform = rotateTransform;
rotateTransform.Rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, rotationAnimation);
这段代码实现了一个旋转动画,将一个正方体对象绕着Y轴旋转。我们首先创建一个DoubleAnimation
对象,设置其From
属性为0,To
属性为360,表示从0度到360度,Duration
属性为5秒,表示动画的持续时间为5秒,RepeatBehavior
属性为Forever
,表示动画循环播放。接着,我们创建一个RotateTransform3D
对象,将其赋值给正方体对象的Transform
属性,表示该对象需要应用旋转变换。最后,我们将旋转对象的Rotation
属性绑定到旋转动画,使得该对象能够按照动画的要求旋转。
4. 总结
通过本文,我们学习了如何使用WPF创建一个3D正方体,并实现旋转动画。同时,我们也了解了一些基本的WPF 3D图形编程知识。