WPF 桌面用的 3D 小工具






3.32/5 (16投票s)
2006年9月20日
4分钟阅读

122549

3380
您是否曾想象过让 3D 对象漂浮在您的桌面上?让我们看看如何仅使用 C# 和 WPF 实现这样的结果。
引言
本文介绍了如何仅使用 C# 和 WPF 为您的桌面创建 3D 小工具。小工具应与桌面集成,始终置顶于所有打开的窗口之上,以便用户可以使用它提供的快捷方式。让我们看看如何实现这样的结果。演示项目包含此图片中所示的 iPod 模型。如果您想先学习如何构建更简单的东西,请继续阅读,您不会失望的。
分解问题
首先,让我们将这个看似不可能的问题分解成几个部分
- 创建 3D 环境
- 为我们创建的 3D 对象添加功能
- 转换窗口,使其透明并始终置顶
1. 填充 Viewport
WPF 中用于承载 3D 对象的控件称为 Viewport
。我们将使用 XAML 标记来创建 Viewport
,这是 .NET 3.0 中的首选方式。代码如下所示:
<Viewport3D Name="mainViewport" ClipToBounds="True">
<Viewport3D.Camera>
<PerspectiveCamera Position ="0,500,500" LookDirection ="0,-100,-100">
</PerspectiveCamera>
</Viewport3D.Camera>
添加了相机,因为没有光,我们将看不到我们创建的任何对象。要完全描述相机,我们必须设置其 Position
(相机在 3D 环境中的位置)和 LookDirection
(相机看向的方向)
现在,让我们向 Viewport
添加一个简单的对象
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<GeometryModel3D x:Name ="pyramid">
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="0,0,37.5 -50,-50,-37.5 50,-50,-37.5 50,50,-37.5
-50,50,-37.5 0,0,-37.5 50,-50,-37.5 50,50,-37.5 -50,50,-37.5
-50,-50,-37.5 -50,-50,-37.5 50,-50,-37.5 50,-50,-37.5 -50,50,-37.5
-50,50,-37.5 -50,-50,-37.5 "
TriangleIndices="0,2,1,0,3,6,0,4,7,0,9,8,10,11,5,12,3,5,3,13,5,14,15,5"
Normals=""
/>
</GeometryModel3D.Geometry >
<GeometryModel3D.Material >
<DiffuseMaterial Brush ="White"/>
</GeometryModel3D.Material>
</GeometryModel3D>
</Model3DGroup>
</ModelVisual3D.Content>
实际的 3D 对象由三角形组成。每个三角形都指定为一系列点;要从此对象开始创建另一个对象,您需要
- 替换
Positions
集合中的点 - 在
TriangleIndices
集合中指定三角形。
但是不用担心,有更简单的方法可以做到。对于我们这些在图形方面不太擅长的开发者来说,最简单的方法是导入现有模型;第一个截图中的 iPod 模型是从 3D Max 模型导入的。
要导入 3D Studio Max 模型,
(*.3DS),网上有很多这类模型,您可以使用 ZAM 3D,该软件可以免费试用,位于 此处,或者您可以使用在线免费转换器及其关联的 *.dll 文件,位于 此处。这个免费在线转换器可能没有更新为 .NET 3.0 RC1,因此您可能需要用逗号替换一些空格,但其余部分工作正常。如果您想知道,iPod 模型来自 ZAM 3D 提供的示例模型。
导入模型后,我们会发现如果导入多个模型,所有模型都会重叠,所以我们必须将每个模型移动到 Viewport
中的另一个位置。我们通过使用变换来实现这一点。我们想要平移对象,所以我们写道:
<ModelVisual3D.Transform>
<TranslateTransform3D OffsetX ="-200"/>
</ModelVisual3D.Transform>
</ModelVisual3D>
添加动画
为了让事情更有趣,我们将添加一个简单的动画;在您的商业应用程序中不要过度使用它,因为动画会分散用户的注意力,并且他们会更快地感到疲劳。
要为 XAML 中的元素添加动画,我们使用 Storyboard
;以便我们可以多次使用动画。我们将其添加到 Windows 资源中,如下所示:
<Window.Resources>
<Storyboard x:Key="RotateStoryboard">
<ParallelTimeline RepeatBehavior="Forever" Storyboard.TargetName="myRotate"
Storyboard.TargetProperty="Angle" >
<DoubleAnimation From="0" To="360" Duration="0:0:30"/>
</ParallelTimeline>
</Storyboard>
</Window.Resources>
动画必须在窗口加载时开始,所以我们使用 OnLoad
事件来启动它,如下所示:
void Window1_Loaded(object sender, RoutedEventArgs e)
{
Storyboard s;
s = (Storyboard)this.FindResource("RotateStoryboard");
this.BeginStoryboard(s);
}
2. 为 3D 对象添加鼠标事件处理程序
要为 3D 对象添加鼠标事件处理程序,我们首先必须找出 ViewPort
中哪个对象被单击(或发生其他鼠标操作)。为此,我们使用 ViewPort
内置的命中测试引擎,如下所示:
void mainViewport_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
System.Windows.Point mouseposition = e.GetPosition(mainViewport);
Point3D testpoint3D = new Point3D(mouseposition.X, mouseposition.Y, 0);
Vector3D testdirection = new Vector3D(mouseposition.X,
mouseposition.Y, 10);
PointHitTestParameters pointparams = new PointHitTestParameters
(mouseposition);
RayHitTestParameters rayparams = new RayHitTestParameters(testpoint3D,
testdirection);
VisualTreeHelper.HitTest(mainViewport, null, HTResult, pointparams);
}
实际处理对象单击的代码如下。关于您可能应该提供的操作的一些建议:
- 关闭小工具的可能性,因为窗体上没有关闭按钮 - 它是不可见的。使用
this.Close
函数关闭窗口。 - 将小工具拖动到屏幕另一部分的可能性,如果它通过覆盖屏幕的重要部分来方便用户(窗口的标题栏也是不可见的,因此标准拖动是不可能的)。使用
DragMove
函数可以快速实现此结果。 - 要创建指向互联网站点的快捷方式,您可以启动一个新进程
System.Diagnostics.Process.Start
,并将 URL 作为参数。private HitTestResultBehavior HTResult (System.Windows.Media.HitTestResult rawresult) { RayHitTestResult rayResult = rawresult as RayHitTestResult; if (rayResult != null) { if (cube == rayResult.ModelHit) { string targetURL = @"https://codeproject.org.cn"; System.Diagnostics.Process.Start(targetURL); } if (cross == rayResult.ModelHit) { this.Close(); } if (pyramid == rayResult.ModelHit) { DragMove(); } }
3. 使窗口不可见
XAML 中窗口的标准定义如下所示:
<Window x:Class="WindowTransparency.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowTransparency" Height="314" Width="813"
要添加透明度,只需添加这些 XAML 标签:
WindowStyle="None" Background="Transparent" AllowsTransparency ="True"
我们还想要另外两件事:窗体不得在任务栏中显示,并且必须始终置顶。相应的标签是:
ShowInTaskbar="False" Topmost="True"
使用代码的注意事项
代码基于 Vista RC1 构建,使用了 .NET 3.0 RC1 框架和 Orcas 开发工具(http://www.microsoft.com/downloads/details.aspx?FamilyID=d1336f3e-e677-426b-925c-c84a54654414&DisplayLang=en)。
它也应该可以在 Windows XP 下运行,因为我没有使用任何 Vista 独有的功能(据我所知),但尚未经过测试。
结论
您可以使用此代码创建一些简单的东西,例如 3D Mac OS X 栏,或者添加一个像 Microsoft 提供的舞者那样的舞者,但这次是 3D 的。可能性是无限的。
请注意,在 XAML 中执行这些操作多么容易,就像在普通的 VB6 应用程序中一样简单,甚至比在 .NET 2.0 中更简单。WPF 允许开发人员轻松实现出色的视觉效果,提高生产力,但代价是需要学习如何正确使用其功能。
历史
- 更新 2006/09/22:已添加 iPod 演示项目和屏幕截图。