]> git.mxchange.org Git - flightgear.git/blob - src/Main/viewer.cxx
Fix a problem with two concurent 'round to multiple of basic simulation
[flightgear.git] / src / Main / viewer.cxx
1 // viewer.cxx -- class for managing a viewer in the flightgear world.
2 //
3 // Written by Curtis Olson, started August 1997.
4 //                          overhaul started October 2000.
5 //   partially rewritten by Jim Wilson jim@kelcomaine.com using interface
6 //                          by David Megginson March 2002
7 //
8 // Copyright (C) 1997 - 2000  Curtis L. Olson  - http://www.flightgear.org/~curt
9 //
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License as
12 // published by the Free Software Foundation; either version 2 of the
13 // License, or (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 // General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23 //
24 // $Id$
25
26 #ifdef HAVE_CONFIG_H
27 #  include "config.h"
28 #endif
29
30 #include <simgear/compiler.h>
31
32 #include "fg_props.hxx"
33
34 #ifdef HAVE_CONFIG_H
35 #  include <config.h>
36 #endif
37
38 #include <simgear/debug/logstream.hxx>
39 #include <simgear/constants.h>
40 #include <simgear/scene/model/placement.hxx>
41 #include <simgear/math/vector.hxx>
42
43 #include <Main/globals.hxx>
44 #include <Scenery/scenery.hxx>
45 #include <Model/acmodel.hxx>
46
47 #include "viewer.hxx"
48
49 #include "CameraGroup.hxx"
50
51 using namespace flightgear;
52 \f
53 ////////////////////////////////////////////////////////////////////////
54 // Implementation of FGViewer.
55 ////////////////////////////////////////////////////////////////////////
56
57 // Constructor...
58 FGViewer::FGViewer( fgViewType Type, bool from_model, int from_model_index,
59                     bool at_model, int at_model_index,
60                     double damp_roll, double damp_pitch, double damp_heading,
61                     double x_offset_m, double y_offset_m, double z_offset_m,
62                     double heading_offset_deg, double pitch_offset_deg,
63                     double roll_offset_deg,
64                     double fov_deg, double aspect_ratio_multiplier,
65                     double target_x_offset_m, double target_y_offset_m,
66                     double target_z_offset_m, double near_m, bool internal ):
67     _dirty(true),
68     _lon_deg(0),
69     _lat_deg(0),
70     _alt_ft(0),
71     _target_lon_deg(0),
72     _target_lat_deg(0),
73     _target_alt_ft(0),
74     _roll_deg(0),
75     _pitch_deg(0),
76     _heading_deg(0),
77     _damp_sync(0),
78     _damp_roll(0),
79     _damp_pitch(0),
80     _damp_heading(0),
81     _scaling_type(FG_SCALING_MAX),
82     _cameraGroup(CameraGroup::getDefault())
83 {
84     _absolute_view_pos = SGVec3d(0, 0, 0);
85     _type = Type;
86     _from_model = from_model;
87     _from_model_index = from_model_index;
88     _at_model = at_model;
89     _at_model_index = at_model_index;
90
91     _internal = internal;
92
93     if (damp_roll > 0.0)
94       _damp_roll = 1.0 / pow(10.0, fabs(damp_roll));
95     if (damp_pitch > 0.0)
96       _damp_pitch = 1.0 / pow(10.0, fabs(damp_pitch));
97     if (damp_heading > 0.0)
98       _damp_heading = 1.0 / pow(10.0, fabs(damp_heading));
99
100     _offset_m.x() = x_offset_m;
101     _offset_m.y() = y_offset_m;
102     _offset_m.z() = z_offset_m;
103     _heading_offset_deg = heading_offset_deg;
104     _pitch_offset_deg = pitch_offset_deg;
105     _roll_offset_deg = roll_offset_deg;
106     _goal_heading_offset_deg = heading_offset_deg;
107     _goal_pitch_offset_deg = pitch_offset_deg;
108     _goal_roll_offset_deg = roll_offset_deg;
109     if (fov_deg > 0) {
110       _fov_deg = fov_deg;
111     } else {
112       _fov_deg = 55;
113     }
114     _aspect_ratio = 1;
115     _aspect_ratio_multiplier = aspect_ratio_multiplier;
116     _target_offset_m.x() = target_x_offset_m;
117     _target_offset_m.y() = target_y_offset_m;
118     _target_offset_m.z() = target_z_offset_m;
119     _ground_level_nearplane_m = near_m;
120     // a reasonable guess for init, so that the math doesn't blow up
121 }
122
123
124 // Destructor
125 FGViewer::~FGViewer( void ) {
126 }
127
128 void
129 FGViewer::init ()
130 {
131 }
132
133 void
134 FGViewer::bind ()
135 {
136 }
137
138 void
139 FGViewer::unbind ()
140 {
141 }
142
143 void
144 FGViewer::setType ( int type )
145 {
146   if (type == 0)
147     _type = FG_LOOKFROM;
148   if (type == 1)
149     _type = FG_LOOKAT;
150 }
151
152 void
153 FGViewer::setInternal ( bool internal )
154 {
155   _internal = internal;
156 }
157
158 void
159 FGViewer::setLongitude_deg (double lon_deg)
160 {
161   _dirty = true;
162   _lon_deg = lon_deg;
163 }
164
165 void
166 FGViewer::setLatitude_deg (double lat_deg)
167 {
168   _dirty = true;
169   _lat_deg = lat_deg;
170 }
171
172 void
173 FGViewer::setAltitude_ft (double alt_ft)
174 {
175   _dirty = true;
176   _alt_ft = alt_ft;
177 }
178
179 void
180 FGViewer::setPosition (double lon_deg, double lat_deg, double alt_ft)
181 {
182   _dirty = true;
183   _lon_deg = lon_deg;
184   _lat_deg = lat_deg;
185   _alt_ft = alt_ft;
186 }
187
188 void
189 FGViewer::setTargetLongitude_deg (double lon_deg)
190 {
191   _dirty = true;
192   _target_lon_deg = lon_deg;
193 }
194
195 void
196 FGViewer::setTargetLatitude_deg (double lat_deg)
197 {
198   _dirty = true;
199   _target_lat_deg = lat_deg;
200 }
201
202 void
203 FGViewer::setTargetAltitude_ft (double alt_ft)
204 {
205   _dirty = true;
206   _target_alt_ft = alt_ft;
207 }
208
209 void
210 FGViewer::setTargetPosition (double lon_deg, double lat_deg, double alt_ft)
211 {
212   _dirty = true;
213   _target_lon_deg = lon_deg;
214   _target_lat_deg = lat_deg;
215   _target_alt_ft = alt_ft;
216 }
217
218 void
219 FGViewer::setRoll_deg (double roll_deg)
220 {
221   _dirty = true;
222   _roll_deg = roll_deg;
223 }
224
225 void
226 FGViewer::setPitch_deg (double pitch_deg)
227 {
228   _dirty = true;
229   _pitch_deg = pitch_deg;
230 }
231
232 void
233 FGViewer::setHeading_deg (double heading_deg)
234 {
235   _dirty = true;
236   _heading_deg = heading_deg;
237 }
238
239 void
240 FGViewer::setOrientation (double roll_deg, double pitch_deg, double heading_deg)
241 {
242   _dirty = true;
243   _roll_deg = roll_deg;
244   _pitch_deg = pitch_deg;
245   _heading_deg = heading_deg;
246 }
247
248 void
249 FGViewer::setTargetRoll_deg (double target_roll_deg)
250 {
251   _dirty = true;
252   _target_roll_deg = target_roll_deg;
253 }
254
255 void
256 FGViewer::setTargetPitch_deg (double target_pitch_deg)
257 {
258   _dirty = true;
259   _target_pitch_deg = target_pitch_deg;
260 }
261
262 void
263 FGViewer::setTargetHeading_deg (double target_heading_deg)
264 {
265   _dirty = true;
266   _target_heading_deg = target_heading_deg;
267 }
268
269 void
270 FGViewer::setTargetOrientation (double target_roll_deg, double target_pitch_deg, double target_heading_deg)
271 {
272   _dirty = true;
273   _target_roll_deg = target_roll_deg;
274   _target_pitch_deg = target_pitch_deg;
275   _target_heading_deg = target_heading_deg;
276 }
277
278 void
279 FGViewer::setXOffset_m (double x_offset_m)
280 {
281   _dirty = true;
282   _offset_m.x() = x_offset_m;
283 }
284
285 void
286 FGViewer::setYOffset_m (double y_offset_m)
287 {
288   _dirty = true;
289   _offset_m.y() = y_offset_m;
290 }
291
292 void
293 FGViewer::setZOffset_m (double z_offset_m)
294 {
295   _dirty = true;
296   _offset_m.z() = z_offset_m;
297 }
298
299 void
300 FGViewer::setTargetXOffset_m (double target_x_offset_m)
301 {
302   _dirty = true;
303   _target_offset_m.x() = target_x_offset_m;
304 }
305
306 void
307 FGViewer::setTargetYOffset_m (double target_y_offset_m)
308 {
309   _dirty = true;
310   _target_offset_m.y() = target_y_offset_m;
311 }
312
313 void
314 FGViewer::setTargetZOffset_m (double target_z_offset_m)
315 {
316   _dirty = true;
317   _target_offset_m.z() = target_z_offset_m;
318 }
319
320 void
321 FGViewer::setPositionOffsets (double x_offset_m, double y_offset_m, double z_offset_m)
322 {
323   _dirty = true;
324   _offset_m.x() = x_offset_m;
325   _offset_m.y() = y_offset_m;
326   _offset_m.z() = z_offset_m;
327 }
328
329 void
330 FGViewer::setRollOffset_deg (double roll_offset_deg)
331 {
332   _dirty = true;
333   _roll_offset_deg = roll_offset_deg;
334 }
335
336 void
337 FGViewer::setPitchOffset_deg (double pitch_offset_deg)
338 {
339   _dirty = true;
340   _pitch_offset_deg = pitch_offset_deg;
341 }
342
343 void
344 FGViewer::setHeadingOffset_deg (double heading_offset_deg)
345 {
346   _dirty = true;
347   _heading_offset_deg = heading_offset_deg;
348 }
349
350 void
351 FGViewer::setGoalRollOffset_deg (double goal_roll_offset_deg)
352 {
353   _dirty = true;
354   _goal_roll_offset_deg = goal_roll_offset_deg;
355 }
356
357 void
358 FGViewer::setGoalPitchOffset_deg (double goal_pitch_offset_deg)
359 {
360   _dirty = true;
361   _goal_pitch_offset_deg = goal_pitch_offset_deg;
362   if ( _goal_pitch_offset_deg < -90 ) {
363     _goal_pitch_offset_deg = -90.0;
364   }
365   if ( _goal_pitch_offset_deg > 90.0 ) {
366     _goal_pitch_offset_deg = 90.0;
367   }
368
369 }
370
371 void
372 FGViewer::setGoalHeadingOffset_deg (double goal_heading_offset_deg)
373 {
374   _dirty = true;
375   _goal_heading_offset_deg = goal_heading_offset_deg;
376   while ( _goal_heading_offset_deg < 0.0 ) {
377     _goal_heading_offset_deg += 360;
378   }
379   while ( _goal_heading_offset_deg > 360 ) {
380     _goal_heading_offset_deg -= 360;
381   }
382 }
383
384 void
385 FGViewer::setOrientationOffsets (double roll_offset_deg, double pitch_offset_deg, double heading_offset_deg)
386 {
387   _dirty = true;
388   _roll_offset_deg = roll_offset_deg;
389   _pitch_offset_deg = pitch_offset_deg;
390   _heading_offset_deg = heading_offset_deg;
391 }
392
393 // recalc() is done every time one of the setters is called (making the 
394 // cached data "dirty") on the next "get".  It calculates all the outputs 
395 // for viewer.
396 void
397 FGViewer::recalc ()
398 {
399   if (_type == FG_LOOKFROM) {
400     recalcLookFrom();
401   } else {
402     recalcLookAt();
403   }
404
405   set_clean();
406 }
407
408 // recalculate for LookFrom view type...
409 void
410 FGViewer::recalcLookFrom ()
411 {
412   // Update location data ...
413   if ( _from_model ) {
414     SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
415     _lat_deg = placement->getLatitudeDeg();
416     _lon_deg = placement->getLongitudeDeg();
417     _alt_ft = placement->getElevationFt();
418
419     _heading_deg = placement->getHeadingDeg();
420     _pitch_deg = placement->getPitchDeg();
421     _roll_deg = placement->getRollDeg();
422   }
423   double lat = _lat_deg;
424   double lon = _lon_deg;
425   double alt = _alt_ft;
426   double head = _heading_deg;
427   double pitch = _pitch_deg;
428   double roll = _roll_deg;
429   if ( !_from_model ) {
430     // update from our own data...
431     dampEyeData(roll, pitch, head);
432   }
433
434   // The geodetic position of our base view position
435   SGGeod geodPos = SGGeod::fromDegFt(lon, lat, alt);
436   // The rotation rotating from the earth centerd frame to
437   // the horizontal local OpenGL frame
438   SGQuatd hlOr = SGQuatd::viewHL(geodPos);
439
440   // the rotation from the horizontal local frame to the basic view orientation
441   SGQuatd hlToBody = SGQuatd::fromYawPitchRollDeg(head, pitch, roll);
442   hlToBody = SGQuatd::simToView(hlToBody);
443
444   // The cartesian position of the basic view coordinate
445   SGVec3d position = SGVec3d::fromGeod(geodPos);
446   // the rotation offset, don't know why heading is negative here ...
447   SGQuatd viewOffsetOr = SGQuatd::simToView(
448     SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg, _pitch_offset_deg,
449                                  _roll_offset_deg));
450
451   // Compute the eyepoints orientation and position
452   // wrt the earth centered frame - that is global coorinates
453   SGQuatd ec2body = hlOr*hlToBody;
454   _absolute_view_pos = position + ec2body.backTransform(_offset_m);
455   mViewOrientation = ec2body*viewOffsetOr;
456 }
457
458 void
459 FGViewer::recalcLookAt ()
460 {
461   // The geodetic position of our target to look at
462   if ( _at_model ) {
463     SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
464     _target_lat_deg = placement->getLatitudeDeg();
465     _target_lon_deg = placement->getLongitudeDeg();
466     _target_alt_ft = placement->getElevationFt();
467     _target_heading_deg = placement->getHeadingDeg();
468     _target_pitch_deg = placement->getPitchDeg();
469     _target_roll_deg = placement->getRollDeg();
470   } else {
471     // if not model then calculate our own target position...
472     dampEyeData(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
473
474   }
475   SGGeod geodTargetPos = SGGeod::fromDegFt(_target_lon_deg,
476                                            _target_lat_deg,
477                                            _target_alt_ft);
478   SGQuatd geodTargetOr = SGQuatd::fromYawPitchRollDeg(_target_heading_deg,
479                                                       _target_pitch_deg,
480                                                       _target_roll_deg);
481   SGQuatd geodTargetHlOr = SGQuatd::fromLonLat(geodTargetPos);
482
483
484   if ( _from_model ) {
485     SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
486     _lat_deg = placement->getLatitudeDeg();
487     _lon_deg = placement->getLongitudeDeg();
488     _alt_ft = placement->getElevationFt();
489     _heading_deg = placement->getHeadingDeg();
490     _pitch_deg = placement->getPitchDeg();
491     _roll_deg = placement->getRollDeg();
492   } else {
493     // update from our own data, just the rotation here...
494     dampEyeData(_roll_deg, _pitch_deg, _heading_deg);
495   }
496   SGGeod geodEyePos = SGGeod::fromDegFt(_lon_deg, _lat_deg, _alt_ft);
497   SGQuatd geodEyeOr = SGQuatd::fromYawPitchRollDeg(_heading_deg,
498                                                    _pitch_deg,
499                                                    _roll_deg);
500   SGQuatd geodEyeHlOr = SGQuatd::fromLonLat(geodEyePos);
501
502   // the rotation offset, don't know why heading is negative here ...
503   SGQuatd eyeOffsetOr =
504     SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg + 180, _pitch_offset_deg,
505                                  _roll_offset_deg);
506
507   // Offsets to the eye position
508   SGVec3d eyeOff(-_offset_m.z(), _offset_m.x(), -_offset_m.y());
509   SGQuatd ec2eye = geodEyeHlOr*geodEyeOr;
510   SGVec3d eyeCart = SGVec3d::fromGeod(geodEyePos);
511   eyeCart += (ec2eye*eyeOffsetOr).backTransform(eyeOff);
512
513   SGVec3d atCart = SGVec3d::fromGeod(geodTargetPos);
514
515   // add target offsets to at_position...
516   SGVec3d target_pos_off(-_target_offset_m.z(), _target_offset_m.x(),
517                          -_target_offset_m.y());
518   target_pos_off = (geodTargetHlOr*geodTargetOr).backTransform(target_pos_off);
519   atCart += target_pos_off;
520   eyeCart += target_pos_off;
521
522   // Compute the eyepoints orientation and position
523   // wrt the earth centered frame - that is global coorinates
524   _absolute_view_pos = eyeCart;
525
526   // the view direction
527   SGVec3d dir = normalize(atCart - eyeCart);
528   // the up directon
529   SGVec3d up = ec2eye.backTransform(SGVec3d(0, 0, -1));
530   // rotate dir to the 0-th unit vector
531   // rotate up to 2-th unit vector
532   mViewOrientation = SGQuatd::fromRotateTo(-dir, 2, up, 1);
533 }
534
535 void
536 FGViewer::dampEyeData(double &roll_deg, double &pitch_deg, double &heading_deg)
537 {
538   const double interval = 0.01;
539
540   static FGViewer *last_view = 0;
541   if (last_view != this) {
542     _damp_sync = 0.0;
543     _damped_roll_deg = roll_deg;
544     _damped_pitch_deg = pitch_deg;
545     _damped_heading_deg = heading_deg;
546     last_view = this;
547     return;
548   }
549
550   if (_damp_sync < interval) {
551     if (_damp_roll > 0.0)
552       roll_deg = _damped_roll_deg;
553     if (_damp_pitch > 0.0)
554       pitch_deg = _damped_pitch_deg;
555     if (_damp_heading > 0.0)
556       heading_deg = _damped_heading_deg;
557     return;
558   }
559
560   while (_damp_sync >= interval) {
561     _damp_sync -= interval;
562
563     double d;
564     if (_damp_roll > 0.0) {
565       d = _damped_roll_deg - roll_deg;
566       if (d >= 180.0)
567         _damped_roll_deg -= 360.0;
568       else if (d < -180.0)
569         _damped_roll_deg += 360.0;
570       roll_deg = _damped_roll_deg = roll_deg * _damp_roll + _damped_roll_deg * (1 - _damp_roll);
571     }
572
573     if (_damp_pitch > 0.0) {
574       d = _damped_pitch_deg - pitch_deg;
575       if (d >= 180.0)
576         _damped_pitch_deg -= 360.0;
577       else if (d < -180.0)
578         _damped_pitch_deg += 360.0;
579       pitch_deg = _damped_pitch_deg = pitch_deg * _damp_pitch + _damped_pitch_deg * (1 - _damp_pitch);
580     }
581
582     if (_damp_heading > 0.0) {
583       d = _damped_heading_deg - heading_deg;
584       if (d >= 180.0)
585         _damped_heading_deg -= 360.0;
586       else if (d < -180.0)
587         _damped_heading_deg += 360.0;
588       heading_deg = _damped_heading_deg = heading_deg * _damp_heading + _damped_heading_deg * (1 - _damp_heading);
589     }
590   }
591 }
592
593 double
594 FGViewer::get_h_fov()
595 {
596     switch (_scaling_type) {
597     case FG_SCALING_WIDTH:  // h_fov == fov
598         return _fov_deg;
599     case FG_SCALING_MAX:
600         if (_aspect_ratio < 1.0) {
601             // h_fov == fov
602             return _fov_deg;
603         } else {
604             // v_fov == fov
605             return
606                 atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
607                      / (_aspect_ratio*_aspect_ratio_multiplier))
608                 * SG_RADIANS_TO_DEGREES * 2;
609         }
610     default:
611         assert(false);
612     }
613     return 0.0;
614 }
615
616
617
618 double
619 FGViewer::get_v_fov()
620 {
621     switch (_scaling_type) {
622     case FG_SCALING_WIDTH:  // h_fov == fov
623         return 
624             atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
625                  * (_aspect_ratio*_aspect_ratio_multiplier))
626             * SG_RADIANS_TO_DEGREES * 2;
627     case FG_SCALING_MAX:
628         if (_aspect_ratio < 1.0) {
629             // h_fov == fov
630             return
631                 atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
632                      * (_aspect_ratio*_aspect_ratio_multiplier))
633                 * SG_RADIANS_TO_DEGREES * 2;
634         } else {
635             // v_fov == fov
636             return _fov_deg;
637         }
638     default:
639         assert(false);
640     }
641     return 0.0;
642 }
643
644 void
645 FGViewer::update (double dt)
646 {
647   _damp_sync += dt;
648
649   int i;
650   int dt_ms = int(dt * 1000);
651   for ( i = 0; i < dt_ms; i++ ) {
652     if ( fabs( _goal_heading_offset_deg - _heading_offset_deg) < 1 ) {
653       setHeadingOffset_deg( _goal_heading_offset_deg );
654       break;
655     } else {
656       // move current_view.headingoffset towards
657       // current_view.goal_view_offset
658       if ( _goal_heading_offset_deg > _heading_offset_deg )
659         {
660           if ( _goal_heading_offset_deg - _heading_offset_deg < 180 ){
661             incHeadingOffset_deg( 0.5 );
662           } else {
663             incHeadingOffset_deg( -0.5 );
664           }
665         } else {
666           if ( _heading_offset_deg - _goal_heading_offset_deg < 180 ){
667             incHeadingOffset_deg( -0.5 );
668           } else {
669             incHeadingOffset_deg( 0.5 );
670           }
671         }
672       if ( _heading_offset_deg > 360 ) {
673         incHeadingOffset_deg( -360 );
674       } else if ( _heading_offset_deg < 0 ) {
675         incHeadingOffset_deg( 360 );
676       }
677     }
678   }
679
680   for ( i = 0; i < dt_ms; i++ ) {
681     if ( fabs( _goal_pitch_offset_deg - _pitch_offset_deg ) < 1 ) {
682       setPitchOffset_deg( _goal_pitch_offset_deg );
683       break;
684     } else {
685       // move current_view.pitch_offset_deg towards
686       // current_view.goal_pitch_offset
687       if ( _goal_pitch_offset_deg > _pitch_offset_deg )
688         {
689           incPitchOffset_deg( 1.0 );
690         } else {
691             incPitchOffset_deg( -1.0 );
692         }
693       if ( _pitch_offset_deg > 90 ) {
694         setPitchOffset_deg(90);
695       } else if ( _pitch_offset_deg < -90 ) {
696         setPitchOffset_deg( -90 );
697       }
698     }
699   }
700
701
702   for ( i = 0; i < dt_ms; i++ ) {
703     if ( fabs( _goal_roll_offset_deg - _roll_offset_deg ) < 1 ) {
704       setRollOffset_deg( _goal_roll_offset_deg );
705       break;
706     } else {
707       // move current_view.roll_offset_deg towards
708       // current_view.goal_roll_offset
709       if ( _goal_roll_offset_deg > _roll_offset_deg )
710         {
711           incRollOffset_deg( 1.0 );
712         } else {
713             incRollOffset_deg( -1.0 );
714         }
715       if ( _roll_offset_deg > 90 ) {
716         setRollOffset_deg(90);
717       } else if ( _roll_offset_deg < -90 ) {
718         setRollOffset_deg( -90 );
719       }
720     }
721   }
722   recalc();
723   _cameraGroup->update(_absolute_view_pos.osg(), mViewOrientation.osg());
724   _cameraGroup->setCameraParameters(get_v_fov(), get_aspect_ratio());
725 }