Fixed the numerical accuracy problems in the Drive and Flight Manipulators.
This commit is contained in:
@@ -24,15 +24,15 @@ public:
|
||||
|
||||
virtual ~DriveManipulator();
|
||||
|
||||
virtual void setNode(osg::Node*);
|
||||
virtual void setNode(osg::Node*);
|
||||
|
||||
virtual const osg::Node* getNode() const;
|
||||
virtual const osg::Node* getNode() const;
|
||||
|
||||
virtual osg::Node* getNode();
|
||||
virtual osg::Node* getNode();
|
||||
|
||||
virtual void home(const GUIEventAdapter& ea,GUIActionAdapter& us);
|
||||
virtual void home(const GUIEventAdapter& ea,GUIActionAdapter& us);
|
||||
|
||||
virtual void init(const GUIEventAdapter& ea,GUIActionAdapter& us);
|
||||
virtual void init(const GUIEventAdapter& ea,GUIActionAdapter& us);
|
||||
|
||||
virtual bool handle(const GUIEventAdapter& ea,GUIActionAdapter& us);
|
||||
|
||||
@@ -44,6 +44,11 @@ private:
|
||||
/** Add the current mouse GUIEvent to internal stack.*/
|
||||
void addMouseEvent(const GUIEventAdapter& ea);
|
||||
|
||||
void computeLocalDataFromCamera();
|
||||
|
||||
void computeCameraFromLocalData();
|
||||
void computeCameraFromLocalData(const osg::Vec3& lv,const osg::Vec3& up);
|
||||
|
||||
/** For the give mouse movement calculate the movement of the camera.
|
||||
Return true is camera has moved and a redraw is required.*/
|
||||
bool calcMovement();
|
||||
@@ -66,6 +71,9 @@ private:
|
||||
|
||||
SpeedControlMode _speedMode;
|
||||
|
||||
osg::Vec3 _eye;
|
||||
osg::Quat _rotation;
|
||||
float _distance;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -50,10 +50,15 @@ private:
|
||||
/** Add the current mouse GUIEvent to internal stack.*/
|
||||
void addMouseEvent(const GUIEventAdapter& ea);
|
||||
|
||||
void computeLocalDataFromCamera();
|
||||
|
||||
void computeCameraFromLocalData();
|
||||
|
||||
/** For the give mouse movement calculate the movement of the camera.
|
||||
Return true is camera has moved and a redraw is required.*/
|
||||
bool calcMovement();
|
||||
|
||||
|
||||
// Internal event stack comprising last three mouse events.
|
||||
osg::ref_ptr<const GUIEventAdapter> _ga_t1;
|
||||
osg::ref_ptr<const GUIEventAdapter> _ga_t0;
|
||||
@@ -64,6 +69,10 @@ private:
|
||||
float _velocity;
|
||||
|
||||
YawControlMode _yawMode;
|
||||
|
||||
osg::Vec3 _eye;
|
||||
osg::Quat _rotation;
|
||||
float _distance;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -46,14 +46,14 @@ class OSGGA_EXPORT TrackballManipulator : public CameraManipulator
|
||||
/** Add the current mouse GUIEvent to internal stack.*/
|
||||
void addMouseEvent(const GUIEventAdapter& ea);
|
||||
|
||||
void computeLocalDataFromCamera();
|
||||
|
||||
void computeCameraFromLocalData();
|
||||
|
||||
/** For the give mouse movement calculate the movement of the camera.
|
||||
Return true is camera has moved and a redraw is required.*/
|
||||
bool calcMovement();
|
||||
|
||||
void computeLocalDataFromCamera();
|
||||
|
||||
void computeCameraFromLocalData();
|
||||
|
||||
void trackball(osg::Vec3& axis,float& angle, float p1x, float p1y, float p2x, float p2y);
|
||||
float tb_project_to_sphere(float r, float x, float y);
|
||||
|
||||
|
||||
@@ -161,6 +161,7 @@ void DriveManipulator::home(const GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
|
||||
flushMouseEventStack();
|
||||
|
||||
computeLocalDataFromCamera();
|
||||
}
|
||||
|
||||
|
||||
@@ -258,6 +259,7 @@ void DriveManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
|
||||
us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2);
|
||||
|
||||
computeLocalDataFromCamera();
|
||||
}
|
||||
|
||||
|
||||
@@ -369,6 +371,59 @@ void DriveManipulator::addMouseEvent(const GUIEventAdapter& ea)
|
||||
_ga_t0 = &ea;
|
||||
}
|
||||
|
||||
void DriveManipulator::computeLocalDataFromCamera()
|
||||
{
|
||||
// maths from gluLookAt/osg::Matrix::makeLookAt
|
||||
osg::Vec3 f(_camera->getCenterPoint()-_camera->getEyePoint());
|
||||
f.normalize();
|
||||
osg::Vec3 s(f^_camera->getUpVector());
|
||||
s.normalize();
|
||||
osg::Vec3 u(s^f);
|
||||
u.normalize();
|
||||
|
||||
osg::Matrix rotation_matrix(s[0], u[0], -f[0], 0.0f,
|
||||
s[1], u[1], -f[1], 0.0f,
|
||||
s[2], u[2], -f[2], 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
_eye = _camera->getEyePoint();
|
||||
_distance = _camera->getLookDistance();
|
||||
_rotation.set(rotation_matrix);
|
||||
_rotation = _rotation.inverse();
|
||||
|
||||
}
|
||||
|
||||
void DriveManipulator::computeCameraFromLocalData()
|
||||
{
|
||||
osg::Matrix new_rotation;
|
||||
new_rotation.makeRotate(_rotation);
|
||||
|
||||
osg::Vec3 up = osg::Vec3(0.0f,1.0f,0.0) * new_rotation;
|
||||
osg::Vec3 center = (osg::Vec3(0.0f,0.0f,-_distance) * new_rotation) + _eye;
|
||||
|
||||
_camera->setLookAt(_eye,center,up);
|
||||
}
|
||||
|
||||
void DriveManipulator::computeCameraFromLocalData(const osg::Vec3& lv,const osg::Vec3& up)
|
||||
{
|
||||
osg::Vec3 f(lv);
|
||||
f.normalize();
|
||||
osg::Vec3 s(f^up);
|
||||
s.normalize();
|
||||
osg::Vec3 u(s^f);
|
||||
u.normalize();
|
||||
|
||||
osg::Matrix rotation_matrix(s[0], u[0], -f[0], 0.0f,
|
||||
s[1], u[1], -f[1], 0.0f,
|
||||
s[2], u[2], -f[2], 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
_rotation.set(rotation_matrix);
|
||||
_rotation = _rotation.inverse();
|
||||
|
||||
computeCameraFromLocalData();
|
||||
}
|
||||
|
||||
|
||||
bool DriveManipulator::calcMovement()
|
||||
{
|
||||
@@ -421,36 +476,29 @@ bool DriveManipulator::calcMovement()
|
||||
}
|
||||
}
|
||||
|
||||
// rotate the camera.
|
||||
osg::Vec3 center = _camera->getEyePoint();
|
||||
osg::Vec3 uv = _camera->getUpVector();
|
||||
osg::Matrix rotation_matrix;
|
||||
rotation_matrix.makeRotate(_rotation);
|
||||
|
||||
osg::Vec3 up = osg::Vec3(0.0f,1.0f,0.0) * rotation_matrix;
|
||||
osg::Vec3 lv = osg::Vec3(0.0f,0.0f,-1.0f) * rotation_matrix;
|
||||
|
||||
// rotate the camera.
|
||||
float mx = (_ga_t0->getXmin()+_ga_t0->getXmax())/2.0f;
|
||||
|
||||
float dx = _ga_t0->getX()-mx;
|
||||
|
||||
float yaw = -inDegrees(dx*0.1f*dt);
|
||||
|
||||
osg::Matrix mat;
|
||||
mat.makeTranslate(-center.x(),-center.y(),-center.z());
|
||||
mat *= Matrix::rotate(yaw,uv.x(),uv.y(),uv.z());
|
||||
mat *= Matrix::translate(center.x(),center.y(),center.z());
|
||||
osg::Quat yaw_rotation;
|
||||
yaw_rotation.makeRotate(yaw,up);
|
||||
|
||||
center = _camera->getEyePoint();
|
||||
uv = _camera->getUpVector();
|
||||
|
||||
_camera->transformLookAt(mat);
|
||||
|
||||
// get the new forward (look) vector.
|
||||
osg::Vec3 sv = _camera->getSideVector();
|
||||
osg::Vec3 lv = _camera->getCenterPoint()-_camera->getEyePoint();
|
||||
float lookDistance = lv.length();
|
||||
lv.normalize();
|
||||
_rotation *= yaw_rotation;
|
||||
rotation_matrix.makeRotate(_rotation);
|
||||
osg::Vec3 sv = osg::Vec3(1.0f,0.0f,0.0f) * rotation_matrix;
|
||||
|
||||
// movement is big enough the move the eye point along the look vector.
|
||||
if (fabsf(_velocity*dt)>1e-8)
|
||||
{
|
||||
osg::Vec3 ep = _camera->getEyePoint();
|
||||
float distanceToMove = _velocity*dt;
|
||||
|
||||
float signedBuffer;
|
||||
@@ -460,7 +508,7 @@ bool DriveManipulator::calcMovement()
|
||||
// check to see if any obstruction in front.
|
||||
osgUtil::IntersectVisitor iv;
|
||||
osg::ref_ptr<osg::LineSegment> segForward = osgNew osg::LineSegment;
|
||||
segForward->set(ep,ep+lv*(signedBuffer+distanceToMove));
|
||||
segForward->set(_eye,_eye+lv*(signedBuffer+distanceToMove));
|
||||
iv.addLineSegment(segForward.get());
|
||||
|
||||
_node->accept(iv);
|
||||
@@ -472,15 +520,15 @@ bool DriveManipulator::calcMovement()
|
||||
{
|
||||
// notify(INFO) << "Hit obstruction"<< std::endl;
|
||||
osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
|
||||
distanceToMove = (ip-ep).length()-_buffer;
|
||||
distanceToMove = (ip-_eye).length()-_buffer;
|
||||
_velocity = 0.0f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// check to see if forward point is correct height above terrain.
|
||||
osg::Vec3 fp = ep+lv*distanceToMove;
|
||||
osg::Vec3 lfp = fp-uv*_height*5;
|
||||
osg::Vec3 fp = _eye+lv*distanceToMove;
|
||||
osg::Vec3 lfp = fp-up*_height*5;
|
||||
|
||||
iv.reset();
|
||||
|
||||
@@ -499,15 +547,13 @@ bool DriveManipulator::calcMovement()
|
||||
osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
|
||||
osg::Vec3 np = hitList.front().getWorldIntersectNormal();
|
||||
|
||||
if (uv*np>0.0f) uv = np;
|
||||
else uv = -np;
|
||||
if (up*np>0.0f) up = np;
|
||||
else up = -np;
|
||||
|
||||
ep = ip+uv*_height;
|
||||
lv = uv^sv;
|
||||
osg::Vec3 lp = ep+lv*lookDistance;
|
||||
_eye = ip+up*_height;
|
||||
lv = up^sv;
|
||||
|
||||
_camera->setLookAt(ep,lp,uv);
|
||||
_camera->ensureOrthogonalUpVector();
|
||||
computeCameraFromLocalData(lv,up);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -538,15 +584,13 @@ bool DriveManipulator::calcMovement()
|
||||
osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
|
||||
osg::Vec3 np = hitList.front().getWorldIntersectNormal();
|
||||
|
||||
if (uv*np>0.0f) uv = np;
|
||||
else uv = -np;
|
||||
if (up*np>0.0f) up = np;
|
||||
else up = -np;
|
||||
|
||||
ep = ip+uv*_height;
|
||||
lv = uv^sv;
|
||||
osg::Vec3 lp = ep+lv*lookDistance;
|
||||
_eye = ip+up*_height;
|
||||
lv = up^sv;
|
||||
|
||||
_camera->setLookAt(ep,lp,uv);
|
||||
_camera->ensureOrthogonalUpVector();
|
||||
computeCameraFromLocalData(lv,up);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -555,13 +599,13 @@ bool DriveManipulator::calcMovement()
|
||||
// no collision with terrain has been found therefore track horizontally.
|
||||
|
||||
lv *= (_velocity*dt);
|
||||
ep += lv;
|
||||
osg::Vec3 lp = _camera->getCenterPoint()+lv;
|
||||
|
||||
_eye += lv;
|
||||
|
||||
_camera->setLookAt(ep,lp,uv);
|
||||
_camera->ensureOrthogonalUpVector();
|
||||
|
||||
}
|
||||
|
||||
computeCameraFromLocalData();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ FlightManipulator::FlightManipulator()
|
||||
_modelScale = 0.01f;
|
||||
_velocity = 0.0f;
|
||||
_yawMode = YAW_AUTOMATICALLY_WHEN_BANKED;
|
||||
|
||||
_distance = 1.0f;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +61,8 @@ void FlightManipulator::home(const GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
|
||||
us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2);
|
||||
|
||||
computeLocalDataFromCamera();
|
||||
|
||||
flushMouseEventStack();
|
||||
|
||||
}
|
||||
@@ -76,6 +80,7 @@ void FlightManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
|
||||
us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2);
|
||||
|
||||
computeLocalDataFromCamera();
|
||||
}
|
||||
|
||||
|
||||
@@ -141,6 +146,16 @@ bool FlightManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
_camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()/1.25f);
|
||||
return true;
|
||||
}
|
||||
else if (ea.getKey()=='q')
|
||||
{
|
||||
_yawMode = YAW_AUTOMATICALLY_WHEN_BANKED;
|
||||
return true;
|
||||
}
|
||||
else if (ea.getKey()=='a')
|
||||
{
|
||||
_yawMode = NO_AUTOMATIC_YAW;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case(GUIEventAdapter::FRAME):
|
||||
@@ -173,6 +188,39 @@ void FlightManipulator::addMouseEvent(const GUIEventAdapter& ea)
|
||||
}
|
||||
|
||||
|
||||
void FlightManipulator::computeLocalDataFromCamera()
|
||||
{
|
||||
// maths from gluLookAt/osg::Matrix::makeLookAt
|
||||
osg::Vec3 f(_camera->getCenterPoint()-_camera->getEyePoint());
|
||||
f.normalize();
|
||||
osg::Vec3 s(f^_camera->getUpVector());
|
||||
s.normalize();
|
||||
osg::Vec3 u(s^f);
|
||||
u.normalize();
|
||||
|
||||
osg::Matrix rotation_matrix(s[0], u[0], -f[0], 0.0f,
|
||||
s[1], u[1], -f[1], 0.0f,
|
||||
s[2], u[2], -f[2], 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
_eye = _camera->getEyePoint();
|
||||
_distance = _camera->getLookDistance();
|
||||
_rotation.set(rotation_matrix);
|
||||
_rotation = _rotation.inverse();
|
||||
|
||||
}
|
||||
|
||||
void FlightManipulator::computeCameraFromLocalData()
|
||||
{
|
||||
osg::Matrix new_rotation;
|
||||
new_rotation.makeRotate(_rotation);
|
||||
|
||||
osg::Vec3 up = osg::Vec3(0.0f,1.0f,0.0) * new_rotation;
|
||||
osg::Vec3 center = (osg::Vec3(0.0f,0.0f,-_distance) * new_rotation) + _eye;
|
||||
|
||||
_camera->setLookAt(_eye,center,up);
|
||||
}
|
||||
|
||||
bool FlightManipulator::calcMovement()
|
||||
{
|
||||
_camera->setFusionDistanceMode(osg::Camera::PROPORTIONAL_TO_SCREEN_DISTANCE);
|
||||
@@ -217,29 +265,45 @@ bool FlightManipulator::calcMovement()
|
||||
float dx = _ga_t0->getX()-mx;
|
||||
float dy = _ga_t0->getY()-my;
|
||||
|
||||
osg::Vec3 center = _camera->getEyePoint();
|
||||
osg::Vec3 sv = _camera->getSideVector();
|
||||
osg::Vec3 lv = _camera->getLookVector();
|
||||
osg::Matrix rotation_matrix;
|
||||
rotation_matrix.makeRotate(_rotation);
|
||||
|
||||
osg::Vec3 up = osg::Vec3(0.0f,1.0f,0.0) * rotation_matrix;
|
||||
osg::Vec3 lv = osg::Vec3(0.0f,0.0f,-1.0f) * rotation_matrix;
|
||||
|
||||
osg::Vec3 sv = lv^up;
|
||||
sv.normalize();
|
||||
|
||||
float pitch = inDegrees(dy*0.15f*dt);
|
||||
float roll = inDegrees(dx*0.1f*dt);
|
||||
|
||||
osg::Matrix mat;
|
||||
mat.makeTranslate(-center);
|
||||
mat *= Matrix::rotate(pitch,sv.x(),sv.y(),sv.z());
|
||||
mat *= Matrix::rotate(roll,lv.x(),lv.y(),lv.z());
|
||||
osg::Quat delta_rotate;
|
||||
|
||||
osg::Quat roll_rotate;
|
||||
osg::Quat pitch_rotate;
|
||||
|
||||
pitch_rotate.makeRotate(pitch,sv.x(),sv.y(),sv.z());
|
||||
roll_rotate.makeRotate(roll,lv.x(),lv.y(),lv.z());
|
||||
|
||||
delta_rotate = pitch_rotate*roll_rotate;
|
||||
|
||||
if (_yawMode==YAW_AUTOMATICALLY_WHEN_BANKED)
|
||||
{
|
||||
float bank = asinf(sv.z());
|
||||
float yaw = inRadians(bank)*dt;
|
||||
mat *= Matrix::rotate(yaw,0.0f,0.0f,1.0f);
|
||||
|
||||
osg::Quat yaw_rotate;
|
||||
yaw_rotate.makeRotate(yaw,0.0f,0.0f,1.0f);
|
||||
|
||||
delta_rotate = delta_rotate*yaw_rotate;
|
||||
}
|
||||
|
||||
lv *= (_velocity*dt);
|
||||
|
||||
mat *= Matrix::translate(center+lv);
|
||||
_eye += lv;
|
||||
_rotation = _rotation*delta_rotate;
|
||||
|
||||
_camera->transformLookAt(mat);
|
||||
computeCameraFromLocalData();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ TrackballManipulator::TrackballManipulator()
|
||||
_modelScale = 0.01f;
|
||||
_minimumZoomScale = 0.05f;
|
||||
_thrown = false;
|
||||
|
||||
_distance = 1.0f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user