WPF 3D Cube及点击交互
在WPF中构建一个简单的立方体比较容易实现,可参考资料也比较众多。比较麻烦的是处理点击交互。
我在WPF中用两种方式实现了3DCube,效果图如下:


方式一: 最常见的3D内容构建模式,结构如下图。

参考
<Viewport3D SnapsToDevicePixels="True" ClipToBounds="True"
RenderTransformOrigin="0.5 0.5" RenderOptions.EdgeMode="Aliased"
RenderOptions.CachingHint="Cache">
<!--Camera-->
<Viewport3D.Camera>
<PerspectiveCamera x:Name="CameraMain" Position="4,4,6" UpDirection="0,1,0" LookDirection="-4,-4,-6"
NearPlaneDistance="" FarPlaneDistance="" FieldOfView="">
<PerspectiveCamera.Transform>
<Transform3DGroup>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D x:Name="CameraRotate" Axis="0,1,0" Angle=""/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
<ScaleTransform3D />
</Transform3DGroup>
</PerspectiveCamera.Transform>
</PerspectiveCamera>
</Viewport3D.Camera>
<!--Light-->
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<AmbientLight Color="White"></AmbientLight>
<DirectionalLight Color="White" Direction="4,6,-6"/>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
<!--六个面-->
<ModelVisual3D x:Name="CubeSlaveContainer">
<ModelUIElement3D>
<GeometryModel3D x:Name="TopPanel">
<GeometryModel3D.Material>
<DiffuseMaterial x:Name="MaterialTop">
<DiffuseMaterial.Brush>
<VisualBrush>
<VisualBrush.Visual>
<TextBlock Text="" Foreground="White"/>
</VisualBrush.Visual>
</VisualBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush="Transparent"/>
</GeometryModel3D.BackMaterial>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="-2,2,2 2,2,2 2,2,-2 -2,2,-2"
TriangleIndices="0,1,2 0,2,3"
TextureCoordinates="-2,2 2,2 2,-2 -2,-2">
</MeshGeometry3D>
</GeometryModel3D.Geometry>
</GeometryModel3D>
</ModelUIElement3D>
<ModelUIElement3D>
<GeometryModel3D x:Name="BottomPanel">
<GeometryModel3D.Material>
<DiffuseMaterial x:Name="MaterialBottom">
<DiffuseMaterial.Brush>
<VisualBrush>
<VisualBrush.Visual>
<TextBlock Text="" Foreground="White"/>
</VisualBrush.Visual>
</VisualBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush="Transparent"/>
</GeometryModel3D.BackMaterial>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="-2,-2,2 2,-2,2 2,-2,-2 -2,-2,-2"
TriangleIndices="0,2,1 0,3,2"
TextureCoordinates="-2,2 2,2 2,-2 -2,-2">
</MeshGeometry3D>
</GeometryModel3D.Geometry>
</GeometryModel3D>
</ModelUIElement3D>
<ModelUIElement3D>
<GeometryModel3D x:Name="LeftPanel">
<GeometryModel3D.Material>
<DiffuseMaterial x:Name="MaterialLeft">
<DiffuseMaterial.Brush>
<VisualBrush>
<VisualBrush.Visual>
<TextBlock Text="" Foreground="White"/>
</VisualBrush.Visual>
</VisualBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush="Transparent"/>
</GeometryModel3D.BackMaterial>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="-2,-2,-2 -2,-2,2 -2,2,2 -2,2,-2"
TriangleIndices="0,1,2 0,2,3"
TextureCoordinates="-2,2 2,2 2,-2 -2,-2">
</MeshGeometry3D>
</GeometryModel3D.Geometry>
</GeometryModel3D>
</ModelUIElement3D>
<ModelUIElement3D>
<GeometryModel3D x:Name="RightPanel">
<GeometryModel3D.Material>
<DiffuseMaterial x:Name="MaterialRight">
<DiffuseMaterial.Brush>
<VisualBrush>
<VisualBrush.Visual>
<TextBlock Text="" Foreground="White"/>
</VisualBrush.Visual>
</VisualBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush="Transparent"/>
</GeometryModel3D.BackMaterial>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="2,-2,2 2,-2,-2 2,2,-2 2,2,2"
TriangleIndices="0,1,2 0,2,3"
TextureCoordinates="-2,2 2,2 2,-2 -2,-2">
</MeshGeometry3D>
</GeometryModel3D.Geometry>
</GeometryModel3D>
</ModelUIElement3D>
<ModelUIElement3D>
<GeometryModel3D x:Name="FrontPanel">
<GeometryModel3D.Material>
<DiffuseMaterial x:Name="MaterialFront">
<DiffuseMaterial.Brush>
<VisualBrush>
<VisualBrush.Visual>
<TextBlock Text="" Foreground="White"/>
</VisualBrush.Visual>
</VisualBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush="Transparent"/>
</GeometryModel3D.BackMaterial>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="-2,-2,2 2,-2,2 2,2,2 -2,2,2"
TriangleIndices="0,1,2 0,2,3"
TextureCoordinates="-2,2 2,2 2,-2 -2,-2">
</MeshGeometry3D>
</GeometryModel3D.Geometry>
</GeometryModel3D> </ModelUIElement3D>
<ModelUIElement3D>
<GeometryModel3D x:Name="BackPanel">
<GeometryModel3D.Material>
<DiffuseMaterial x:Name="MaterialBack">
<DiffuseMaterial.Brush>
<VisualBrush>
<VisualBrush.Visual>
<TextBlock Text="" Foreground="White"></TextBlock>
</VisualBrush.Visual>
</VisualBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush="Transparent"/>
</GeometryModel3D.BackMaterial>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="2,-2,-2 -2,-2,-2 -2,2,-2 2,2,-2"
TriangleIndices="0,1,2 0,2,3"
TextureCoordinates="-2,2 2,2 2,-2 -2,-2">
</MeshGeometry3D>
</GeometryModel3D.Geometry>
</GeometryModel3D>
</ModelUIElement3D>
</ModelVisual3D>
</Viewport3D>
点击交互:
给ModelUIElement3D附加事件,如下图

方式二: 使用3DTools.dll构建,结构如下图

参考
<!-- xmlns:Plugin3D="clr-namespace:_3DTools;assembly=3DTools" -->
<Plugin3D:Interactive3DDecorator HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Viewport3D x:Name="Viewport3DMain" Margin="0,-50,0,50"
SnapsToDevicePixels="True" ClipToBounds="True"
RenderTransformOrigin="0.5 0.5" RenderOptions.EdgeMode="Aliased"
RenderOptions.CachingHint="Cache">
<!--摄像机-->
<Viewport3D.Camera>
<PerspectiveCamera x:Name="CameraMain" Position="4,4,6"
UpDirection="0,1,0" LookDirection="-4,-4,-6"
NearPlaneDistance="" FarPlaneDistance="" FieldOfView="">
<PerspectiveCamera.Transform>
<Transform3DGroup>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D x:Name="CameraRotate" Axis="0,1,0" Angle=""/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
</Transform3DGroup>
</PerspectiveCamera.Transform>
</PerspectiveCamera>
</Viewport3D.Camera>
<!--Light-->
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<AmbientLight Color="White"></AmbientLight>
<DirectionalLight Color="White" Direction="4,6,-6"/>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
<!--六个面-->
<Plugin3D:InteractiveVisual3D x:Name="TopPanel" IsBackVisible="True">
<Plugin3D:InteractiveVisual3D.Geometry>
<MeshGeometry3D Positions="-2,2,2 2,2,2 2,2,-2 -2,2,-2"
TriangleIndices="0,1,2 0,2,3"
TextureCoordinates="0,0 0,1 1,1 1,0"
Normals="0,1,0 0,1,0 0,1,0 0,1,0"/>
</Plugin3D:InteractiveVisual3D.Geometry>
</Plugin3D:InteractiveVisual3D>
<Plugin3D:InteractiveVisual3D x:Name="BottomPanel" IsBackVisible="True">
<Plugin3D:InteractiveVisual3D.Geometry>
<MeshGeometry3D Positions="-2,-2,2 2,-2,2 2,-2,-2 -2,-2,-2"
TriangleIndices="0,2,1 0,3,2"
TextureCoordinates="0,0 0,1 1,1 1,0"
Normals="0,1,0 0,1,0 0,1,0 0,1,0"/>
</Plugin3D:InteractiveVisual3D.Geometry>
</Plugin3D:InteractiveVisual3D>
<Plugin3D:InteractiveVisual3D x:Name="LeftPanel" IsBackVisible="True">
<Plugin3D:InteractiveVisual3D.Geometry>
<MeshGeometry3D Positions="-2,-2,-2 -2,-2,2 -2,2,2 -2,2,-2"
TriangleIndices="0,1,2 0,2,3"
TextureCoordinates="0,0 0,1 1,1 1,0"
Normals="0,1,0 0,1,0 0,1,0 0,1,0"/>
</Plugin3D:InteractiveVisual3D.Geometry>
</Plugin3D:InteractiveVisual3D>
<Plugin3D:InteractiveVisual3D x:Name="RightPanel" IsBackVisible="True">
<Plugin3D:InteractiveVisual3D.Geometry>
<MeshGeometry3D Positions="2,-2,2 2,-2,-2 2,2,-2 2,2,2"
TriangleIndices="0,1,2 0,2,3"
TextureCoordinates="0,0 0,1 1,1 1,0"
Normals="0,1,0 0,1,0 0,1,0 0,1,0"/>
</Plugin3D:InteractiveVisual3D.Geometry>
</Plugin3D:InteractiveVisual3D>
<Plugin3D:InteractiveVisual3D x:Name="FrontPanel" IsBackVisible="True">
<Plugin3D:InteractiveVisual3D.Geometry>
<MeshGeometry3D Positions="-2,-2,2 2,-2,2 2,2,2 -2,2,2"
TriangleIndices="0,1,2 0,2,3"
TextureCoordinates="0,0 0,1 1,1 1,0"
Normals="0,1,0 0,1,0 0,1,0 0,1,0"/>
</Plugin3D:InteractiveVisual3D.Geometry>
</Plugin3D:InteractiveVisual3D>
<Plugin3D:InteractiveVisual3D x:Name="BackPanel" IsBackVisible="True">
<Plugin3D:InteractiveVisual3D.Geometry>
<MeshGeometry3D Positions="2,-2,-2 -2,-2,-2 -2,2,-2 2,2,-2"
TriangleIndices="0,1,2 0,2,3"
TextureCoordinates="0,0 0,1 1,1 1,0"
Normals="0,1,0 0,1,0 0,1,0 0,1,0"/>
</Plugin3D:InteractiveVisual3D.Geometry>
</Plugin3D:InteractiveVisual3D>
</Viewport3D>
</Plugin3D:Interactive3DDecorator>
点击交互:
给Plugin3D:InteractiveVisual3D对象的Visual对象附加点击事件,如创建一个Grid, 将Grid作为Plugin3D:InteractiveVisual3D的Visual值。
调用: this.SetCubeMaterialBrush(this.FrontPanel, "定义的ImageBrush资源的Key值", 5);
工具:Visual Studio 2017
工程:WPF C#
源码下载:

WPF 3D Cube及点击交互的更多相关文章
- WPF 3D 知识点大全以及实例
引言 现在物联网概念这么火,如果监控的信息能够实时在手机的客服端中以3D形式展示给我们,那种体验大家可以发挥自己的想象. 那生活中我们还有很多地方用到这些,如上图所示的Kinect 在医疗上的应用,当 ...
- WPF 3D 小小小小引擎 - ·WPF 3D变换应用
原文:WPF 3D 小小小小引擎 - ·WPF 3D变换应用 WPF可以提供的3D模型使我们可以轻松地创建3D实体,虽然目前来看还很有一些性能上的问题,不过对于一些简单的3D应用应该是可取的,毕竟其开 ...
- TextView + Spanned实现图文混排以及图片点击交互
最近要实现图文混排的需求,webview过大,所以想到了用SpannableStringBuilder来实现. 不过参考了大量国内文章,大多数是教你如何实现图文混排,并没有提及图片点击交互的.有翻阅了 ...
- WPF MVVM UI分离之《交互与数据分离》 基础才是重中之重~delegate里的Invoke和BeginInvoke 将不确定变为确定系列~目录(“机器最能证明一切”) 爱上MVC3系列~全局异常处理与异常日志 基础才是重中之重~lock和monitor的区别 将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行 将不确定变成确定~LINQ DBML模型可以对
WPF MVVM UI分离之<交互与数据分离> 在我们使用WPF过程中,不可避免并且超级喜欢使用MVVM框架. 那么,使用MVVM的出发点是视觉与业务逻辑分离,即UI与数据分离 诸如下 ...
- WPF 3D变换应用
WPF可以提供的3D模型使我们可以轻松地创建3D实体,虽然目前来看还很有一些性能上的问题,不过对于一些简单的3D应用应该是可取的,毕竟其开发效率高,而且也容易上手. 下面给大家演示的是使用在WPF 3 ...
- WPF 3D中多个模型如何设置某一个在最前?
原文:WPF 3D中多个模型如何设置某一个在最前? 问题:我们的模型包括导入的3D solid模型和axis坐标轴模型,当模型旋转的时候,3D会将axis挡住. 期望:axis一直在最前面,不会被3D ...
- WPF 3D 获取鼠标在场景的3d坐标
原文:WPF 3D 获取鼠标在场景的3d坐标 上一篇中我们谈到了WPF 3d做图的一些简单原理,这里我们简单介绍一下怎样获得鼠标在场景中的3d坐标,知道了3d坐标就可以进行很多操作了: 首先介绍一下3 ...
- 最优化WPF 3D性能(基于“Tier-2”硬件)
原文:最优化WPF 3D性能(基于"Tier-2"硬件) 原文地址:Maximizing WPF 3D Performance on Tier-2 Hardware 开发人员在应用 ...
- 优化WPF 3D性能
Maximize WPF 3D Performance .NET Framework 4.5 As you use the Windows Presentation Foundation (WPF ...
随机推荐
- stream,做减法,优化搜索代码。
做一个搜索,三个输入条件,求这个条件的交集.起初我的思路是按照操作的流程,一步步的来做这三个筛选. let searchResults = []; //step1 根据id搜索,得到一个子集. if ...
- 【IoT平台北向API调用】使用Postman调用Https接口
1. Download and install postman https://www.getpostman.com/ Version:the version I download is Postma ...
- L1 loss, L2 loss以及Smooth L1 Loss的对比
总结对比下\(L_1\) 损失函数,\(L_2\) 损失函数以及\(\text{Smooth} L_1\) 损失函数的优缺点. 均方误差MSE (\(L_2\) Loss) 均方误差(Mean Squ ...
- layui中formSelects的使用
1.下载 下载地址:https://github.com/hnzzmsf/layui-formSelects 2. 引入 //引入formSelects.css <link rel=" ...
- 灵魂拷问:Java 的 substring() 是如何工作的?
在逛 programcreek 的时候,我发现了一些小而精悍的主题.比如说:Java 的 substring() 方法是如何工作的?像这类灵魂拷问的主题,非常值得深入地研究一下. 另外,我想要告诉大家 ...
- 学习之Redis(一)
一.redis简介 一般学习,最好先去官网,之所以建议看官网,是因为这是一手的学习资料,其他资料都最多只能算二手,一手资料意味着最权威,准确性最高.https://redis.io/topics/in ...
- 自学PHP的第22天---ThinkPHP中的路由、ThinkPHP目录结构
这一切的一切都得从“Hello world”说起!!! 有很多东西在thinkPHP的官方开发文档上其实都有讲到,我在这里只是想记录自己每天坚持学习PHP的情况,今天接触ThinkPHP的路由,路由这 ...
- iOS 手势及触摸
转自:http://justsee.iteye.com/blog/1885538 一.响应链 在IOS开发中会遇到各种操作事件,通过程序可以对这些事件做出响应. 首先,当发生事件响应时,必须知道由谁来 ...
- java之JVM内存模型
简而言之: 基础数据类型,值是保存在栈中: 引用数据类型,值保存在堆中,栈中保存的是引用数据类型在堆中的地址: 方法区:保存所有的class和static变量:
- CF 1132A,1132B,1132C,1132D,1132E,1132F(Round 61 A,B,C,D,E,F)题解
A.Regular bracket sequence A string is called bracket sequence if it does not contain any characters ...