OSG3.4.0碰撞检测(下)

本文分享了使用OpenSceneGraph(OSG)进行碰撞检测的实际代码案例。通过键盘控制小球移动,并实现与场景中其它物体的碰撞检测。文章详细介绍了MoveShpereEventHandler类的实现方法,包括如何设置碰撞场景、移动小球以及处理碰撞后的响应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在前面的话:笔者新手学习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;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大观矩阵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值