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