Fixed the numerical accuracy problems in the Drive and Flight Manipulators.

This commit is contained in:
Robert Osfield
2002-08-29 20:41:19 +00:00
parent 44beefa9a5
commit fc5f07acaa
6 changed files with 186 additions and 59 deletions

View File

@@ -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;
};
}

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -10,6 +10,8 @@ TrackballManipulator::TrackballManipulator()
_modelScale = 0.01f;
_minimumZoomScale = 0.05f;
_thrown = false;
_distance = 1.0f;
}