3DTools TrackballDecorator实现3D漫游
1.基本原理
WPF提供的TrackballDecorator類用來實(shí)現(xiàn)三維漫游功能。TrackballDecorator可以看做是在Viewport3D后面的一個(gè)虛擬球面,當(dāng)鼠標(biāo)點(diǎn)擊TraclcballDecorator投影在Viewport3D的這個(gè)平面內(nèi)時(shí),可以在球面上找到與鼠標(biāo)在平面上面一一對(duì)應(yīng)的一個(gè)點(diǎn)。當(dāng)鼠標(biāo)運(yùn)動(dòng)的時(shí)候,照相機(jī)根據(jù)鼠標(biāo)的運(yùn)動(dòng)來旋轉(zhuǎn),以此來保證鼠標(biāo)在這個(gè)虛擬球面上的位置是不變的。這樣就完成了把把鼠標(biāo)的二維運(yùn)動(dòng)轉(zhuǎn)換為三維運(yùn)動(dòng)。下面以一個(gè)立方體為模型,簡單說明一下上述過程。
圖1.1 Viewport3D與TtackballDecorator位置關(guān)系
圖1.2 鼠標(biāo)垂直拖動(dòng)
圖1-2表示當(dāng)鼠標(biāo)進(jìn)行垂直移動(dòng)的時(shí)候,球面繞X軸進(jìn)行旋轉(zhuǎn),來保證鼠標(biāo)在球面上的位置是不變的,同時(shí)球面內(nèi)的模型會(huì)跟隨球面運(yùn)動(dòng),就能得到預(yù)期的效果。
2.實(shí)現(xiàn)過程
對(duì)于每次鼠標(biāo)移動(dòng),都需要計(jì)算一個(gè)旋轉(zhuǎn)來保證鼠標(biāo)在球面上的位置是不變的。因此需要做以下兩個(gè)工作:首先,確定鼠標(biāo)在球面上的位置;其次,計(jì)算鼠標(biāo)從一個(gè)點(diǎn)移動(dòng)到另一個(gè)點(diǎn)所進(jìn)行的旋轉(zhuǎn)。為了找到鼠標(biāo)在球體上對(duì)應(yīng)的點(diǎn),將UIElement坐標(biāo)系中的二維點(diǎn)投影到的Viewport3D內(nèi)部的球面上。
(1)首先如何將二維點(diǎn)映射到Viewport3D內(nèi)部球面呢?下面顯示了兩個(gè)坐標(biāo)系。
2.1 二維坐標(biāo)系
2.2 三維坐標(biāo)系
如圖2-1所示,鼠標(biāo)顯示了其在UIElement坐標(biāo)系中的位置,原點(diǎn)(0,0)位于坐標(biāo)系的左上角。在圖2-2中把鼠標(biāo)映射到Viewport3D內(nèi)部的球面上,鼠標(biāo)的坐標(biāo)也變換為了三維坐標(biāo)系中的坐標(biāo)。
由于最終的目的是得到相機(jī)的旋轉(zhuǎn),因此可以選擇最簡單的TrackballDecorator球面坐標(biāo)系,因此可以假定這個(gè)球面半徑為1,其圓心為坐標(biāo)系的原點(diǎn)(0,0,0)。只需要構(gòu)建一個(gè)[0,0]—[2,2]的Viewport3D,然后將原點(diǎn)從左上角移動(dòng)至中心,這樣 ViewportsD 就變成了從[-1,1]一[1,-1]。如圖 2-3,圖 2-4 所示。
2.3 建一個(gè)寬、高為2的Viewport3D
2.4 將原點(diǎn)平移至中心
假設(shè)鼠標(biāo)在UIElement坐標(biāo)系的坐標(biāo)為(Px, Py),在TrackballDecorator坐標(biāo)系中的坐標(biāo)為(x,y, z)那么可得出x,y點(diǎn)坐標(biāo)如式2-1,2-2所示。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
根據(jù)球面半徑,就能得到Z坐標(biāo)如式2-3所示。
獲取三維坐標(biāo)信息代碼:
private Vector3D ProjectToTrackball(double width, double height. Point point) { double X = point.X / (width / 2); double y = point. Y / (height / 2); X = X - 1; y = 1 - y; double z2=l-x*x-y*y; double z = z2 > 0 ? Math.Sqrt(z2): 0; return new Vector3D(x, y, z); }這樣就得到了鼠標(biāo)在球面上的坐標(biāo)(x,y,z)對(duì)于鼠標(biāo)的每次拖動(dòng),都需要構(gòu)建一個(gè)旋轉(zhuǎn),使得鼠標(biāo)在球面上的位置保持不變。因此需要記錄鼠標(biāo)拖動(dòng)之前的坐標(biāo),和鼠標(biāo)拖動(dòng)到當(dāng)前位置的旋轉(zhuǎn)。為了得到這個(gè)旋轉(zhuǎn)需要計(jì)算旋轉(zhuǎn)軸和旋轉(zhuǎn)角度。
2.3用向量來描述鼠標(biāo)的拖動(dòng)
如圖2.3所示向量VI和向量V2分別為原點(diǎn)到鼠標(biāo)拖動(dòng)前所在位置和拖動(dòng)后所在位置的向量。可以簡單計(jì)算得到旋轉(zhuǎn)軸Axis和旋轉(zhuǎn)角度0,如式2-4、2-5所示。
//根據(jù)右手定則,兩向量叉乘,確定垂直兩向量的軸,即旋轉(zhuǎn)軸
Θ為球面的旋轉(zhuǎn)角度,取Θ的相反數(shù)就得到了照相機(jī)的旋轉(zhuǎn)角度,當(dāng)有了旋轉(zhuǎn)軸和旋轉(zhuǎn)角度就可以控制的照相機(jī)去進(jìn)行旋轉(zhuǎn)。
//響應(yīng)漫游
private void Track(Point currentPosition) { Vector3D currentPosition3D =ProjectToTrackball( EventSource.Actual Width,EventSource.ActualHeight, currentPosition);Vector3D axis =Vector3D.CrossProduct(_previousPosition3D, currentPosition3D); double angle =Vector3D.AngleBetween(_previousPosition3D, currentPosition3D); Quaternion delta = new Quaternion(axis, -angle); AxisAngleRotation3D r = _rotation; Quaternion q = new Quatemion(_rotation.Axis, _rotation.Angle); q*= delta; _rotation.Axis = q.Axis; _rotation.Angle = q.Angle; _previousPosition3 D = currentPosition3D; } 3.源代碼點(diǎn)擊打開鏈接
總結(jié)
以上是生活随笔為你收集整理的3DTools TrackballDecorator实现3D漫游的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: zeppelin--使用D-Tale,针
- 下一篇: 计算机专业课程设计收获及总结,课程设计的