關於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.
Point mouseposition = args.GetPosition(ViewPort);
MoveCenter(mouseposition);
}
}
}
}
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,所以代碼有點多。
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.平移后: