$search
00001 /* 00002 @mainpage 00003 Desc: GazeboRosTextureProjector plugin that controls texture projection 00004 Author: Jared Duke 00005 Date: 17 Jun 2010 00006 SVN info: $Id$ 00007 @htmlinclude manifest.html 00008 @b GazeboRosTextureProjector plugin that controls texture projection 00009 */ 00010 00011 #include <algorithm> 00012 #include <assert.h> 00013 #include <utility> 00014 #include <sstream> 00015 00016 #include <gazebo_plugins/gazebo_ros_projector.h> 00017 00018 #include <gazebo/OgreAdaptor.hh> 00019 #include <gazebo/OgreVisual.hh> 00020 #include <gazebo/Sensor.hh> 00021 #include <gazebo/Global.hh> 00022 #include <gazebo/XMLConfig.hh> 00023 #include <gazebo/Simulator.hh> 00024 #include <gazebo/gazebo.h> 00025 #include <gazebo/World.hh> 00026 #include <gazebo/GazeboError.hh> 00027 #include <gazebo/ControllerFactory.hh> 00028 #include <gazebo/Vector3.hh> 00029 #include <gazebo/Quatern.hh> 00030 00031 #include "std_msgs/String.h" 00032 #include "std_msgs/Int32.h" 00033 00034 #include <Ogre.h> 00035 #include <OgreMath.h> 00036 #include <OgreSceneNode.h> 00037 #include <OgreFrustum.h> 00038 #include <OgreSceneQuery.h> 00039 00040 using namespace gazebo; 00041 00042 typedef std::map<std::string,Ogre::Pass*> OgrePassMap; 00043 typedef OgrePassMap::iterator OgrePassMapIterator; 00044 00045 GZ_REGISTER_DYNAMIC_CONTROLLER("gazebo_ros_projector", GazeboRosProjector); 00046 00048 // Constructor 00049 GazeboRosProjector::GazeboRosProjector(Entity *parent) 00050 : Controller(parent) 00051 { 00052 this->myParent = dynamic_cast<Model*>(this->parent); 00053 if (this->myParent) 00054 ROS_WARN("Deprecating gazebo_ros_projector directly under Model, it should have a Body as a parent instead"); 00055 else 00056 { 00057 this->myBody = dynamic_cast<Body*>(this->parent); 00058 if (!this->myBody) 00059 gzthrow("GazeboRosProjector controller requires a Body as its parent"); 00060 } 00061 00062 Param::Begin(&this->parameters); 00063 this->robotNamespaceP = new ParamT<std::string>("robotNamespace", "/", 0); 00064 this->textureTopicNameP = new ParamT<std::string>("textureTopicName","", 1); 00065 this->projectorTopicNameP = new ParamT<std::string>("projectorTopicName","", 1); 00066 this->bodyNameP = new ParamT<std::string>("bodyName","", 0); 00067 this->xyzP = new ParamT<Vector3>("xyz", Vector3(0,0,0), 0); 00068 this->rpyP = new ParamT<Quatern>("rpy", Quatern(1,0,0,0), 0); 00069 this->textureNameP = new ParamT<std::string>("textureName","", 0); 00070 this->filterTextureNameP = new ParamT<std::string>("filterTextureName","", 0); 00071 this->nearClipDistP = new ParamT<double>("nearClipDist", .1, 0); 00072 this->farClipDistP = new ParamT<double>("farClipDist", 15, 0); 00073 this->fovP = new ParamT<double>("fov", Ogre::Math::PI*.25, 0); 00074 Param::End(); 00075 00076 this->fov = Ogre::Math::PI*.25; 00077 this->nearClipDist = .25; 00078 this->farClipDist = 15; 00079 00080 this->rosnode_ = NULL; 00081 00082 std::ostringstream pn_stream; 00083 std::ostringstream pfn_stream; 00084 if (this->myParent) 00085 { 00086 pn_stream << this->myParent->GetName() << "_ProjectorNode"; 00087 pfn_stream << this->myParent->GetName() << "_ProjectorFilterNode"; 00088 } 00089 else 00090 { 00091 pn_stream << this->myBody->GetModel()->GetName() << "_ProjectorNode"; 00092 pfn_stream << this->myBody->GetModel()->GetName() << "_ProjectorFilterNode"; 00093 } 00094 this->projectorNodeName = pn_stream.str(); 00095 this->projectorFilterNodeName = pfn_stream.str(); 00096 } 00097 00099 // Destructor 00100 GazeboRosProjector::~GazeboRosProjector() 00101 { 00102 delete this->robotNamespaceP; 00103 delete this->rosnode_; 00104 00105 delete this->textureTopicNameP; 00106 delete this->projectorTopicNameP; 00107 delete this->bodyNameP; 00108 delete this->xyzP; 00109 delete this->rpyP; 00110 delete this->textureNameP; 00111 delete this->filterTextureNameP; 00112 delete this->fovP; 00113 delete this->nearClipDistP; 00114 delete this->farClipDistP; 00115 00116 } 00117 00119 // Load the controller 00120 void GazeboRosProjector::LoadChild(XMLConfigNode *node) 00121 { 00122 this->robotNamespaceP->Load(node); 00123 this->robotNamespace = this->robotNamespaceP->GetValue(); 00124 00125 if (!ros::isInitialized()) 00126 { 00127 int argc = 0; 00128 char** argv = NULL; 00129 ros::init(argc,argv,"gazebo",ros::init_options::NoSigintHandler|ros::init_options::AnonymousName); 00130 } 00131 00132 this->rosnode_ = new ros::NodeHandle(this->robotNamespace); 00133 00134 this->textureTopicNameP->Load(node); 00135 this->projectorTopicNameP->Load(node); 00136 this->bodyNameP->Load(node); 00137 this->xyzP->Load(node); 00138 this->rpyP->Load(node); 00139 this->textureNameP->Load(node); 00140 this->filterTextureNameP->Load(node); 00141 this->fovP->Load(node); 00142 this->nearClipDistP->Load(node); 00143 this->farClipDistP->Load(node); 00144 00145 this->textureTopicName = this->textureTopicNameP->GetValue(); 00146 this->projectorTopicName = this->projectorTopicNameP->GetValue(); 00147 this->bodyName = this->bodyNameP->GetValue(); 00148 this->xyz = this->xyzP->GetValue(); 00149 this->rpy = this->rpyP->GetValue(); 00150 this->textureName = this->textureNameP->GetValue(); 00151 this->filterTextureName = this->filterTextureNameP->GetValue(); 00152 this->fov = this->fovP->GetValue(); 00153 this->nearClipDist = this->nearClipDistP->GetValue(); 00154 this->farClipDist = this->farClipDistP->GetValue(); 00155 00156 // Verify that the body by bodyName exists 00157 if (!this->myBody) 00158 { 00159 this->myBody = dynamic_cast<Body*>(this->myParent->GetBody(this->bodyName)); 00160 if (this->myBody == NULL) 00161 { 00162 ROS_WARN("gazebo_ros_projector plugin error: bodyName: %s does not exist\n",this->bodyName.c_str()); 00163 return; 00164 } 00165 else 00166 ROS_WARN("Deprecation Warning: gazebo_ros_projector should be parented under Body instead of Model in the future, <bodyName> tag will be ignored in the future."); 00167 } 00168 00169 // Custom Callback Queue 00170 ros::SubscribeOptions so = ros::SubscribeOptions::create<std_msgs::Int32>( 00171 this->projectorTopicName,1, 00172 boost::bind( &GazeboRosProjector::ToggleProjector,this,_1), 00173 ros::VoidPtr(), &this->queue_); 00174 this->projectorSubscriber_ = this->rosnode_->subscribe(so); 00175 00176 ros::SubscribeOptions so2 = ros::SubscribeOptions::create<std_msgs::String>( 00177 this->textureTopicName,1, 00178 boost::bind( &GazeboRosProjector::LoadImage,this,_1), 00179 ros::VoidPtr(), &this->queue_); 00180 this->imageSubscriber_ = this->rosnode_->subscribe(so2); 00181 } 00182 00184 // Initialize the controller 00185 void GazeboRosProjector::InitChild() 00186 { 00187 // Custom Callback Queue 00188 this->callback_queue_thread_ = boost::thread( boost::bind( &GazeboRosProjector::QueueThread,this ) ); 00189 00190 // Initialize the projector 00191 if (Simulator::Instance()->GetRenderEngineEnabled()) 00192 { 00193 projector_.init( this->myBody->GetVisualNode()->GetSceneNode(), 00194 this->textureName, this->filterTextureName, 00195 this->nearClipDist, this->farClipDist, this->fov, 00196 this->robotNamespace+"projectorNodeName", 00197 this->robotNamespace+"projectorFilterNodeName"); 00198 00199 // set the projector pose relative to body 00200 projector_.setPose( this->xyz, this->rpy ); 00201 00202 // Add the projector as an Ogre frame listener 00203 getRootP()->addFrameListener( &this->projector_ ); 00204 } 00205 } 00206 00208 // Load a texture into the projector 00209 void GazeboRosProjector::LoadImage(const std_msgs::String::ConstPtr& imageMsg) 00210 { 00211 if (Simulator::Instance()->GetRenderEngineEnabled()) 00212 { 00213 this->lock.lock(); 00214 this->projector_.setTextureName( imageMsg->data ); 00215 this->lock.unlock(); 00216 } 00217 } 00218 00220 // Toggle the activation of the projector 00221 void GazeboRosProjector::ToggleProjector(const std_msgs::Int32::ConstPtr& projectorMsg) 00222 { 00223 if (Simulator::Instance()->GetRenderEngineEnabled()) 00224 { 00225 this->lock.lock(); 00226 this->projector_.setEnabled( projectorMsg->data ? true : false ); 00227 this->lock.unlock(); 00228 } 00229 } 00230 00232 // Update the controller 00233 void GazeboRosProjector::UpdateChild() 00234 { 00235 00236 } 00237 00239 // Finalize the controller 00240 void GazeboRosProjector::FiniChild() 00241 { 00242 // Custom Callback Queue 00243 this->queue_.clear(); 00244 this->queue_.disable(); 00245 this->rosnode_->shutdown(); 00246 this->callback_queue_thread_.join(); 00247 00248 // Ogre cleanup 00249 getRootP()->removeFrameListener( &this->projector_ ); 00250 } 00251 00252 Ogre::Root* GazeboRosProjector::getRootP() 00253 { 00254 return Ogre::Root::getSingletonPtr(); 00255 } 00256 00258 // Custom callback queue thread 00259 void GazeboRosProjector::QueueThread() 00260 { 00261 static const double timeout = 0.01; 00262 00263 while (this->rosnode_->ok()) 00264 { 00265 this->queue_.callAvailable(ros::WallDuration(timeout)); 00266 } 00267 } 00268 00270 GazeboRosProjector::Projector::Projector() 00271 { 00272 this->isEnabled = false; 00273 this->isInit = false; 00274 this->isUsingShaders = false; 00275 00276 this->projectorNode = NULL; 00277 this->projectorFilterNode = NULL; 00278 this->projectorQuery = NULL; 00279 this->projectorFrustum = NULL; 00280 this->projectorFilterFrustum = NULL; 00281 00282 this->projectorNodeName = "ProjectorNode"; 00283 this->projectorFilterNodeName = "projectorFilterNode"; 00284 } 00285 00287 GazeboRosProjector::Projector::~Projector() 00288 { 00289 removeProjectorPassFromMaterials(); 00290 00291 if( this->projectorNode ) 00292 { 00293 this->projectorNode->detachObject( this->projectorFrustum ); 00294 this->parentSceneNode->removeAndDestroyChild(this->projectorNodeName); 00295 this->projectorNode = NULL; 00296 } 00297 if( this->projectorFilterNode ) 00298 { 00299 this->projectorFilterNode->detachObject( this->projectorFilterFrustum ); 00300 this->parentSceneNode->removeAndDestroyChild(this->projectorFilterNodeName); 00301 this->projectorFilterNode = NULL; 00302 } 00303 00304 delete this->projectorFrustum; 00305 delete this->projectorFilterFrustum; 00306 00307 if( this->projectorQuery ) 00308 getSceneMgrP()->destroyQuery( this->projectorQuery ); 00309 } 00310 00311 void GazeboRosProjector::Projector::init( Ogre::SceneNode *sceneNodePtr, 00312 Ogre::String textureName, 00313 Ogre::String filterTextureName, 00314 double nearDist, 00315 double farDist, 00316 double fov, 00317 std::string projectorNodeName, 00318 std::string projectorFilterNodeName) 00319 { 00320 if( this->isInit ) 00321 return; 00322 00323 this->projectorNodeName = projectorNodeName; 00324 this->projectorFilterNodeName = projectorFilterNodeName; 00325 00326 this->projectorFrustum = new Ogre::Frustum(); 00327 this->projectorFilterFrustum = new Ogre::Frustum(); 00328 this->projectorFilterFrustum->setProjectionType(Ogre::PT_ORTHOGRAPHIC); 00329 00330 this->projectorQuery = getSceneMgrP()->createPlaneBoundedVolumeQuery(Ogre::PlaneBoundedVolumeList()); 00331 00332 this->parentSceneNode = sceneNodePtr; 00333 setSceneNode(); 00334 setTextureName( textureName ); 00335 setFilterTextureName( filterTextureName ); 00336 setFrustumClipDistance( nearDist, farDist ); 00337 setFrustumFOV( fov ); 00338 00339 this->isInit = true; 00340 } 00341 00342 00344 bool GazeboRosProjector::Projector::frameStarted(const Ogre::FrameEvent &evt) 00345 { 00346 if( !isInit ) 00347 init( this->projectorNode ); 00348 00349 if( isEnabled && !projectedTextureName.empty() ) 00350 { 00351 addProjectorPassToVisibleMaterials(); 00352 //addProjectorPassToAllMaterials(); 00353 } 00354 else 00355 { 00356 removeProjectorPassFromMaterials(); 00357 } 00358 00359 return true; 00360 } 00361 00363 bool GazeboRosProjector::Projector::frameEnded(const Ogre::FrameEvent &evt) 00364 { 00365 return true; 00366 } 00367 00369 bool GazeboRosProjector::Projector::frameRenderingQueued(const Ogre::FrameEvent &evt) 00370 { 00371 return true; 00372 } 00373 00375 void GazeboRosProjector::Projector::setEnabled(bool enabled) 00376 { 00377 this->isEnabled = enabled; 00378 } 00379 00381 void GazeboRosProjector::Projector::setUsingShaders(bool usingShaders) 00382 { 00383 this->isUsingShaders = usingShaders; 00384 } 00385 00387 void GazeboRosProjector::Projector::setSceneNode() 00388 { 00389 if( this->projectorNode ) 00390 { 00391 this->projectorNode->detachObject( this->projectorFrustum ); 00392 this->parentSceneNode->removeAndDestroyChild(this->projectorNodeName); 00393 this->projectorNode = NULL; 00394 } 00395 if( this->projectorFilterNode ) 00396 { 00397 this->projectorFilterNode->detachObject( this->projectorFilterFrustum ); 00398 this->parentSceneNode->removeAndDestroyChild(this->projectorFilterNodeName); 00399 this->projectorFilterNode = NULL; 00400 } 00401 00402 this->projectorNode = this->parentSceneNode->createChildSceneNode(this->projectorNodeName); 00403 this->projectorFilterNode = this->parentSceneNode->createChildSceneNode(this->projectorFilterNodeName); 00404 00405 if( this->projectorNode ) 00406 { 00407 this->projectorNode->attachObject( this->projectorFrustum ); 00408 } 00409 if( this->projectorFilterNode ) 00410 { 00411 this->projectorFilterNode->attachObject( this->projectorFilterFrustum ); 00412 this->projectorFilterNode->setOrientation( Ogre::Quaternion(Ogre::Degree(90), Ogre::Vector3::UNIT_Y) ); 00413 } 00414 } 00415 00417 void GazeboRosProjector::Projector::setPose( Vector3 xyz, Quatern rpy ) 00418 { 00419 ROS_DEBUG("%f %f %f", xyz.x, xyz.y, xyz.z); 00420 ROS_DEBUG("%f %f %f %f",rpy.u, rpy.x, rpy.y, rpy.z); 00421 00422 this->projectorNode->setPosition(xyz.x, xyz.y, xyz.z); 00423 this->projectorNode->setOrientation(rpy.u, rpy.x, rpy.y, rpy.z); 00424 this->projectorFilterNode->setPosition(xyz.x, xyz.y, xyz.z); 00425 Ogre::Quaternion offset_q = Ogre::Quaternion(Ogre::Degree(90), Ogre::Vector3::UNIT_Y); 00426 this->projectorFilterNode->setOrientation(offset_q+Ogre::Quaternion(rpy.u, rpy.x, rpy.y, rpy.z)); 00427 } 00428 00430 void GazeboRosProjector::Projector::setTextureName( const Ogre::String& textureName ) 00431 { 00432 this->projectedTextureName = textureName; 00433 } 00434 00436 void GazeboRosProjector::Projector::setFilterTextureName( const Ogre::String& textureName ) 00437 { 00438 this->projectedFilterTextureName = textureName; 00439 } 00440 00442 void GazeboRosProjector::Projector::setFrustumClipDistance( double nearDist, double farDist ) 00443 { 00444 this->projectorFrustum->setNearClipDistance( nearDist ); 00445 this->projectorFilterFrustum->setNearClipDistance( nearDist ); 00446 this->projectorFrustum->setFarClipDistance( farDist ); 00447 this->projectorFilterFrustum->setFarClipDistance( farDist ); 00448 } 00449 00451 void GazeboRosProjector::Projector::setFrustumFOV( double fovInRadians ) 00452 { 00453 this->projectorFrustum->setFOVy( Ogre::Radian( fovInRadians ) ); 00454 this->projectorFilterFrustum->setFOVy( Ogre::Radian( fovInRadians ) ); 00455 } 00456 00458 Ogre::SceneManager* GazeboRosProjector::Projector::getSceneMgrP() 00459 { 00460 return OgreAdaptor::Instance()->sceneMgr; 00461 } 00462 00464 void GazeboRosProjector::Projector::addProjectorPassToAllMaterials() 00465 { 00466 using namespace Ogre; 00467 00468 std::list<std::string> allMaterials; 00469 00470 SceneManager::MovableObjectIterator it = getSceneMgrP()->getMovableObjectIterator("Entity"); 00471 00472 while( it.hasMoreElements() ) 00473 { 00474 Ogre::Entity* entity = dynamic_cast<Ogre::Entity*>( it.getNext() ); 00475 if(entity && entity->getName().find("ENTITY") != std::string::npos) 00476 00477 for(unsigned int i = 0; i < entity->getNumSubEntities(); i++) 00478 { 00479 allMaterials.push_back( entity->getSubEntity( i )->getMaterialName() ); 00480 } 00481 } 00482 00483 addProjectorPassToMaterials( allMaterials ); 00484 } 00485 00487 void GazeboRosProjector::Projector::addProjectorPassToVisibleMaterials() 00488 { 00489 using namespace Ogre; 00490 00491 PlaneBoundedVolumeList volumeList; 00492 volumeList.push_back( projectorFrustum->getPlaneBoundedVolume() ); 00493 00494 this->projectorQuery->setVolumes( volumeList ); 00495 SceneQueryResult result = this->projectorQuery->execute(); 00496 00497 std::list<std::string> newVisibleMaterials; 00498 00499 // Find all visible materials 00500 SceneQueryResultMovableList::iterator it; 00501 for(it = result.movables.begin(); it != result.movables.end(); ++it) 00502 { 00503 Ogre::Entity* entity = dynamic_cast<Ogre::Entity*>( *it ); 00504 if(entity && entity->getName().find("ENTITY") != std::string::npos) 00505 { 00506 for(unsigned int i = 0; i < entity->getNumSubEntities(); i++) 00507 { 00508 //addProjectorPassToMaterial( entity->getSubEntity( i )->getMaterialName() ); 00509 newVisibleMaterials.push_back( entity->getSubEntity( i )->getMaterialName() ); 00510 } 00511 } 00512 } 00513 00514 addProjectorPassToMaterials( newVisibleMaterials ); 00515 } 00516 00518 void GazeboRosProjector::Projector::addProjectorPassToMaterials( std::list<std::string>& matList ) 00519 { 00520 matList.remove(""); 00521 matList.unique(); 00522 00523 // Loop through all existing passes, removing those for materials not in the newlist, 00524 // and skipping pass creation for those in the newlist that have already been created 00525 OgrePassMapIterator used = projectorTargets.begin(); 00526 while( used != projectorTargets.end() ) 00527 { 00528 std::list<std::string>::iterator visibleMaterial = std::find(matList.begin(),matList.end(),used->first); 00529 00530 // Remove the pass if it applies to a material not in the new list 00531 if( visibleMaterial == matList.end() ) 00532 { 00533 std::string invisibleMaterial = used->first; 00534 ++used; 00535 removeProjectorPassFromMaterial( invisibleMaterial ); 00536 } 00537 // Otherwise remove it from the list of passes to be added 00538 else 00539 { 00540 matList.remove( used->first ); 00541 ++used; 00542 } 00543 } 00544 00545 // Add pass for new materials 00546 while( !matList.empty() ) 00547 { 00548 addProjectorPassToMaterial( matList.front() ); 00549 matList.erase( matList.begin() ); 00550 } 00551 } 00552 00554 void GazeboRosProjector::Projector::addProjectorPassToMaterial( std::string matName ) 00555 { 00556 if( projectorTargets.find( matName ) != projectorTargets.end() ) 00557 { 00558 ROS_DEBUG("Adding a Material that already exists."); 00559 return; 00560 } 00561 00562 using namespace Ogre; 00563 00564 MaterialPtr mat = (MaterialPtr)MaterialManager::getSingleton().getByName( matName ); 00565 Pass *pass = mat->getTechnique( 0 )->createPass(); 00566 00567 if( isUsingShaders ) 00568 { 00569 Matrix4 viewProj = projectorFrustum->getProjectionMatrix() * projectorFrustum->getViewMatrix(); 00570 pass->setVertexProgram("GazeboWorlds/TexProjectionVP"); 00571 //pass->setFragmentProgram("GazeboWorlds/TexProjectionFP"); 00572 GpuProgramParametersSharedPtr vsParams = pass->getVertexProgramParameters(); 00573 GpuProgramParametersSharedPtr psParams = pass->getFragmentProgramParameters(); 00574 //vsParams->setNamedAutoConstant("worldViewProjMatrix", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); 00575 //vsParams->setNamedAutoConstant("worldMatrix",GpuProgramParameters::ACT_WORLD_MATRIX); 00576 //vsParams->setNamedConstant("texViewProjMatrix", viewProj); 00577 vsParams->setNamedAutoConstant("worldMatrix",GpuProgramParameters::ACT_WORLD_MATRIX); 00578 vsParams->setNamedConstant("texProjMatrix", viewProj); 00579 //psParams->setNamedConstant("projMap", viewProj); 00580 pass->setVertexProgramParameters(vsParams); 00581 //pass->setFragmentProgramParameters(psParams); 00582 } 00583 00584 TextureUnitState *texState = pass->createTextureUnitState( projectedTextureName ); 00585 texState->setProjectiveTexturing(true, projectorFrustum); 00586 texState->setTextureAddressingMode(TextureUnitState::TAM_BORDER); 00587 texState->setTextureFiltering(TFO_ANISOTROPIC); 00588 texState->setTextureBorderColour(ColourValue(0.0, 0.0, 0.0, 0.0)); 00589 texState->setColourOperation(LBO_ALPHA_BLEND); 00590 00591 texState = pass->createTextureUnitState( projectedFilterTextureName ); 00592 texState->setProjectiveTexturing(true, projectorFilterFrustum); 00593 texState->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); 00594 texState->setTextureFiltering(TFO_NONE); 00595 00596 pass->setSceneBlending( SBT_TRANSPARENT_ALPHA ); 00597 pass->setDepthBias( 1 ); 00598 pass->setLightingEnabled( false ); 00599 00600 this->projectorTargets[ matName ] = pass; 00601 } 00602 00604 void GazeboRosProjector::Projector::removeProjectorPassFromMaterials() 00605 { 00606 for( OgrePassMap::const_iterator it = this->projectorTargets.begin(); it != this->projectorTargets.end(); ++it ) 00607 { 00608 it->second->getParent()->removePass( it->second->getIndex() ); 00609 } 00610 this->projectorTargets.clear(); 00611 } 00612 00614 void GazeboRosProjector::Projector::removeProjectorPassFromMaterial(std::string matName) 00615 { 00616 this->projectorTargets[ matName ]->getParent()->removePass( this->projectorTargets[matName]->getIndex() ); 00617 this->projectorTargets.erase( this->projectorTargets.find( matName ) ); 00618 } 00619