1. 程式人生 > >【轉】OSG新增自由飛行漫遊器

【轉】OSG新增自由飛行漫遊器

 1 //標頭檔案裡
 2 #define MANIPULATOR_W 0x01
 3 #define MANIPULATOR_A 0x02
 4 #define MANIPULATOR_S 0x04
 5 #define MANIPULATOR_D 0x08
 6 #define MANIPULATOR_R 0x10
 7 #define MANIPULATOR_F 0x20
 8 
 9 #define MANIPULATOR_MAX 127
10 //所有漫遊器都必須實現的4個純虛擬函式  
11         virtual void setByMatrix(const osg::Matrixd& matrix);  //
設定相機的位置姿態矩陣 12 virtual void setByInverseMatrix(const osg::Matrixd& matrix) {} //設定相機的檢視矩陣 13 virtual osg::Matrixd getMatrix() const; //獲取相機的姿態矩陣 14 virtual osg::Matrixd getInverseMatrix() const; //獲取相機的檢視矩陣 15 16 //所有操作在這裡響應 17 virtual bool handle(const
osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us); 18 19 20 void reFreshSawEarth();//在當前經緯度,姿態回正:1.視點向地面 2.頭部向正北 21 void reFreshSawSkyline(osg::Vec3d eye=osg::Vec3d(0,0,0));//在當前經緯度,頭部回正:1.視點中心不變 2.頭部向天 22 23 osg::Vec3d _eye; //視點位置 24 osg::Quat _rotate; //
旋轉姿態 25 osg::Quat _rotateNew; //旋轉姿態 26 osg::ref_ptr<osg::Node> _root; 27 28 osg::observer_ptr<osg::Node> _node; 29 osg::observer_ptr<osgEarth::MapNode> _mapNode; 30 31 osg::ref_ptr<const osgEarth::SpatialReference> _srs; 32 33 float _speed; //速度 34 float _speedBase; 35 float _speedMultiple; //速度倍數 36 float _timerRoll; 37 bool _updateAltitude; 38 bool _updateRollStart; //更新滾轉 39 bool _updateRoll; //更新滾轉 40 bool _openStree; 41 // Internal event stack comprising last two mouse events. 42 osg::ref_ptr<const osgGA::GUIEventAdapter> _ga_t1; 43 osg::ref_ptr<const osgGA::GUIEventAdapter> _ga_t0;
  1 //cpp檔案
  2 void setByMatrix(const osg::Matrixd& matrix)//設定相機的位置姿態矩陣  
  3 {
  4     gMinpulatorContgrol = 0;
  5     _eye = matrix.getTrans();
  6     osg::Vec3d  v3Eye, v3Center, v3Up;
  7     v3Eye = _eye;//使用相機實際位置
  8     osg::Vec3d v3EyeLonLat;
  9     _srs->transformFromWorld(v3Eye, v3EyeLonLat);
 10     //先獲取當前位置的經緯度,再獲取當前正上,正北
 11     osg::Matrix mRealAttitude;
 12 
 13     if (v3EyeLonLat.z() < 10000)//距離地面1千萬米以內需要矯正
 14         //reFreshSawSkyline();
 15         _updateRoll = true;
 16     else
 17         reFreshSawEarth();
 18 }  
 19 
 20 osg::Matrixd getInverseMatrix() const
 21 {
 22     osg::Matrix mat;
 23     mat.setRotate(-_rotate);
 24     mat.preMultTranslate(-_eye);
 25     return mat;
 26     //return osg::Matrixd::inverse(getMatrix());
 27 }void setNode(osg::Node* node)
 28 {
 29     // you can only set the node if it has not already been set, OR if you are setting
 30     // it to NULL. (So to change it, you must first set it to NULL.) This is to prevent
 31     // OSG from overwriting the node after you have already set on manually.
 32     if (node == 0L || !_node.valid())
 33     {
 34         _root = node;
 35         _node = node;
 36         _mapNode = 0L;
 37         _srs = 0L;
 38 
 39         established();
 40 
 41         osg::Matrix matrixGood1;
 42         GeoPoint point1(_srs, 0, 0, 10000.0);
 43         point1.createLocalToWorld(matrixGood1);
 44 
 45         _eye = matrixGood1.getTrans();
 46 
 47         osg::Vec3d worldup;
 48         point1.createWorldUpVector(worldup);
 49 
 50         osg::Matrix mat;
 51         matrixGood1.getRotate().get(mat);
 52         osg::Vec3d eye, center, up;
 53         mat.getLookAt(eye, center, up);
 54         mat.makeLookAt(eye, -worldup, up);
 55 
 56         _rotate = mat.getRotate();
 57 
 58     }
 59 }
 60 void reFreshSawSkyline(osg::Vec3d eye)
 61 {
 62     osg::Vec3d v3Eye;
 63     osg::Vec3d v3EyeLonLat;
 64     v3Eye = _eye;//使用相機實際位置
 65     
 66     if (eye != osg::Vec3d(0, 0, 0))
 67     {
 68         v3Eye += eye;
 69     }
 70 
 71     _srs->transformFromWorld(v3Eye, v3EyeLonLat);
 72     //先獲取當前位置的經緯度,再獲取當前正上,正北
 73 
 74     if (v3EyeLonLat.z() < 10000)//距離地面1千萬米以內需要矯正
 75     {
 76             osg::Matrix mRealAttitude;
 77             GeoPoint gEyeGeo(_srs, v3EyeLonLat.x(), v3EyeLonLat.y(), v3EyeLonLat.z());
 78             gEyeGeo.createLocalToWorld(mRealAttitude);
 79 
 80             osg::Vec3d v3HorizonUp;//指天向量
 81             gEyeGeo.createWorldUpVector(v3HorizonUp);
 82 
 83             _rotate.get(mRealAttitude);//要使用當前相機的姿態
 84             osg::Vec3d  theEye,v3Center, v3Up;
 85             mRealAttitude.getLookAt(theEye, v3Center, v3Up);//獲取新的位置和姿態
 86             osg::Vec3d v3Direction = v3Center - theEye;
 87             mRealAttitude.makeLookAt(osg::Vec3d(0, 0, 0), v3Direction, v3HorizonUp);
 88             _rotate = mRealAttitude.getRotate();
 89     
 90     }
 91     
 92     //_eye = v3Eye;
 93 }
 94 
 95 void  reFreshSawEarth()
 96 {
 97     osg::Vec3d  v3Eye, v3Center, v3Up;
 98     v3Eye = _eye;//使用相機實際位置
 99     osg::Vec3d v3EyeLonLat;
100     _srs->transformFromWorld(v3Eye, v3EyeLonLat);
101         //先獲取當前位置的經緯度,再獲取當前正上,正北
102         osg::Matrix mRealAttitude;
103 
104     if (v3EyeLonLat.z() < 0)//v3EyeLonLat.z()是眼點實際海拔
105         v3EyeLonLat.z() = 100;//將海拔0以下的物體拉到海拔100米
106 
107     GeoPoint gEyeGeo(_srs, v3EyeLonLat.x(), v3EyeLonLat.y(), v3EyeLonLat.z());
108     gEyeGeo.createLocalToWorld(mRealAttitude);
109 
110     osg::Vec3d v3HorizonUp;//指天向量
111     gEyeGeo.createWorldUpVector(v3HorizonUp);
112 
113     _eye = mRealAttitude.getTrans();
114 
115     mRealAttitude.getLookAt(v3Eye, v3Center, v3Up);//獲取新的位置和姿態
116 
117     osg::Matrix mDeviationAttitude;//向北位置偏移0.00001緯度,為了計算正北方向
118     GeoPoint gDeviationEyeGeo(_srs, v3EyeLonLat.x(), v3EyeLonLat.y() + 0.00001, v3EyeLonLat.z());
119     gDeviationEyeGeo.createLocalToWorld(mDeviationAttitude);
120     osg::Vec3d v3DeviationNorthPoint = mDeviationAttitude.getTrans();
121     osg::Vec3d v3NorthHeadUp = v3DeviationNorthPoint - v3Eye;
122     v3NorthHeadUp.normalize();//指北向量
123 
124     if (v3EyeLonLat.y() < 89.99999  && v3EyeLonLat.y() > -90.0)
125     {
126         mRealAttitude.makeLookAt(osg::Vec3d(0, 0, 0), -v3HorizonUp, v3NorthHeadUp);
127     }
128     _rotate = mRealAttitude.getRotate();
129 }
130 
131 bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us)
132 {
133     bool handled = false;
134 
135     switch (ea.getEventType())
136     {
137     case(osgGA::GUIEventAdapter::FRAME):
138     {
139         if (gMinpulatorContgrol & MANIPULATOR_MAX)
140         {
141             osg::Vec3d   v3Direction;         //視點方向  
142             osg::Matrix mCameraQuat;
143             osg::Vec3d  v3Eye, v3Center, v3Up;
144             _rotate.get(mCameraQuat);
145             mCameraQuat.getLookAt(v3Eye, v3Center, v3Up);//這裡的v3Eye不是實際相機的位置,而是0,0,0
146             v3Direction = v3Center - v3Eye;
147             v3Direction.normalize();
148             /*********************************************************/
149             osg::Vec3d RealEye = _eye;
150             osg::Vec3d testHight = v3Direction*100;
151             double _DvalueHight = 0.0;
152             {
153                 osg::Vec3d testLonLat1, testLonLat2;
154                 _srs->transformFromWorld(RealEye, testLonLat1);
155                 RealEye = _eye;
156                 osg::Vec3d testEye = RealEye + testHight;
157                 _srs->transformFromWorld(testEye, testLonLat2);
158                 _DvalueHight = abs(testLonLat2.z() - testLonLat1.z());
159 
160                 if (_DvalueHight < 10)//趨近水平使用水平方向
161                 {
162                     testLonLat2.z() = testLonLat1.z();
163                     _srs->transformToWorld(testLonLat2, testEye);
164                     v3Direction = testEye - RealEye;
165                     v3Direction.normalize();
166                 }
167             }
168 
169             osg::Vec3d v3CrossVector = v3Up^v3Direction;
170             v3CrossVector.normalize();
171 
172             /*********************************************************/
173             //計算地面高度
174             osg::Vec3d v3EyeLonLat;
175             v3Eye = _eye;
176             _srs->transformFromWorld(v3Eye, v3EyeLonLat);
177             double mAltitude = VRE_ENGINE.GetToolsFunc()->GetGeoPointAltitude(v3EyeLonLat.x(), v3EyeLonLat.y());
178             float height = osg::clampBetween(v3EyeLonLat.z() - mAltitude, 100.0, 1000000.0);
179             _speed = height / 200.0;//根據離地面高度計算當前速度值
180             RealEye = _eye;
181             if (gMinpulatorContgrol & MANIPULATOR_W)
182             {
183                 RealEye += v3Direction * _speed *_speedMultiple * _speedBase;
184                 _updateAltitude = false;
185             }if (gMinpulatorContgrol & MANIPULATOR_A)
186             {
187                 RealEye += v3CrossVector * _speed *_speedMultiple * _speedBase;
188                 _updateAltitude = false;
189             }if (gMinpulatorContgrol & MANIPULATOR_S)
190             {
191                 RealEye -= v3Direction * _speed *_speedMultiple * _speedBase;
192                 _updateAltitude = false;
193             }if (gMinpulatorContgrol & MANIPULATOR_D)
194             {
195                 RealEye -= v3CrossVector * _speed *_speedMultiple * _speedBase;
196                 _updateAltitude = false;
197             }if (gMinpulatorContgrol & MANIPULATOR_R)
198             {
199                 //_eye += v3Up * _speed *_speedMultiple * _speedBase;
200                 v3EyeLonLat.z() += _speed *_speedMultiple * _speedBase;
201                 osg::Vec3d newv3Eye;
202                 _srs->transformToWorld(v3EyeLonLat, newv3Eye);
203                 RealEye = newv3Eye;
204                 _updateAltitude = false;
205             }if (gMinpulatorContgrol & MANIPULATOR_F)
206             {
207                 //_eye -= v3Up * _speed *_speedMultiple * _speedBase;
208                 v3EyeLonLat.z() -= _speed *_speedMultiple * _speedBase;
209                 osg::Vec3d newv3Eye;
210                 _srs->transformToWorld(v3EyeLonLat, newv3Eye);
211                 RealEye = newv3Eye;
212                 _updateAltitude = false;
213             }
214 
215             _eye = RealEye;
216             //reFreshSawSkyline(RealEye);
217         }
218     
219         if (_updateRoll)
220         {
221             osg::Vec3d v3Eye;
222             osg::Vec3d v3EyeLonLat;
223             v3Eye = _eye;//使用相機實際位置
224             _srs->transformFromWorld(v3Eye, v3EyeLonLat);
225             //先獲取當前位置的經緯度,再獲取當前正上,正北
226 
227             if (v3EyeLonLat.z() < 10000)//距離地面1千萬米以內需要矯正
228             {
229                 osg::Matrix mRealAttitude;
230                 GeoPoint gEyeGeo(_srs, v3EyeLonLat.x(), v3EyeLonLat.y(), v3EyeLonLat.z());
231                 gEyeGeo.createLocalToWorld(mRealAttitude);
232 
233                 osg::Vec3d v3HorizonUp;//指天向量
234                 gEyeGeo.createWorldUpVector(v3HorizonUp);
235 
236                 _rotate.get(mRealAttitude);//要使用當前相機的姿態
237                 osg::Vec3d  theEye, v3Center, v3Up;
238                 mRealAttitude.getLookAt(theEye, v3Center, v3Up);//獲取新的位置和姿態
239                 osg::Vec3d v3Direction = v3Center - theEye;
240                 mRealAttitude.makeLookAt(osg::Vec3d(0, 0, 0), v3Direction, v3HorizonUp);
241                 _rotateNew = mRealAttitude.getRotate();
242                 _updateRoll = false;
243                 _updateRollStart = true;
244                 _timerRoll = 0.0;
245             }
246             else
247             {
248                 _updateRoll = false;
249             }
250         }
251 
252         if (_updateRollStart)
253         {
254             _timerRoll += 0.01;
255             if (_timerRoll > 1.0)
256             {
257                 _timerRoll = 1.0;
258                 _updateRollStart = false;
259             }
260             _rotate.slerp(_timerRoll, _rotate, _rotateNew);
261         }
262 
263         if (_updateAltitude)
264         {
265             //每幀調節高度
266             osg::Vec3d newEye = _eye;
267             osg::Vec3d v3EyeLonLat;
268             _srs->transformFromWorld(newEye, v3EyeLonLat);
269             double _mAltitude = v3EyeLonLat.z();
270             double mAltitude = VRE_ENGINE.GetToolsFunc()->GetGeoPointAltitude(v3EyeLonLat.x(), v3EyeLonLat.y()) + MANIPULATOR_PERSONVIEWHEIGHT;
271             double interprolationAltitude = mAltitude - _mAltitude;
272             if (interprolationAltitude > 1)
273             {
274                 interprolationAltitude /= 10.0;
275                 v3EyeLonLat.z() += interprolationAltitude;
276             }
277             else if (interprolationAltitude > 0.1)
278             {
279                 v3EyeLonLat.z() += 0.1;
280             }
281             else
282             {
283                 _updateAltitude = false;
284             }
285             osg::Vec3d FinalEye;
286             _srs->transformToWorld(v3EyeLonLat, FinalEye);
287             _eye = FinalEye;
288         }
289     }break;
290     case(osgGA::GUIEventAdapter::PUSH):
291     {
292     }break;
293     case(osgGA::GUIEventAdapter::RELEASE):
294     {
295         flushMouseEventStack();
296     }break;
297     case(osgGA::GUIEventAdapter::DRAG):
298     {
299         if (calcMovement(ea))//根據滑鼠在螢幕中的位置調整相機轉向
300         {
301             //reFreshSawSkyline();
302             _updateRoll = true;
303             us.requestRedraw();
304             return true;
305         }
306     };
307     case(osgGA::GUIEventAdapter::SCROLL)://由於已經每幀都調整姿態,所以手動滾動不需要了
308     {
309         osg::Vec3d   v3Direction;         //視點方向  
310         osg::Matrix mCameraQuat;
311         osg::Vec3d  v3Eye, v3Center, v3Up;
312         _rotate.get(mCameraQuat);
313         mCameraQuat.getLookAt(v3Eye, v3Center, v3Up);//這裡的v3Eye不是實際相機的位置,而是0,0,0
314         v3Direction = v3Center - v3Eye;
315         v3Direction.normalize();
316         osg::Vec3d v3CrossVector = v3Up^v3Direction;
317         v3CrossVector.normalize();
318         switch (ea.getScrollingMotion())
319         {
320         case osgGA::GUIEventAdapter::ScrollingMotion::SCROLL_UP:
321         {
322             _eye += v3Direction * _speed *_speedMultiple;
323             //reFreshSawSkyline();
324             _updateRoll = true;
325         }break;
326         case osgGA::GUIEventAdapter::ScrollingMotion::SCROLL_DOWN:
327         {
328             _eye -= v3Direction * _speed *_speedMultiple;
329             //reFreshSawSkyline();
330             _updateRoll = true;
331         }break;
332         }
333         //reFreshSawSkyline();
334 
335         return true;
336     }break;
337     case (osgGA::GUIEventAdapter::KEYDOWN):
338     {
339         if (ea.getKey() == 'r' || ea.getKey() == 'R')//往頭部前進
340         {
341             gMinpulatorContgrol |= MANIPULATOR_R;
342         }
343         if (ea.getKey() == 'f' || ea.getKey() == 'F')//往尾部後退
344         {
345             gMinpulatorContgrol |= MANIPULATOR_F;
346         }
347         if (ea.getKey() == 'w' || ea.getKey() == 'W' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Up)//前進
348         {
349             gMinpulatorContgrol |= MANIPULATOR_W;
350         }
351         if (ea.getKey() == 's' || ea.getKey() == 'S' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Down)//後退
352         {
353             gMinpulatorContgrol |= MANIPULATOR_S;
354         }
355         if (ea.getKey() == 'a' || ea.getKey() == 'A' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Left)//左移
356         {
357             gMinpulatorContgrol |= MANIPULATOR_A;
358         }
359         if (ea.getKey() == 'd' || ea.getKey() == 'D' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)//右移
360         {
361             gMinpulatorContgrol |= MANIPULATOR_D;
362         }
363         if (ea.getKey() == '-' || ea.getKey() == '_' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Down)//減10倍移動速度
364         {
365             _speedBase /= 10.0;
366             if (_speedBase < 0.1)
367             {
368                 _speedBase = 0.1;
369             }
370         }
371         if (ea.getKey() == '=' || ea.getKey() == '+' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Up)//加10倍移動速度
372         {
373             _speedBase *= 10.0;
374             if (_speedBase > 1000.0)
375             {
376                 _speedBase = 1000.0;
377             }
378         }
379 
380         if (ea.getKey() == 'h' || ea.getKey() == 'H')//在當前經緯度,姿態回正:1.視點向地面 2.頭部向正北
381         {
382             reFreshSawEarth();
383         }
384         if (ea.getKey() == 'g' || ea.getKey() == 'G')//在當前經緯度,頭部回正:1.視點中心不變 2.頭部向天
385         {
386             reFreshSawSkyline();
387         }
388         if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L || ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_R)
389         {
390             _speedMultiple = 10.0;
391         }
392     }break;
393     case (osgGA::GUIEventAdapter::KEYUP):
394     {
395         if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L || ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_R)
396         {
397             _speedMultiple = 1.0;
398         }
399         if (ea.getKey() == 'a' || ea.getKey() == 'A' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Left)//左移
400         {
401             gMinpulatorContgrol &= ~MANIPULATOR_A;
402             _updateAltitude = true;
403         }
404         if (ea.getKey() == 'd' || ea.getKey() == 'D' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)//右移
405         {
406             gMinpulatorContgrol &= ~MANIPULATOR_D;
407             _updateAltitude = true;
408         }
409         if (ea.getKey() == 'w' || ea.getKey() == 'W' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Up)//前進
410         {
411             gMinpulatorContgrol &= ~MANIPULATOR_W;
412             _updateAltitude = true;
413         }
414         if (ea.getKey() == 'q' || ea.getKey() == 'Q' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Up)//往頭部前進
415         {
416             gMinpulatorContgrol &= ~MANIPULATOR_R;
417             _updateAltitude = true;
418         }
419         if (ea.getKey() == 'e' || ea.getKey() == 'E' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Down)//往尾部後退
420         {
421             gMinpulatorContgrol &= ~MANIPULATOR_F;
422             _updateAltitude = true;
423         }
424         if (ea.getKey() == 's' || ea.getKey() == 'S' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Down)//後退
425         {
426             gMinpulatorContgrol &= ~MANIPULATOR_S;
427             _updateAltitude = true;
428         }
429     }break;
430     default:
431         break;
432     }
433 
434     return handled;
435 }