Ported intersection code to use new osgUtil::LineSegmentIntersector/IntersectionVisitor.

This commit is contained in:
Robert Osfield
2008-07-05 16:39:28 +00:00
parent e70e3a6d5d
commit 9a9c543ffa
4 changed files with 132 additions and 240 deletions

View File

@@ -76,6 +76,8 @@ class OSGGA_EXPORT DriveManipulator : public MatrixManipulator
virtual ~DriveManipulator();
bool intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection, osg::Vec3d& normal) const;
/** Reset the internal GUIEvent stack.*/
void flushMouseEventStack();

View File

@@ -85,7 +85,7 @@ class OSGGA_EXPORT TerrainManipulator : public MatrixManipulator
virtual ~TerrainManipulator();
bool intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection);
bool intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection) const;
/** Reset the internal GUIEvent stack.*/
void flushMouseEventStack();
@@ -122,7 +122,7 @@ class OSGGA_EXPORT TerrainManipulator : public MatrixManipulator
osg::Vec3d _center;
osg::Quat _rotation;
float _distance;
double _distance;
osg::Vec3d _previousUp;
};

View File

@@ -18,7 +18,7 @@
#include <stdlib.h>
#include <osgGA/DriveManipulator>
#include <osgUtil/IntersectVisitor>
#include <osgUtil/LineSegmentIntersector>
#include <osg/Notify>
using namespace osg;
@@ -31,9 +31,9 @@ using namespace osgGA;
// #define INCREMENTAL_PITCH 1
#define KEYBOARD_PITCH 1
static float getHeightOfDriver()
static double getHeightOfDriver()
{
float height = 1.5f;
double height = 1.5;
if (getenv("OSG_DRIVE_MANIPULATOR_HEIGHT"))
{
height = atof(getenv("OSG_DRIVE_MANIPULATOR_HEIGHT"));
@@ -44,8 +44,8 @@ static float getHeightOfDriver()
DriveManipulator::DriveManipulator()
{
_modelScale = 0.01f;
_velocity = 0.0f;
_modelScale = 1.0;
_velocity = 0.0;
_height = getHeightOfDriver();
_buffer = _height*1.3;
_pitch = 0.0;
@@ -69,9 +69,10 @@ void DriveManipulator::setNode(osg::Node* node)
if (_node.get())
{
const osg::BoundingSphere& boundingSphere=_node->getBound();
_modelScale = boundingSphere._radius;
//_height = sqrtf(_modelScale)*0.03f;
//_buffer = sqrtf(_modelScale)*0.05f;
//_height = sqrtf(_modelScale)*0.03;
//_buffer = sqrtf(_modelScale)*0.05;
_height = getHeightOfDriver();
_buffer = _height*1.3;
@@ -91,6 +92,25 @@ osg::Node* DriveManipulator::getNode()
return _node.get();
}
bool DriveManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection, osg::Vec3d& normal) const
{
osg::ref_ptr<osgUtil::LineSegmentIntersector> lsi = new osgUtil::LineSegmentIntersector(start,end);
osgUtil::IntersectionVisitor iv(lsi.get());
iv.setTraversalMask(_intersectTraversalMask);
_node->accept(iv);
if (lsi->containsIntersections())
{
intersection = lsi->getIntersections().begin()->getWorldIntersectPoint();
normal = lsi->getIntersections().begin()->getWorldIntersectNormal();
return true;
}
return false;
}
void DriveManipulator::computeHomePosition()
{
if(_node.get())
@@ -106,39 +126,22 @@ void DriveManipulator::computeHomePosition()
bp -= getUpVector(cf)* _modelScale;
// check to see if any obstruction in front.
osgUtil::IntersectVisitor iv;
iv.setTraversalMask(_intersectTraversalMask);
bool positionSet = false;
osg::ref_ptr<osg::LineSegment> segDown = new osg::LineSegment;
segDown->set(ep,bp);
iv.addLineSegment(segDown.get());
_node->accept(iv);
if (iv.hits())
osg::Vec3d ip, np;
if (intersect(ep, bp, ip, np))
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get());
if (!hitList.empty())
{
// notify(INFO) << "Hit terrain ok"<< std::endl;
osg::Vec3d ip = hitList.front().getWorldIntersectPoint();
osg::Vec3d np = hitList.front().getWorldIntersectNormal();
osg::Vec3d uv;
if (np * getUpVector(cf)>0.0) uv = np;
else uv = -np;
osg::Vec3d uv;
if (np * getUpVector(cf)>0.0) uv = np;
else uv = -np;
ep = ip;
ep += getUpVector(cf)*_height;
osg::Vec3 lv = uv^osg::Vec3d(1.0,0.0,0.0);
ep = ip;
ep += getUpVector(cf)*_height;
osg::Vec3 lv = uv^osg::Vec3d(1.0,0.0,0.0);
setHomePosition(ep,ep+lv,uv);
setHomePosition(ep,ep+lv,uv);
positionSet = true;
}
positionSet = true;
}
@@ -147,33 +150,20 @@ void DriveManipulator::computeHomePosition()
bp = ep;
bp += getUpVector(cf)*_modelScale;
osg::ref_ptr<osg::LineSegment> segUp = new osg::LineSegment;
segUp->set(ep,bp);
iv.addLineSegment(segUp.get());
_node->accept(iv);
if (iv.hits())
if (intersect(ep, bp, ip, np))
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segUp.get());
if (!hitList.empty())
{
// notify(INFO) << "Hit terrain ok"<< std::endl;
osg::Vec3d ip = hitList.front().getWorldIntersectPoint();
osg::Vec3d np = hitList.front().getWorldIntersectNormal();
osg::Vec3d uv;
if (np*getUpVector(cf)>0.0) uv = np;
else uv = -np;
osg::Vec3d uv;
if (np*getUpVector(cf)>0.0) uv = np;
else uv = -np;
ep = ip;
ep += getUpVector(cf)*_height;
osg::Vec3 lv = uv^osg::Vec3d(1.0,0.0,0.0);
setHomePosition(ep,ep+lv,uv);
ep = ip;
ep += getUpVector(cf)*_height;
osg::Vec3 lv = uv^osg::Vec3d(1.0,0.0,0.0);
setHomePosition(ep,ep+lv,uv);
positionSet = true;
}
positionSet = true;
}
}
@@ -213,7 +203,7 @@ void DriveManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us)
us.requestContinuousUpdate(false);
_velocity = 0.0f;
_velocity = 0.0;
osg::Vec3d ep = _eye;
@@ -225,39 +215,21 @@ void DriveManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us)
osg::Vec3d bp = ep;
bp -= getUpVector(cf)*_modelScale;
// check to see if any obstruction in front.
osgUtil::IntersectVisitor iv;
iv.setTraversalMask(_intersectTraversalMask);
bool positionSet = false;
osg::ref_ptr<osg::LineSegment> segDown = new osg::LineSegment;
segDown->set(ep,bp);
iv.addLineSegment(segDown.get());
_node->accept(iv);
if (iv.hits())
osg::Vec3d ip, np;
if (intersect(ep, bp, ip, np))
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get());
if (!hitList.empty())
{
// notify(INFO) << "Hit terrain ok"<< std::endl;
osg::Vec3d ip = hitList.front().getWorldIntersectPoint();
osg::Vec3d np = hitList.front().getWorldIntersectNormal();
osg::Vec3d uv;
if (np*getUpVector(cf)>0.0) uv = np;
else uv = -np;
osg::Vec3d uv;
if (np*getUpVector(cf)>0.0) uv = np;
else uv = -np;
ep = ip+uv*_height;
osg::Vec3d lv = uv^sv;
ep = ip+uv*_height;
osg::Vec3d lv = uv^sv;
computePosition(ep,ep+lv,uv);
positionSet = true;
}
computePosition(ep,ep+lv,uv);
positionSet = true;
}
if (!positionSet)
@@ -265,33 +237,19 @@ void DriveManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us)
bp = ep;
bp += getUpVector(cf)*_modelScale;
osg::ref_ptr<osg::LineSegment> segUp = new osg::LineSegment;
segUp->set(ep,bp);
iv.addLineSegment(segUp.get());
_node->accept(iv);
if (iv.hits())
if (intersect(ep, bp, ip, np))
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segUp.get());
if (!hitList.empty())
{
// notify(INFO) << "Hit terrain ok"<< std::endl;
osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
osg::Vec3 np = hitList.front().getWorldIntersectNormal();
osg::Vec3 uv;
if (np*getUpVector(cf)>0.0f) uv = np;
else uv = -np;
osg::Vec3d uv;
if (np*getUpVector(cf)>0.0f) uv = np;
else uv = -np;
ep = ip+uv*_height;
osg::Vec3 lv = uv^sv;
ep = ip+uv*_height;
osg::Vec3 lv = uv^sv;
computePosition(ep,ep+lv,uv);
positionSet = true;
}
computePosition(ep,ep+lv,uv);
positionSet = true;
}
}
@@ -472,10 +430,10 @@ void DriveManipulator::computePosition(const osg::Vec3d& eye,const osg::Vec3d& c
osg::Vec3d u(s^f);
u.normalize();
osg::Matrix rotation_matrix(s[0], u[0], -f[0], 0.0,
s[1], u[1], -f[1], 0.0,
s[2], u[2], -f[2], 0.0,
0.0, 0.0, 0.0, 1.0);
osg::Matrixd rotation_matrix(s[0], u[0], -f[0], 0.0,
s[1], u[1], -f[1], 0.0,
s[2], u[2], -f[2], 0.0,
0.0, 0.0, 0.0, 1.0);
_eye = eye;
_rotation = rotation_matrix.getRotate().inverse();
@@ -492,15 +450,17 @@ bool DriveManipulator::calcMovement()
if (dt<0.0f)
{
notify(INFO) << "warning dt = "<<dt<< std::endl;
dt = 0.0f;
dt = 0.0;
}
double accelerationFactor = _height*10.0;
switch(_speedMode)
{
case(USE_MOUSE_Y_FOR_SPEED):
{
double dy = _ga_t0->getYnormalized();
_velocity = _modelScale*0.2f*dy;
_velocity = _height*dy;
break;
}
case(USE_MOUSE_BUTTONS_FOR_SPEED):
@@ -510,7 +470,7 @@ bool DriveManipulator::calcMovement()
{
// pan model.
_velocity += dt*_modelScale*0.01;
_velocity += dt*accelerationFactor;
}
else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||
@@ -523,7 +483,7 @@ bool DriveManipulator::calcMovement()
else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON)
{
_velocity -= dt*_modelScale*0.01;
_velocity -= dt*accelerationFactor;
}
break;
@@ -532,7 +492,7 @@ bool DriveManipulator::calcMovement()
osg::CoordinateFrame cf=getCoordinateFrame(_eye);
osg::Matrix rotation_matrix;
osg::Matrixd rotation_matrix;
rotation_matrix.makeRotate(_rotation);
osg::Vec3d up = osg::Vec3d(0.0,1.0,0.0) * rotation_matrix;
@@ -542,7 +502,7 @@ bool DriveManipulator::calcMovement()
// rotate the camera.
double dx = _ga_t0->getXnormalized();
double yaw = -inDegrees(dx*50.0f*dt);
double yaw = -inDegrees(dx*50.0*dt);
#ifdef KEYBOARD_PITCH
@@ -580,98 +540,51 @@ bool DriveManipulator::calcMovement()
else signedBuffer=-_buffer;
// check to see if any obstruction in front.
osgUtil::IntersectVisitor iv;
iv.setTraversalMask(_intersectTraversalMask);
osg::ref_ptr<osg::LineSegment> segForward = new osg::LineSegment;
segForward->set(_eye,_eye+lv*(signedBuffer+distanceToMove));
iv.addLineSegment(segForward.get());
_node->accept(iv);
if (iv.hits())
osg::Vec3d ip, np;
if (intersect(_eye,_eye+lv*(signedBuffer+distanceToMove), ip, np))
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segForward.get());
if (!hitList.empty())
{
// notify(INFO) << "Hit obstruction"<< std::endl;
osg::Vec3d ip = hitList.front().getWorldIntersectPoint();
distanceToMove = (ip-_eye).length()-_buffer;
_velocity = 0.0;
}
distanceToMove = (ip-_eye).length()-_buffer;
_velocity = 0.0;
}
// check to see if forward point is correct height above terrain.
osg::Vec3d fp = _eye+lv*distanceToMove;
osg::Vec3d lfp = fp-up*_height*5;
osg::Vec3d fp = _eye + lv*distanceToMove;
osg::Vec3d lfp = fp - up*(_height*5.0);
iv.reset();
osg::ref_ptr<osg::LineSegment> segNormal = new osg::LineSegment;
segNormal->set(fp,lfp);
iv.addLineSegment(segNormal.get());
_node->accept(iv);
if (iv.hits())
if (intersect(fp, lfp, ip, np))
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segNormal.get());
if (!hitList.empty())
{
// notify(INFO) << "Hit terrain ok"<< std::endl;
osg::Vec3d ip = hitList.front().getWorldIntersectPoint();
osg::Vec3d np = hitList.front().getWorldIntersectNormal();
if (up*np>0.0) up = np;
else up = -np;
if (up*np>0.0) up = np;
else up = -np;
_eye = ip+up*_height;
_eye = ip+up*_height;
lv = up^sv;
lv = up^sv;
computePosition(_eye,_eye+lv,up);
computePosition(_eye,_eye+lv,up);
return true;
}
return true;
}
// no hit on the terrain found therefore resort to a fall under
// under the influence of gravity.
osg::Vec3d dp = lfp;
dp -= getUpVector(cf)* (2*_modelScale);
dp -= getUpVector(cf)* (2.0*_modelScale);
iv.reset();
osg::ref_ptr<osg::LineSegment> segFall = new osg::LineSegment;
segFall->set(lfp,dp);
iv.addLineSegment(segFall.get());
_node->accept(iv);
if (iv.hits())
if (intersect(lfp, dp, ip, np))
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segFall.get());
if (!hitList.empty())
{
notify(INFO) << "Hit terrain on decent ok"<< std::endl;
osg::Vec3d ip = hitList.front().getWorldIntersectPoint();
osg::Vec3d np = hitList.front().getWorldIntersectNormal();
if (up*np>0.0) up = np;
else up = -np;
if (up*np>0.0) up = np;
else up = -np;
_eye = ip+up*_height;
_eye = ip+up*_height;
lv = up^sv;
lv = up^sv;
computePosition(_eye,_eye+lv,up);
computePosition(_eye,_eye+lv,up);
return true;
}
return true;
}
// no collision with terrain has been found therefore track horizontally.

View File

@@ -73,6 +73,25 @@ osg::Node* TerrainManipulator::getNode()
}
bool TerrainManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection) const
{
osg::ref_ptr<osgUtil::LineSegmentIntersector> lsi = new osgUtil::LineSegmentIntersector(start,end);
osgUtil::IntersectionVisitor iv(lsi.get());
iv.setTraversalMask(_intersectTraversalMask);
_node->accept(iv);
if (lsi->containsIntersections())
{
intersection = lsi->getIntersections().begin()->getWorldIntersectPoint();
return true;
}
return false;
}
void TerrainManipulator::home(const GUIEventAdapter& ,GUIActionAdapter& us)
{
if (getAutoComputeHomePosition()) computeHomePosition();
@@ -219,48 +238,6 @@ void TerrainManipulator::addMouseEvent(const GUIEventAdapter& ea)
_ga_t1 = _ga_t0;
_ga_t0 = &ea;
}
bool TerrainManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection)
{
#if 0
// need to reintersect with the terrain
osgUtil::IntersectVisitor iv;
iv.setTraversalMask(_intersectTraversalMask);
osg::ref_ptr<osg::LineSegment> segLookVector = new osg::LineSegment;
segLookVector->set(start,end);
iv.addLineSegment(segLookVector.get());
_node->accept(iv);
if (iv.hits())
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segLookVector.get());
if (!hitList.empty())
{
intersection = hitList.front().getWorldIntersectPoint();
return true;
}
}
return false;
#else
osg::ref_ptr<osgUtil::LineSegmentIntersector> lsi = new osgUtil::LineSegmentIntersector(start,end);
osgUtil::IntersectionVisitor iv(lsi.get());
iv.setTraversalMask(_intersectTraversalMask);
_node->accept(iv);
if (lsi->containsIntersections())
{
intersection = lsi->getIntersections().begin()->getWorldIntersectPoint();
return true;
}
return false;
#endif
}
void TerrainManipulator::setByMatrix(const osg::Matrixd& matrix)
{
@@ -294,9 +271,9 @@ void TerrainManipulator::setByMatrix(const osg::Matrixd& matrix)
_distance = (eye-ip).length();
osg::Matrix rotation_matrix = osg::Matrixd::translate(0.0,0.0,-_distance)*
matrix*
osg::Matrixd::translate(-_center);
osg::Matrixd rotation_matrix = osg::Matrixd::translate(0.0,0.0,-_distance)*
matrix*
osg::Matrixd::translate(-_center);
_rotation = rotation_matrix.getRotate();
@@ -330,12 +307,12 @@ void TerrainManipulator::setByMatrix(const osg::Matrixd& matrix)
osg::Matrixd TerrainManipulator::getMatrix() const
{
return osg::Matrixd::translate(0.0,0.0,_distance)*osg::Matrixd::rotate(_rotation)*osg::Matrix::translate(_center);
return osg::Matrixd::translate(0.0,0.0,_distance)*osg::Matrixd::rotate(_rotation)*osg::Matrixd::translate(_center);
}
osg::Matrixd TerrainManipulator::getInverseMatrix() const
{
return osg::Matrix::translate(-_center)*osg::Matrixd::rotate(_rotation.inverse())*osg::Matrixd::translate(0.0,0.0,-_distance);
return osg::Matrixd::translate(-_center)*osg::Matrixd::rotate(_rotation.inverse())*osg::Matrixd::translate(0.0,0.0,-_distance);
}
void TerrainManipulator::computePosition(const osg::Vec3d& eye,const osg::Vec3d& center,const osg::Vec3d& up)
@@ -343,7 +320,7 @@ void TerrainManipulator::computePosition(const osg::Vec3d& eye,const osg::Vec3d&
if (!_node) return;
// compute rotation matrix
osg::Vec3 lv(center-eye);
osg::Vec3d lv(center-eye);
_distance = lv.length();
_center = center;
@@ -353,10 +330,10 @@ void TerrainManipulator::computePosition(const osg::Vec3d& eye,const osg::Vec3d&
{
bool hitFound = false;
float distance = lv.length();
float maxDistance = distance+2*(eye-_node->getBound().center()).length();
osg::Vec3 farPosition = eye+lv*(maxDistance/distance);
osg::Vec3 endPoint = center;
double distance = lv.length();
double maxDistance = distance+2*(eye-_node->getBound().center()).length();
osg::Vec3d farPosition = eye+lv*(maxDistance/distance);
osg::Vec3d endPoint = center;
for(int i=0;
!hitFound && i<2;
++i, endPoint = farPosition)
@@ -464,7 +441,7 @@ bool TerrainManipulator::calcMovement()
// pan model.
double scale = -0.3f*_distance;
osg::Matrix rotation_matrix;
osg::Matrixd rotation_matrix;
rotation_matrix.makeRotate(_rotation);
@@ -571,7 +548,7 @@ void TerrainManipulator::clampOrientation()
{
if (_rotationMode==ELEVATION_AZIM)
{
osg::Matrix rotation_matrix;
osg::Matrixd rotation_matrix;
rotation_matrix.makeRotate(_rotation);
osg::Vec3d lookVector = -getUpVector(rotation_matrix);