写在前面的话:笔者新手学习OpenSceneGraph3.4.0(OSG),并且C++的基础较差,OpenGL的基础也较差,都没有系统性科学性地学习过。由于毕业论文需要,所以突击学习,在网上各种论坛和各种博客里找不到太多有价值的参考代码,OSG本身的源码又看不懂。总之,想了很多办法,最近取得一点学习进展,现将osgViewer 碰撞检测知识点代码所学积累都公布出来,供小白使用。如果觉得有点用请留言给我加油,或者建议、改进都可以。谢谢。
#include "../Common/Common.h"
#include "../NodeMatrix/NodeMatrix.h"
#ifdef _DEBUG
#pragma comment(lib, "../Debug/Common.lib")
#pragma comment(lib, "../Debug/NodeMatrix.lib")
#else
#pragma comment(lib, "../Release/Common.lib")
#pragma comment(lib, "../Release/NodeMatrix")
#endif
#define LEFT 1
#define RIGHT 2
#define UP 3
#define DOWN 4
#define FRONT 5
#define BACK 6
class MoveShpereEventHandler : public osgGA::GUIEventHandler
{
public:
MoveShpereEventHandler(NodeMatrix *node)
{
if (!node)
{
//
}
sphere = node;
point = 0;
pop = NULL;
}
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::KEYDOWN:
{
switch (ea.getKey())
{
case osgGA::GUIEventAdapter::KEY_Left:
{
point = LEFT;
position = sphere->getPosition();
ChangePosition(osg::Vec3d(position.x() - 20, position.y(), position.z()), position);
}
break;
case osgGA::GUIEventAdapter::KEY_Right:
{
point = RIGHT;
position = sphere->getPosition();
ChangePosition(osg::Vec3d(position.x() + 20, position.y(), position.z()), position);
}
break;
case osgGA::GUIEventAdapter::KEY_Up:
{
point = FRONT;
position = sphere->getPosition();
ChangePosition(osg::Vec3d(position.x(), position.y() + 20, position.z()), position);
}
break;
case osgGA::GUIEventAdapter::KEY_Down:
{
point = BACK;
position = sphere->getPosition();
ChangePosition(osg::Vec3d(position.x(), position.y() - 20, position.z()), position);
}
break;
case osgGA::GUIEventAdapter::KEY_Home:
{
point = UP;
position = sphere->getPosition();
ChangePosition(osg::Vec3d(position.x(), position.y(), position.z() + 20), position);
}
break;
case osgGA::GUIEventAdapter::KEY_End:
{
point = DOWN;
position = sphere->getPosition();
ChangePosition(osg::Vec3d(position.x(), position.y(), position.z() - 20), position);
}
break;
default:
break;
}// end switch getKey
}
break;
default:
break;
}// end switch getEventType
return false;
}
/*设置碰撞场景*/
void setNode(osg::Node *node)
{
if (!node)
{
//
}
box = node;
}
/*移动*/
void ChangePosition(osg::Vec3d &NewPos, osg::Vec3d &oldPos)
{
osg::ref_ptr<osg::LineSegment> ls = new osg::LineSegment();
osg::ref_ptr<osgUtil::IntersectVisitor> iv = new osgUtil::IntersectVisitor();
int minX, maxX, minY, maxY, minZ, maxZ;
switch (point)
{
case LEFT:
{
ls->set(osg::Vec3d(NewPos.x() - 40, NewPos.y(), NewPos.z()), oldPos);
}
break;
case RIGHT:
{
ls->set(osg::Vec3d(NewPos.x() + 40, NewPos.y(), NewPos.z()), oldPos);
}
break;
case FRONT:
{
ls->set(osg::Vec3d(NewPos.x(), NewPos.y() + 40, NewPos.z()), oldPos);
}
break;
case BACK:
{
ls->set(osg::Vec3d(NewPos.x(), NewPos.y() - 40, NewPos.z()), oldPos);
}
break;
case UP:
{
ls->set(osg::Vec3d(NewPos.x(), NewPos.y(), NewPos.z() + 40), oldPos);
}
break;
case DOWN:
{
ls->set(osg::Vec3d(NewPos.x(), NewPos.y(), NewPos.z() - 40), oldPos);
}
break;
default:
break;
}
iv->addLineSegment(ls.get());
box->accept(*(iv.get()));
if (iv->hits())
{
//看看撞了谁
{
//得到HitList
osgUtil::IntersectVisitor::HitList hitList = iv->getHitList(ls.get());
osg::NodePath nodePath;
osgUtil::IntersectVisitor::HitList::iterator iter = hitList.begin();
osg::Vec3d X;
minX = iter->getWorldIntersectPoint().x();
maxX = minX;
minY = iter->getWorldIntersectPoint().y();
maxY = minY;
minZ = iter->getWorldIntersectPoint().z();
maxZ = minZ;
for (; iter != hitList.end(); iter++)
{
nodePath = iter->getNodePath();
X = iter->getWorldIntersectPoint();
if (minX > X.x())
{
minX = X.x();
}
if (maxX < X.x())
{
maxX = X.x();
}
if (minY > X.y())
{
minY = X.y();
}
if (maxY < X.y())
{
maxY = X.y();
}
if (minZ > X.z())
{
minZ = X.z();
}
if (maxZ < X.z())
{
maxZ = X.z();
}
for (osg::NodePath::iterator iterNode = nodePath.begin(); iterNode != nodePath.end(); iterNode++)
{
std::cout << "撞了:" << (*iterNode)->getName() << std::endl;
if ((*iterNode)->getName() != "ReadBox")
{
if (!pop)
{
pop = (*iterNode);
}
else
{
pop->setNodeMask(1);
}
(*iterNode)->setNodeMask(0);
pop = (*iterNode);
}
}
}
} // END 看看撞了谁
// 移动到目的点
{
switch (point)
{
case LEFT:
{
NewPos.set(maxX + 40, NewPos.y(), NewPos.z());
sphere->toPosition(NewPos);
}
break;
case RIGHT:
{
NewPos.set(minX - 40, NewPos.y(), NewPos.z());
sphere->toPosition(NewPos);
}
break;
case FRONT:
{
NewPos.set(NewPos.x(), minY - 40, NewPos.z());
sphere->toPosition(NewPos);
}
break;
case BACK:
{
NewPos.set(NewPos.x(), maxY + 40, NewPos.z());
sphere->toPosition(NewPos);
}
break;
case UP:
{
NewPos.set(NewPos.x(), NewPos.y(), minZ - 40);
sphere->toPosition(NewPos);
}
break;
case DOWN:
{
NewPos.set(NewPos.x(), NewPos.y(), maxZ + 40);
sphere->toPosition(NewPos);
}
break;
default:
break;
}
}
}
else
{
sphere->toPosition(NewPos);
}
}
private:
/*移动的小球*/
NodeMatrix * sphere;
/*当前位置*/
osg::Vec3d position;
/*碰撞的物体*/
osg::Node * box;
/*记录移动方向*/
int point;
/*POP*/
osg::Node * pop;
};
/*画一个小球*/
osg::ref_ptr<osg::Geode> CreateSphere()
{
osg::ref_ptr<osg::Geode> gnode = new osg::Geode;
osg::ref_ptr<osg::ShapeDrawable> sd = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0, 0, 0), 40));
gnode->addDrawable(sd.get());
return gnode;
}
int main()
{
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
osg::ref_ptr<osg::Group> gp = new osg::Group;
osg::ref_ptr<NodeMatrix> nm = new NodeMatrix;
osg::ref_ptr<osg::Node> node = CreateSphere();
osg::ref_ptr<osg::Node> box = osgDB::readNodeFile("Box.ive");
osg::ref_ptr<MoveShpereEventHandler> eh = new MoveShpereEventHandler(nm.get());
nm->addsChild(node.get());
nm->toPosition(osg::Vec3d(0, 0, 250));
gp->setName("Root Group");
box->setName("ReadBox");
node->setName("Sphere");
nm->setName("NodeMatrixFirst");
gp->addChild(nm.get());
gp->addChild(box.get());
eh->setNode(box.get());
viewer->addEventHandler(eh);
viewer->addEventHandler(new osgViewer::WindowSizeHandler);
viewer->setSceneData(gp);
viewer->run();
return 0;
}
common.h文件代码如下:
#pragma once
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgDB/ReadFile>
#include <osgGA/GUIEventAdapter>
#include <osgGA/GUIActionAdapter>
#include <osgGA/TrackballManipulator>
#include <osgGA/GUIEventHandler>
#include <osg/GraphicsContext>
#include <osg/AnimationPath>
#include <osg/MatrixTransform>
#include <osg/PositionAttitudeTransform>
#include <osg/Matrixd>
#include <osg/Geode>
#include <osg/Shape>
#include <osg/ShapeDrawable>
#include <osg/GraphicsContext>
#include <osg/LineSegment>
#include <osgUtil/IntersectVisitor>
#include <iostream>
class ChangeWindow : public osgGA::GUIEventHandler
{
public:
ChangeWindow(){first = false;}
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if(!first)
{
osgViewer::Viewer * viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
osgViewer::Viewer::Windows ws;
first = true;
viewer->getWindows(ws);
if(!ws.empty())
{
osgViewer::Viewer::Windows::iterator iter = ws.begin();
for(; iter != ws.end(); iter++)
{
(*iter)->setWindowRectangle (300, 100, 800, 600);
(*iter)->setWindowDecoration(false);
}
}
}
return false;
}
private:
bool first ;
};
NodeMatrix.h文件代码如下:
#pragma once
#include "../Common/Common.h"
#ifdef _DEBUG
#pragma comment(lib, "../Debug/Common.lib")
#else
#pragma comment(lib, "../Release/Common.lib")
#endif
#ifdef NODE_MATRIX
#else
#define NODE_MATRIX __declspec(dllimport)
#endif
class NODE_MATRIX NodeMatrix : public osg::MatrixTransform
{
public:
NodeMatrix(void);
~NodeMatrix(void);
public:
/**设置当前模型转动方式*/
void rotating(const osg::Vec3d &pivot, const osg::Vec3d &axis, float angularVelocity);
/**旋转模型*/
void toRotate(const osg::Matrix &mat);
/**旋转模型*/
void toRotate(float angle, const osg::Vec3f &axis);
/**缩放模型*/
void toScale(const osg::Matrix &mat);
/**缩放模型*/
void toScale(double &lel);
/**addsChild方法*/
void addsChild(osg::Node *node);
/**将模型移到目的点*/
void toPosition(osg::Vec3d &pos);
/**得到模型当前的位置*/
osg::Vec3d getPosition();
/**限制模型大小*/
void adapt(osg::BoundingSphere &sps);
/**限制模型大小*/
void adapt(osg::Node *node);
private:
osg::ref_ptr<osg::MatrixTransform> pat;
osg::BoundingSphere ps;
osg::Node * pnode;
float level;
osg::Vec3d position;
};
NodeMatrix.cpp文件如下:
#define NODE_MATRIX __declspec(dllexport)
#include "NodeMatrix.h"
NodeMatrix::NodeMatrix(void)
{
pat = new osg::MatrixTransform;
addChild(pat.get());
level = 1.0;
position = osg::Vec3d(0, 0, 0);
}
NodeMatrix::~NodeMatrix(void)
{
}
/**设置当前模型转动方式*/
void NodeMatrix::rotating(const osg::Vec3d &pivot, const osg::Vec3d &axis, float angularVelocity)
{
setUpdateCallback(new osg::AnimationPathCallback(pivot, axis, angularVelocity));
}
/**旋转模型*/
void NodeMatrix::toRotate(const osg::Matrix &mat)
{
pat->setMatrix(mat);
}
/**旋转模型*/
void NodeMatrix::toRotate(float angle, const osg::Vec3f &axis)
{
pat->setMatrix(osg::Matrix::rotate(angle, axis));
}
/**缩放模型*/
void NodeMatrix::toScale(const osg::Matrix &mat)
{
pat->setMatrix(mat);
}
/**缩放模型*/
void NodeMatrix::toScale(double &lel)
{
pat->setMatrix(osg::Matrix::scale(lel, lel, lel));
}
/**addsChild方法*/
void NodeMatrix::addsChild(osg::Node *node)
{
pat->addChild(node);
pnode = node;
ps = node->getBound();
osg::notify(osg::NOTICE)<<ps.center().x() << " " <<ps.center().y() << " " <<ps.center().z() << std::endl;
}
/**将模型移到目的点*/
void NodeMatrix::toPosition(osg::Vec3d &pos)
{
osg::Vec3d cps;
cps.set(-ps.center().x()*level, -ps.center().y()*level, -ps.center().z()*level);
pat->setMatrix(osg::Matrix::translate(cps)*osg::Matrix::translate(pos));
position = pos;
}
/**限制模型大小*/
void NodeMatrix::adapt(osg::BoundingSphere &sps)
{
float level = sps.radius()/ps.radius();
pat->setMatrix(osg::Matrix::scale(level, level, level));
}
/**限制模型大小*/
void NodeMatrix::adapt(osg::Node * node)
{
osg::BoundingSphere sps = node->getBound();
level = sps.radius()/ps.radius();
pat->setMatrix(osg::Matrix::scale(level, level, level));
}
/**得到当前的位置*/
osg::Vec3d NodeMatrix::getPosition()
{
return position;
}