关于WPF 3D,网上有很多旋转的例子,但是关于平移的例子并不是太多。本文并非WPF 3D扫盲篇,因此需要对WPF 3D有一定了解,至少知道Viewport, PerspectiveCamera, ModelVisual3D等数据结构。需要了解WPF 3D的基础知识,可以参考MSDN:?http://msdn.microsoft.com/zh-cn/library/ms747437.aspx。
?
1. 摄像机平移OR物体平移:
WPF场景主要是由这两部分构成的:摄像机,物体。可以想象一下,自己拿着台摄像机正对着某个物体进行拍摄。
那么当发生平移的时候有两种方法,第一种是将摄像机平移;第二种是将物体平移。相对来说,摄像机平移实现较复杂,效率较高;物体平移效率较低,实现简单。
本文实现的是物体平移,如果希望做摄像机平移的朋友可以不往下读了。
?
2. 在本项目中平移的操作流程:?
1. 程序启动时可以看到整个3D场景,类似一个沙盘,此时旋转等操作会围绕沙盘中心;
2. 双击沙盘某个地方,将沙盘中心移动到双击的地方,此时旋转等操作会围绕新的沙盘中心。
?
3. 平移的算法:
1.获取双击屏幕后鼠标在3D中相对应的点,主要利用了射线和3D碰撞的一个原理。代码上主要应用的就是VisualTreeHelper.HitTest函数,它会将结果传入一个回调函数中,我们这里是HTResultCenter.
void BridgeVisual_MouseDoubleClick(object sender, MouseButtonEventArgs args)
{??
? ? ?Point?mouseposition?=?args.GetPosition(ViewPort);
? ?MoveCenter(mouseposition);
}
?
?public void MoveCenter(Point mouseposition)
?{
? ? ? PointHitTestParameters pointparams = new PointHitTestParameters(mouseposition);
? ? ? VisualTreeHelper.HitTest(ViewPort, null, HTResultCenter, pointparams);
?}?
?
?private HitTestResultBehavior HTResultCenter(HitTestResult result)
?{
? ? ? RayHitTestResult rayResult = result as RayHitTestResult;
? ? ? if (rayResult != null)
? ? ? {
? ? ? ? ? ?//这就是鼠标点击后在3D中的坐标
? ? ? ? ? ?var hitPoint = rayResult.PointHit;
? ? ? ? ? ?...
? ? ? }
?}?
?
2.根据相机位置 + 相机的投射方向 = 获取相机在3D上投影的点,camera.Postion就是摄像机在3D世界中的位置了,camera.LookDirection就是摄像机看的方向。那么两者加起来就可以获取这个摄像机投射过后的位置了。?
?
??
////相机位置
??
var?cameraPostion?= Camera.Position;
???????????????
??
////相机看的方向
??
var?lookDirection?= Camera.LookDirection;
??
///?获取相机在3D投影的点?
??
var?x?=?cameraPostion.X?+?lookDirection.X;
??
var?y?=?cameraPostion.Y?+?lookDirection.Y;
??
var?z?=?cameraPostion.Z?+?lookDirection.Z;
?
?
3. 那么利用摄像机投射的位置 - 鼠标双击的位置就可以获取物体应该偏移的量了,WPF中本来就有Transform3D?这个东西进行平移,
此处应用了动画DoubleAnimation,所以代码有点多。
DoubleAnimation?doubleAnimationX?=?
new?DoubleAnimation();
doubleAnimationX.BeginTime?=?
new?TimeSpan(
0,?
0,?
0);
doubleAnimationX.Duration?=?TimeSpan.FromMilliseconds(
500);
doubleAnimationX.From?= Transform3D.OffsetX;
doubleAnimationX.To?=?x?-?hitPoint.X;
DoubleAnimation?doubleAnimationY?=?
new?DoubleAnimation();
doubleAnimationY.BeginTime?=?
new?TimeSpan(
0,?
0,?
0);
doubleAnimationY.Duration?=?TimeSpan.FromMilliseconds(
500);
doubleAnimationY.From?=?_Transform3D.OffsetY;
doubleAnimationY.To?=?y?-?hitPoint.Y;
DoubleAnimation?doubleAnimationZ?=?
new?DoubleAnimation();
doubleAnimationZ.BeginTime?=?
new?TimeSpan(
0,?
0,?
0);
doubleAnimationZ.Duration?=?TimeSpan.FromMilliseconds(
500);
doubleAnimationZ.From?= Transform3D.OffsetZ;
doubleAnimationZ.To?=?z?-?hitPoint.Z;
Transform3D.BeginAnimation(TranslateTransform3D.OffsetXProperty,?doubleAnimationX);
Transform3D.BeginAnimation(TranslateTransform3D.OffsetYProperty,?doubleAnimationY); ?
Transform3D.BeginAnimation(TranslateTransform3D.OffsetZProperty,?doubleAnimationZ);??
?
?
4. 最终的效果:
1.平移前:
?
?2.平移后:
?
?