OSGBullet碰撞检测小程序

    xiaoxiao2021-04-03  45

    对OsgBullet编译后的示例程序Example collision进行修改,将原来的立方体包围盒修改为三角网格,使得可以对模型做更精确的碰撞检测。

    #include <btBulletCollisionCommon.h> #include <osgbCollision/CollisionShapes.h> #include <osgbCollision/Utils.h> #include <osgViewer/Viewer> #include <osgDB/ReadFile> #include <osgDB/FileUtils> #include <osgGA/TrackballManipulator> #include <osgGA/GUIEventHandler> #include <osg/MatrixTransform> #include <osg/Geode> #include <osgwTools/Shapes.h> #include <osgwTools/Version.h> #include <osg/io_utils> #include <iostream> /* \cond */ class MoveManipulator : public osgGA::GUIEventHandler { public: MoveManipulator() : _co( NULL ), _mt( NULL ) {} MoveManipulator( const MoveManipulator& mm, osg::CopyOp copyop ) : _co( mm._co ), _mt( mm._mt ) {} ~MoveManipulator() {} #if( OSGWORKS_OSG_VERSION > 20800 ) META_Object(osgBulletExample,MoveManipulator); #endif virtual bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) { if( ( ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_CTRL ) == 0 ) { return( false ); } else if( ea.getEventType() == osgGA::GUIEventAdapter::PUSH ) { _lastX = ea.getXnormalized(); _lastY = ea.getYnormalized(); return( true ); } else if( ea.getEventType() == osgGA::GUIEventAdapter::DRAG ) { double deltaX = ea.getXnormalized() - _lastX; double deltaY = ea.getYnormalized() - _lastY; _lastX = ea.getXnormalized(); _lastY = ea.getYnormalized(); deltaX *= 6.; deltaY *= 6.; osg::Matrix trans = osgbCollision::asOsgMatrix( _co->getWorldTransform() ); trans = trans * osg::Matrix::translate( deltaX, 0., deltaY ); _mt->setMatrix( trans ); _co->setWorldTransform( osgbCollision::asBtTransform( trans ) ); return( true ); } return( false ); } void setCollisionObject( btCollisionObject* co ) { _co = co; } void setMatrixTransform( osg::MatrixTransform* mt ) { _mt = mt; } protected: btCollisionObject* _co; osg::MatrixTransform* _mt; double _lastX, _lastY; }; /* \endcond */ btCollisionWorld* initCollision() { btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration(); btCollisionDispatcher* dispatcher = new btCollisionDispatcher( collisionConfiguration ); btVector3 worldAabbMin( -10000, -10000, -10000 ); btVector3 worldAabbMax( 10000, 10000, 10000 ); btBroadphaseInterface* inter = new btAxisSweep3( worldAabbMin, worldAabbMax, 1000 ); btCollisionWorld* collisionWorld = new btCollisionWorld( dispatcher, inter, collisionConfiguration ); return( collisionWorld ); } osg::Node* createScene( btCollisionWorld* cw, MoveManipulator* mm, osg::ArgumentParser& arguments ) { osg::ref_ptr< osg::Group > root = new osg::Group; osg::Node* node = osgDB::readNodeFile("cow.osg"); root->addChild(node); btCollisionObject* btBoxObject = new btCollisionObject; btBoxObject->setCollisionShape(osgbCollision::btTriMeshCollisionShapeFromOSG(node)); btBoxObject->setCollisionFlags( btCollisionObject::CF_STATIC_OBJECT ); cw->addCollisionObject( btBoxObject ); // Create a box we can drag around with the mouse osg::Node* glider = osgDB::readNodeFile("glider.osg"); osg::Matrix transMatrix = osg::Matrix::translate( 5., 0., 0. ); osg::MatrixTransform* mt = new osg::MatrixTransform( transMatrix ); mt->addChild(glider); root->addChild( mt ); btBoxObject = new btCollisionObject; btBoxObject->setCollisionShape(osgbCollision::btBoxCollisionShapeFromOSG(glider)); btBoxObject->setCollisionFlags( btCollisionObject::CF_KINEMATIC_OBJECT ); btBoxObject->setWorldTransform( osgbCollision::asBtTransform( transMatrix ) ); cw->addCollisionObject( btBoxObject ); mm->setCollisionObject( btBoxObject ); mm->setMatrixTransform( mt ); return( root.release() ); } void detectCollision( bool& lastColState, btCollisionWorld* cw ) { unsigned int numManifolds = cw->getDispatcher()->getNumManifolds(); if( ( numManifolds == 0 ) && (lastColState == true ) ) { osg::notify( osg::ALWAYS ) << "No collision." << std::endl; lastColState = false; } else { for( unsigned int i = 0; i < numManifolds; i++ ) { btPersistentManifold* contactManifold = cw->getDispatcher()->getManifoldByIndexInternal(i); unsigned int numContacts = contactManifold->getNumContacts(); for( unsigned int j=0; j<numContacts; j++ ) { btManifoldPoint& pt = contactManifold->getContactPoint( j ); if( ( pt.getDistance() <= 0.f ) && ( lastColState == false ) ) { // grab these values for the contact normal arrows: osg::Vec3 pos = osgbCollision::asOsgVec3( pt.getPositionWorldOnA() ); osg::Vec3 normal = osgbCollision::asOsgVec3( pt.m_normalWorldOnB ); float pen = pt.getDistance(); //penetration depth osg::Quat q; q.makeRotate( osg::Vec3( 0, 0, 1 ), normal ); osg::notify( osg::ALWAYS ) << "Collision detected." << std::endl; osg::notify( osg::ALWAYS ) << "\tPosition: " << pos << std::endl; osg::notify( osg::ALWAYS ) << "\tNormal: " << normal << std::endl; osg::notify( osg::ALWAYS ) << "\tPenetration depth: " << pen << std::endl; lastColState = true; } else if( ( pt.getDistance() > 0.f ) && ( lastColState == true ) ) { osg::notify( osg::ALWAYS ) << "No collision." << std::endl; lastColState = false; } } } } } int main( int argc, char * argv[] ) { osgDB::getDataFilePathList().push_back("F:\\sketchup\\jimei\\model\\bulkc06"); btCollisionWorld* collisionWorld = initCollision(); osg::ArgumentParser arguments( &argc, argv ); //自定义漫游器,按住ctrl键可以对模型进行拖动 MoveManipulator* mm = new MoveManipulator; osg::ref_ptr< osg::Node > root = createScene( collisionWorld, mm, arguments ); osgViewer::Viewer viewer; viewer.setUpViewInWindow( 10, 30, 800, 600 ); viewer.setCameraManipulator( new osgGA::TrackballManipulator() ); viewer.addEventHandler( mm ); viewer.setSceneData( root.get() ); bool lastColState = false; while( !viewer.done() ) { //执行检测 collisionWorld->performDiscreteCollisionDetection(); detectCollision( lastColState, collisionWorld ); viewer.frame(); } return( 0 ); }
    转载请注明原文地址: https://ju.6miu.com/read-666039.html

    最新回复(0)