From Frauciel Luc, "Added support for other pointers than mouses by using a nearpoint and farpoint instead of mousex,mousey + Camera (see Dragger and Dragger.cpp).

The major modification concern the LineProjector class in Projector.cpp. The intersection was previously done in window space, I've modified it to compute it in object space."
This commit is contained in:
Robert Osfield
2007-05-28 10:14:29 +00:00
parent e808119b91
commit 49217e8a88
4 changed files with 69 additions and 92 deletions

View File

@@ -27,13 +27,12 @@ namespace osgManipulator {
class OSGMANIPULATOR_EXPORT CommandManager : public osg::Referenced
{
public:
CommandManager();
/**
* Connect a dragger to a selection. The selection will begin listening
* to commands generated by the dragger. This can be called multiple
* times to connect many selections to a dragger.
* to commands generated by the dragger. This can be called multiple
* times to connect many selections to a dragger.
*/
virtual bool connect(Dragger& dragger, Selection& selection);

View File

@@ -36,9 +36,9 @@ class OSGMANIPULATOR_EXPORT PointerInfo
PointerInfo();
PointerInfo(const PointerInfo& rhs):
_pixel_x(rhs._pixel_x),
_pixel_y(rhs._pixel_y),
_camera(rhs._camera),
_nearPoint(rhs._nearPoint),
_farPoint(rhs._farPoint),
_eyeDir(rhs._eyeDir),
_hitList(rhs._hitList)
{
_hitIter = _hitList.begin();
@@ -63,35 +63,43 @@ class OSGMANIPULATOR_EXPORT PointerInfo
typedef std::list< NodePathIntersectionPair> IntersectionList;
osg::Vec2 pointToProject() const { return osg::Vec2(_pixel_x, _pixel_y); }
osg::Vec3 getLocalIntersectPoint() const { return _hitIter->second; }
bool projectWindowXYIntoObject(const osg::Vec2& windowCoord, osg::Vec3& nearPoint, osg::Vec3& farPoint) const;
bool projectWindowXYIntoObject(osg::Vec3& nearPoint, osg::Vec3& farPoint) const
{
return projectWindowXYIntoObject(pointToProject(), nearPoint, farPoint);
void setNearFarPoints (osg::Vec3 nearPoint, osg::Vec3 farPoint) {
_nearPoint = nearPoint;
_farPoint=farPoint;
_eyeDir = farPoint - nearPoint;
}
const osg::Vec3& getEyeDir() const {return _eyeDir;}
void getNearFarPoints( osg::Vec3& nearPoint, osg::Vec3& farPoint) const {
nearPoint = _nearPoint;
farPoint = _farPoint;
}
bool projectObjectIntoWindow(const osg::Vec3& object,osg::Vec3& window) const;
const osg::Matrix& getViewMatrix() const { return _camera->getViewMatrix(); }
bool contains(const osg::Node* node) const;
void setCamera(osg::Camera* camera)
{
_camera = camera;
if (_camera)
if (camera)
{
_MVPW = _camera->getViewMatrix() * _camera->getProjectionMatrix();
if (_camera->getViewport()) _MVPW.postMult(_camera->getViewport()->computeWindowMatrix());
_MVPW = camera->getViewMatrix() * camera->getProjectionMatrix();
if (camera->getViewport()) _MVPW.postMult(camera->getViewport()->computeWindowMatrix());
_inverseMVPW.invert(_MVPW);
osg::Vec3 eye, center, up;
camera->getViewMatrix().getLookAt(eye, center, up);
_eyeDir = eye - center;
}
else
{
_MVPW.makeIdentity();
_inverseMVPW.makeIdentity();
_eyeDir = osg::Vec3(0,0,1);
}
}
@@ -105,17 +113,19 @@ class OSGMANIPULATOR_EXPORT PointerInfo
void setMousePosition(float pixel_x, float pixel_y)
{
_pixel_x = pixel_x;
_pixel_y = pixel_y;
projectWindowXYIntoObject(osg::Vec2(pixel_x, pixel_y), _nearPoint, _farPoint);
}
protected:
bool projectWindowXYIntoObject(const osg::Vec2& windowCoord, osg::Vec3& nearPoint, osg::Vec3& farPoint) const;
public:
float _pixel_x, _pixel_y;
osg::Camera* _camera;
IntersectionList _hitList;
IntersectionList::const_iterator _hitIter;
IntersectionList::iterator _hitIter;
protected:
osg::Vec3 _nearPoint,_farPoint;
osg::Vec3 _eyeDir;
osg::Matrix _MVPW;
osg::Matrix _inverseMVPW;
@@ -139,14 +149,14 @@ class OSGMANIPULATOR_EXPORT Dragger : public Selection
const CommandManager* getCommandManager() const { return _commandManager; }
/**
* Set/Get parent dragger. For simple draggers parent points to itself.
* For composite draggers parent points to the parent dragger that uses
* this dragger.
*/
* Set/Get parent dragger. For simple draggers parent points to itself.
* For composite draggers parent points to the parent dragger that uses
* this dragger.
*/
virtual void setParentDragger(Dragger* parent) { _parentDragger = parent; }
Dragger* getParentDragger() { return _parentDragger; }
const Dragger* getParentDragger() const { return _parentDragger; }
/** Returns 0 if this Dragger is not a CompositeDragger. */
virtual const CompositeDragger* getComposite() const { return 0; }
@@ -163,7 +173,7 @@ class OSGMANIPULATOR_EXPORT Dragger : public Selection
CommandManager* _commandManager;
Dragger* _parentDragger;
Dragger* _parentDragger;
};
@@ -210,12 +220,12 @@ class OSGMANIPULATOR_EXPORT CompositeDragger : public Dragger
* could have a line with an invisible cylinder around it to enable picking on
* that line.
*/
void setDrawableToAlwaysCull(osg::Drawable& drawable);
void OSGMANIPULATOR_EXPORT setDrawableToAlwaysCull(osg::Drawable& drawable);
/**
* Convenience function for setting the material color on a node.
*/
void setMaterialColor(const osg::Vec4& color, osg::Node& node);
void OSGMANIPULATOR_EXPORT setMaterialColor(const osg::Vec4& color, osg::Node& node);
}

View File

@@ -18,9 +18,9 @@
using namespace osgManipulator;
PointerInfo::PointerInfo():
_pixel_x(0.0),
_pixel_y(0.0),
_camera(0)
_nearPoint(osg::Vec3()),
_farPoint(osg::Vec3()),
_eyeDir(osg::Vec3(0,0,1))
{
_hitIter = _hitList.begin();
}
@@ -39,12 +39,6 @@ bool PointerInfo::projectWindowXYIntoObject(const osg::Vec2& windowCoord, osg::V
return true;
}
bool PointerInfo::projectObjectIntoWindow(const osg::Vec3& object,osg::Vec3& window) const
{
window = object * _MVPW;
return true;
}
Dragger::Dragger() : _commandManager(0)
{
_parentDragger = this;

View File

@@ -174,12 +174,8 @@ bool getCylinderLineIntersection(const osg::Cylinder& cylinder,
return true;
}
osg::Vec3 getEyeDirection(const osg::Matrix& viewingMatrix, const osg::Matrix& localToWorld)
osg::Vec3 getLocalEyeDirection(const osg::Vec3& eyeDir, const osg::Matrix& localToWorld)
{
osg::Vec3 eye, center, up;
viewingMatrix.getLookAt(eye, center, up);
osg::Vec3 eyeDir = eye - center;
// To take a normal from world to local you need to transform it by the transpose of the inverse of the
// world to local matrix. Pre-multipling is equivalent to doing a post-multiplication of the transpose.
osg::Vec3 localEyeDir = localToWorld * eyeDir;
@@ -187,10 +183,10 @@ osg::Vec3 getEyeDirection(const osg::Matrix& viewingMatrix, const osg::Matrix& l
return localEyeDir;
}
osg::Plane computePlaneThruPointAndOrientedToEye(const osg::Matrix& viewingMatrix, const osg::Matrix& localToWorld,
osg::Plane computePlaneThruPointAndOrientedToEye(const osg::Vec3& eyeDir, const osg::Matrix& localToWorld,
const osg::Vec3& point, bool front)
{
osg::Vec3 planeNormal = getEyeDirection(viewingMatrix, localToWorld);
osg::Vec3 planeNormal = getLocalEyeDirection(eyeDir, localToWorld);
if (! front) planeNormal = -planeNormal;
osg::Plane plane;
@@ -198,12 +194,12 @@ osg::Plane computePlaneThruPointAndOrientedToEye(const osg::Matrix& viewingMatri
return plane;
}
osg::Plane computePlaneParallelToAxisAndOrientedToEye(const osg::Matrix& viewingMatrix, const osg::Matrix& localToWorld,
osg::Plane computePlaneParallelToAxisAndOrientedToEye(const osg::Vec3& eyeDir, const osg::Matrix& localToWorld,
const osg::Vec3& axisDir, float radius,
osg::Vec3& planeLineStart, osg::Vec3& planeLineEnd,
bool front)
{
osg::Vec3 perpDir = axisDir ^ getEyeDirection(viewingMatrix, localToWorld);
osg::Vec3 perpDir = axisDir ^ getLocalEyeDirection(eyeDir, localToWorld);
osg::Vec3 planeDir = perpDir ^ axisDir;
planeDir.normalize();
if (! front)
@@ -255,38 +251,18 @@ bool LineProjector::project(const PointerInfo& pi, osg::Vec3& projectedPoint) co
osg::ref_ptr<osg::LineSegment> objectLine = new osg::LineSegment;
objectLine->mult(*_line, getLocalToWorld());
// Project the objectLine onto the window.
osg::ref_ptr<osg::LineSegment> windowLine = new osg::LineSegment;
pi.projectObjectIntoWindow(objectLine->start(), windowLine->start());
pi.projectObjectIntoWindow(objectLine->end(), windowLine->end());
// Get the near and far points for the mouse point.
osg::Vec3 nearPoint, farPoint;
pi.getNearFarPoints(nearPoint,farPoint);
osg::ref_ptr<osg::LineSegment> pointerLine = new osg::LineSegment(nearPoint,farPoint);
windowLine->start().z() = windowLine->end().z() = 0.0f;
// Can't project if the line is straight into the screen.
if (!windowLine->valid())
return false;
// Compute projection of the point on the windowLine by computing the dot product.
osg::Vec2 windowLineStart(windowLine->start().x(),windowLine->start().y());
osg::Vec2 windowLineEnd(windowLine->end().x(),windowLine->end().y());
osg::Vec2 windowLineDirection = windowLineEnd - windowLineStart;
windowLineDirection.normalize();
float dotProduct = (windowLineDirection) * (pi.pointToProject() - windowLineStart);
// Get the closest point on the windowLine from (x,y).
osg::Vec2 closestWindowPt = windowLineStart + windowLineDirection * dotProduct;
// Project the closest point back into the scene and into local space.
osg::ref_ptr<osg::LineSegment> projectedLocalLine = new osg::LineSegment;
pi.projectWindowXYIntoObject(closestWindowPt, projectedLocalLine->start(), projectedLocalLine->end());
projectedLocalLine->mult(*projectedLocalLine, getWorldToLocal());
// Find the closest point between _line and projectedLocalLine on _line and that's the result.
osg::Vec3 closestPtLine, closestPtProjWorkingLine;
if (! computeClosestPoints(*_line, *projectedLocalLine, closestPtLine, closestPtProjWorkingLine))
if (! computeClosestPoints(*objectLine, *pointerLine, closestPtLine, closestPtProjWorkingLine))
return false;
projectedPoint = closestPtLine;
osg::Vec3 localClosestPtLine = closestPtLine * getWorldToLocal();
projectedPoint = localClosestPtLine;
return true;
}
@@ -315,7 +291,7 @@ bool PlaneProjector::project(const PointerInfo& pi, osg::Vec3& projectedPoint) c
// Get the near and far points for the mouse point.
osg::Vec3 nearPoint, farPoint;
pi.projectWindowXYIntoObject(nearPoint,farPoint);
pi.getNearFarPoints(nearPoint,farPoint);
// Transform these points into local coordinates.
osg::Vec3 objectNearPoint, objectFarPoint;
@@ -350,7 +326,7 @@ bool SphereProjector::project(const PointerInfo& pi, osg::Vec3& projectedPoint)
// Get the near and far points for the mouse point.
osg::Vec3 nearPoint, farPoint;
pi.projectWindowXYIntoObject(nearPoint,farPoint);
pi.getNearFarPoints(nearPoint,farPoint);
// Transform these points into local coordinates.
osg::Vec3 objectNearPoint, objectFarPoint;
@@ -367,7 +343,7 @@ bool SphereProjector::project(const PointerInfo& pi, osg::Vec3& projectedPoint)
bool SphereProjector::isPointInFront(const PointerInfo& pi, const osg::Matrix& localToWorld) const
{
osg::Vec3 centerToPoint = getSphere()->getCenter() - pi.getLocalIntersectPoint();
if (centerToPoint * getEyeDirection(pi.getViewMatrix(), localToWorld) < 0.0)
if (centerToPoint * getLocalEyeDirection(pi.getEyeDir(), localToWorld) < 0.0)
return false;
return true;
}
@@ -456,12 +432,10 @@ bool SpherePlaneProjector::project(const PointerInfo& pi, osg::Vec3& projectedPo
osg::notify(osg::WARN) << "Warning: Invalid sphere. SpherePlaneProjector::project() failed." << std::endl;
return false;
}
const osg::Vec2 pointToProject = pi.pointToProject();
// Get the near and far points for the mouse point.
osg::Vec3 nearPoint, farPoint;
pi.projectWindowXYIntoObject(nearPoint,farPoint);
pi.getNearFarPoints(nearPoint,farPoint);
// Transform these points into local coordinates.
osg::Vec3 objectNearPoint, objectFarPoint;
@@ -477,7 +451,7 @@ bool SpherePlaneProjector::project(const PointerInfo& pi, osg::Vec3& projectedPo
hitSphere = getSphereLineIntersection(*_sphere, objectNearPoint, objectFarPoint, dontCare, sphereIntersection);
// Compute plane oriented to the eye.
_plane = computePlaneThruPointAndOrientedToEye(pi.getViewMatrix(), getLocalToWorld(), getSphere()->getCenter(), _front);
_plane = computePlaneThruPointAndOrientedToEye(pi.getEyeDir(), getLocalToWorld(), getSphere()->getCenter(), _front);
// Find the intersection on the plane.
osg::Vec3 planeIntersection;
@@ -535,7 +509,7 @@ bool CylinderProjector::project(const PointerInfo& pi, osg::Vec3& projectedPoint
// Get the near and far points for the mouse point.
osg::Vec3 nearPoint, farPoint;
pi.projectWindowXYIntoObject(nearPoint,farPoint);
pi.getNearFarPoints(nearPoint,farPoint);
// Transform these points into local coordinates.
osg::Vec3 objectNearPoint, objectFarPoint;
@@ -554,7 +528,7 @@ bool CylinderProjector::isPointInFront(const PointerInfo& pi, const osg::Matrix&
pi.getLocalIntersectPoint(), closestPointOnAxis);
osg::Vec3 perpPoint = pi.getLocalIntersectPoint() - closestPointOnAxis;
if (perpPoint * getEyeDirection(pi.getViewMatrix(), localToWorld) < 0.0)
if (perpPoint * getLocalEyeDirection(pi.getEyeDir(), localToWorld) < 0.0)
return false;
return true;
}
@@ -582,7 +556,7 @@ bool CylinderPlaneProjector::project(const PointerInfo& pi, osg::Vec3& projected
// Get the near and far points for the mouse point.
osg::Vec3 nearPoint, farPoint;
pi.projectWindowXYIntoObject(nearPoint,farPoint);
pi.getNearFarPoints(nearPoint,farPoint);
// Transform these points into local coordinates.
osg::Vec3 objectNearPoint, objectFarPoint;
@@ -604,9 +578,9 @@ bool CylinderPlaneProjector::project(const PointerInfo& pi, osg::Vec3& projected
}
// Compute plane oriented to the eye.
_plane = computePlaneParallelToAxisAndOrientedToEye(pi.getViewMatrix(), getLocalToWorld(), _cylinderAxis,
_plane = computePlaneParallelToAxisAndOrientedToEye(pi.getEyeDir(), getLocalToWorld(), _cylinderAxis,
getCylinder()->getRadius(), _planeLineStart, _planeLineEnd,
_front);
_front);
// Find the intersection on the plane.
osg::Vec3 planeIntersection;