/* * Copyright (C) 2012 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include #include #include "gazebo/math/Vector2d.hh" #include "gazebo/msgs/msgs.hh" #include "gazebo/common/Assert.hh" #include "gazebo/common/Event.hh" #include "gazebo/common/Events.hh" #include "gazebo/common/CommonIface.hh" #include "gazebo/common/MeshManager.hh" #include "gazebo/common/Console.hh" #include "gazebo/common/Exception.hh" #include "gazebo/common/Mesh.hh" #include "gazebo/common/Plugin.hh" #include "gazebo/common/Skeleton.hh" #include "gazebo/rendering/COMVisual.hh" #include "gazebo/rendering/Conversions.hh" #include "gazebo/rendering/DynamicLines.hh" #include "gazebo/rendering/InertiaVisual.hh" #include "gazebo/rendering/JointVisual.hh" #include "gazebo/rendering/LinkFrameVisual.hh" #include "gazebo/rendering/Material.hh" #include "gazebo/rendering/MovableText.hh" #include "gazebo/rendering/ogre_gazebo.h" #include "gazebo/rendering/RenderEngine.hh" #include "gazebo/rendering/RenderEvents.hh" #include "gazebo/rendering/RTShaderSystem.hh" #include "gazebo/rendering/Scene.hh" #include "gazebo/rendering/SelectionObj.hh" #include "gazebo/rendering/Visual.hh" #include "gazebo/rendering/VisualPrivate.hh" #include "gazebo/rendering/WireBox.hh" using namespace gazebo; using namespace rendering; // Note: The value of GZ_UINT32_MAX is reserved as a flag. uint32_t VisualPrivate::visualIdCount = GZ_UINT32_MAX - 1; ////////////////////////////////////////////////// Visual::Visual(const std::string &_name, VisualPtr _parent, bool _useRTShader) : dataPtr(new VisualPrivate) { this->Init(_name, _parent, _useRTShader); } ////////////////////////////////////////////////// Visual::Visual(const std::string &_name, ScenePtr _scene, bool _useRTShader) : dataPtr(new VisualPrivate) { this->Init(_name, _scene, _useRTShader); } ////////////////////////////////////////////////// Visual::Visual(VisualPrivate &_dataPtr, const std::string &_name, VisualPtr _parent, bool _useRTShader) : dataPtr(&_dataPtr) { this->Init(_name, _parent, _useRTShader); } ////////////////////////////////////////////////// Visual::Visual(VisualPrivate &_dataPtr, const std::string &_name, ScenePtr _scene, bool _useRTShader) : dataPtr(&_dataPtr) { this->Init(_name, _scene, _useRTShader); } ////////////////////////////////////////////////// void Visual::Init(const std::string &_name, ScenePtr _scene, bool _useRTShader) { this->dataPtr->id = this->dataPtr->visualIdCount--; this->dataPtr->boundingBox = NULL; this->dataPtr->useRTShader = _useRTShader; this->dataPtr->visibilityFlags = GZ_VISIBILITY_ALL; this->dataPtr->sdf.reset(new sdf::Element); sdf::initFile("visual.sdf", this->dataPtr->sdf); this->SetName(_name); this->dataPtr->sceneNode = NULL; this->dataPtr->animState = NULL; this->dataPtr->skeleton = NULL; this->dataPtr->initialized = false; this->dataPtr->lighting = true; this->dataPtr->castShadows = true; this->dataPtr->visible = true; this->dataPtr->layer = -1; this->dataPtr->inheritTransparency = true; std::string uniqueName = this->GetName(); int index = 0; while (_scene->OgreSceneManager()->hasSceneNode(uniqueName)) { uniqueName = this->GetName() + "_" + boost::lexical_cast(index++); } this->dataPtr->scene = _scene; this->SetName(uniqueName); this->dataPtr->sceneNode = this->dataPtr->scene->OgreSceneManager()->getRootSceneNode()-> createChildSceneNode(this->GetName()); this->Init(); } ////////////////////////////////////////////////// void Visual::Init(const std::string &_name, VisualPtr _parent, bool _useRTShader) { this->dataPtr->id = this->dataPtr->visualIdCount--; this->dataPtr->boundingBox = NULL; this->dataPtr->useRTShader = _useRTShader; this->dataPtr->sdf.reset(new sdf::Element); sdf::initFile("visual.sdf", this->dataPtr->sdf); this->SetName(_name); this->dataPtr->sceneNode = NULL; this->dataPtr->animState = NULL; this->dataPtr->initialized = false; this->dataPtr->lighting = true; this->dataPtr->castShadows = true; this->dataPtr->visible = true; this->dataPtr->layer = -1; this->dataPtr->inheritTransparency = true; Ogre::SceneNode *pnode = NULL; if (_parent) pnode = _parent->GetSceneNode(); else { gzerr << "Create a visual, invalid parent!!!\n"; return; } if (!pnode) { gzerr << "Unable to get parent scene node\n"; return; } std::string uniqueName = this->GetName(); int index = 0; while (pnode->getCreator()->hasSceneNode(uniqueName)) uniqueName = this->GetName() + "_" + boost::lexical_cast(index++); this->SetName(uniqueName); this->dataPtr->sceneNode = pnode->createChildSceneNode(this->GetName()); this->dataPtr->parent = _parent; this->dataPtr->scene = this->dataPtr->parent->GetScene(); this->Init(); } ////////////////////////////////////////////////// Visual::~Visual() { if (this->dataPtr->preRenderConnection) event::Events::DisconnectPreRender(this->dataPtr->preRenderConnection); delete this->dataPtr->boundingBox; // delete instance from lines vector /*for (std::list::iterator iter = this->dataPtr->lines.begin(); iter != this->dataPtr->lines.end(); ++iter) delete *iter; */ this->dataPtr->lines.clear(); if (this->dataPtr->sceneNode != NULL) { // seems we never get into this block because Fini() runs first this->DestroyAllAttachedMovableObjects(this->dataPtr->sceneNode); this->dataPtr->sceneNode->removeAndDestroyAllChildren(); this->dataPtr->scene->OgreSceneManager()->destroySceneNode( this->dataPtr->sceneNode->getName()); this->dataPtr->sceneNode = NULL; } this->dataPtr->scene.reset(); this->dataPtr->sdf->Reset(); this->dataPtr->sdf.reset(); this->dataPtr->parent.reset(); this->dataPtr->children.clear(); delete this->dataPtr->typeMsg; delete this->dataPtr; this->dataPtr = 0; } ///////////////////////////////////////////////// void Visual::Fini() { this->dataPtr->plugins.clear(); // Detach from the parent if (this->dataPtr->parent) this->dataPtr->parent->DetachVisual(this->GetName()); if (this->dataPtr->sceneNode) { this->dataPtr->sceneNode->detachAllObjects(); this->dataPtr->scene->OgreSceneManager()->destroySceneNode( this->dataPtr->sceneNode); this->dataPtr->sceneNode = NULL; } if (this->dataPtr->preRenderConnection) { event::Events::DisconnectPreRender(this->dataPtr->preRenderConnection); this->dataPtr->preRenderConnection.reset(); } this->dataPtr->scene.reset(); } ///////////////////////////////////////////////// VisualPtr Visual::Clone(const std::string &_name, VisualPtr _newParent) { VisualPtr result(new Visual(_name, _newParent)); result->Load(this->dataPtr->sdf); result->SetScale(this->dataPtr->scale); result->SetVisibilityFlags(this->dataPtr->visibilityFlags); std::string visName = this->GetName(); for (auto iter: this->dataPtr->children) { // give a unique name by prefixing child visuals with the new clone name std::string childName = iter->GetName(); std::string newName = childName; size_t pos = childName.find(visName); if (pos == 0) newName = _name + childName.substr(pos+visName.size()); iter->Clone(newName, result); } if (_newParent == this->dataPtr->scene->WorldVisual()) result->SetWorldPose(this->GetWorldPose()); result->ShowCollision(false); result->SetInheritTransparency(this->InheritTransparency()); result->SetName(_name); return result; } ///////////////////////////////////////////////// void Visual::DestroyAllAttachedMovableObjects(Ogre::SceneNode *_sceneNode) { if (!_sceneNode) return; // Destroy all the attached objects Ogre::SceneNode::ObjectIterator itObject = _sceneNode->getAttachedObjectIterator(); while (itObject.hasMoreElements()) { Ogre::Entity *ent = static_cast(itObject.getNext()); if (ent->getMovableType() != DynamicLines::GetMovableType()) this->dataPtr->scene->OgreSceneManager()->destroyEntity(ent); else delete ent; } // Recurse to child SceneNodes Ogre::SceneNode::ChildNodeIterator itChild = _sceneNode->getChildIterator(); while (itChild.hasMoreElements()) { Ogre::SceneNode* pChildNode = static_cast(itChild.getNext()); this->DestroyAllAttachedMovableObjects(pChildNode); } } ////////////////////////////////////////////////// void Visual::Init() { this->dataPtr->type = VT_ENTITY; this->dataPtr->transparency = 0.0; this->dataPtr->isStatic = false; this->dataPtr->visible = true; this->dataPtr->ribbonTrail = NULL; this->dataPtr->staticGeom = NULL; this->dataPtr->layer = -1; this->dataPtr->wireframe = false; this->dataPtr->inheritTransparency = true; this->dataPtr->scale = ignition::math::Vector3d::One; this->dataPtr->initialized = true; } ////////////////////////////////////////////////// void Visual::LoadFromMsg(const boost::shared_ptr< msgs::Visual const> &_msg) { this->dataPtr->sdf = msgs::VisualToSDF(*_msg.get()); this->Load(); this->UpdateFromMsg(_msg); } ////////////////////////////////////////////////// void Visual::Load(sdf::ElementPtr _sdf) { this->dataPtr->sdf->Copy(_sdf); this->Load(); } ////////////////////////////////////////////////// void Visual::Load() { std::ostringstream stream; math::Pose pose; Ogre::Vector3 meshSize(1, 1, 1); Ogre::MovableObject *obj = NULL; if (this->dataPtr->parent) this->dataPtr->parent->AttachVisual(shared_from_this()); // Read the desired position and rotation of the mesh pose = this->dataPtr->sdf->Get("pose"); std::string mesh = this->GetMeshName(); std::string subMesh = this->GetSubMeshName(); bool centerSubMesh = this->GetCenterSubMesh(); if (!mesh.empty()) { try { // Create the visual stream << "VISUAL_" << this->dataPtr->sceneNode->getName(); obj = this->AttachMesh(mesh, subMesh, centerSubMesh, stream.str()); } catch(Ogre::Exception &e) { gzerr << "Ogre Error:" << e.getFullDescription() << "\n"; gzerr << "Unable to create a mesh from " << mesh << "\n"; return; } } Ogre::Entity *ent = static_cast(obj); if (ent) { if (ent->hasSkeleton()) this->dataPtr->skeleton = ent->getSkeleton(); for (unsigned int i = 0; i < ent->getNumSubEntities(); i++) { ent->getSubEntity(i)->setCustomParameter(1, Ogre::Vector4( this->dataPtr->sdf->Get("laser_retro"), 0.0, 0.0, 0.0)); } } // Set the pose of the scene node this->SetPose(pose); this->dataPtr->initialRelativePose = pose.Ign(); // Get the size of the mesh if (obj) meshSize = obj->getBoundingBox().getSize(); // Keep transparency to set after setting material double sdfTransparency = -1; if (this->dataPtr->sdf->HasElement("transparency")) { sdfTransparency = this->dataPtr->sdf->Get("transparency"); } if (this->dataPtr->sdf->HasElement("geometry")) { sdf::ElementPtr geomElem = this->dataPtr->sdf->GetElement("geometry"); ignition::math::Vector3d geometrySize; bool hasGeom = true; if (geomElem->HasElement("box")) { geometrySize = geomElem->GetElement("box")->Get("size"); } else if (geomElem->HasElement("sphere")) { double r = geomElem->GetElement("sphere")->Get("radius"); geometrySize.Set(r * 2.0, r * 2.0, r * 2.0); } else if (geomElem->HasElement("cylinder")) { double r = geomElem->GetElement("cylinder")->Get("radius"); double l = geomElem->GetElement("cylinder")->Get("length"); geometrySize.Set(r * 2.0, r * 2.0, l); } else if (geomElem->HasElement("plane")) { math::Vector2d size = geomElem->GetElement("plane")->Get("size"); geometrySize.Set(size.x, size.y, 1); } else if (geomElem->HasElement("mesh")) { geometrySize = geomElem->GetElement("mesh")->Get("scale"); } else { hasGeom = false; } if (hasGeom) { // geom values give the absolute size so compute a scale that will // be mulitiply by the current scale to get to the geom size. ignition::math::Vector3d derivedScale = this->DerivedScale(); ignition::math::Vector3d localScale = geometrySize / (derivedScale / this->dataPtr->scale); this->dataPtr->sceneNode->setScale( Conversions::Convert(math::Vector3(localScale))); this->dataPtr->scale = localScale; this->dataPtr->geomSize = geometrySize; } } // Set the material of the mesh if (this->dataPtr->sdf->HasElement("material")) { sdf::ElementPtr matElem = this->dataPtr->sdf->GetElement("material"); // clone the material sdf to preserve the new values to be set // as updating the material name via SetMaterial can affect the // ambient/diffuse/specular/emissive color sdf elements. sdf::ElementPtr matElemClone = matElem->Clone(); if (matElem->HasElement("script")) { sdf::ElementPtr scriptElem = matElem->GetElement("script"); sdf::ElementPtr uriElem = scriptElem->GetElement("uri"); // Add all the URI paths to the render engine while (uriElem) { std::string matUri = uriElem->Get(); if (!matUri.empty()) RenderEngine::Instance()->AddResourcePath(matUri); uriElem = uriElem->GetNextElement("uri"); } std::string matName = scriptElem->Get("name"); if (!matName.empty()) this->SetMaterial(matName); } if (matElemClone->HasElement("ambient")) this->SetAmbient(matElemClone->Get("ambient")); if (matElemClone->HasElement("diffuse")) this->SetDiffuse(matElemClone->Get("diffuse")); if (matElemClone->HasElement("specular")) this->SetSpecular(matElemClone->Get("specular")); if (matElemClone->HasElement("emissive")) this->SetEmissive(matElemClone->Get("emissive")); if (matElem->HasElement("lighting")) { this->SetLighting(matElem->Get("lighting")); } } if (sdfTransparency > -1) { this->SetTransparency(sdfTransparency); } // Allow the mesh to cast shadows this->SetCastShadows(this->dataPtr->sdf->Get("cast_shadows")); this->LoadPlugins(); this->dataPtr->scene->AddVisual(shared_from_this()); // Set meta information if (this->dataPtr->sdf->HasElement("meta")) { if (this->dataPtr->sdf->GetElement("meta")->HasElement("layer")) { this->dataPtr->layer = this->dataPtr->sdf->GetElement("meta")->Get("layer"); rendering::Events::newLayer(this->dataPtr->layer); } } } ////////////////////////////////////////////////// void Visual::Update() { if (!this->dataPtr->visible) return; std::list::iterator iter; // Update the lines for (iter = this->dataPtr->lines.begin(); iter != this->dataPtr->lines.end(); ++iter) { (*iter)->Update(); } std::list< std::pair >::iterator liter; for (liter = this->dataPtr->lineVertices.begin(); liter != this->dataPtr->lineVertices.end(); ++liter) { liter->first->SetPoint(liter->second, Conversions::ConvertIgn( this->dataPtr->sceneNode->_getDerivedPosition())); liter->first->Update(); } if (this->dataPtr->animState) { this->dataPtr->animState->addTime( (common::Time::GetWallTime() - this->dataPtr->prevAnimTime).Double()); this->dataPtr->prevAnimTime = common::Time::GetWallTime(); if (this->dataPtr->animState->hasEnded()) { this->dataPtr->animState = NULL; this->dataPtr->sceneNode->getCreator()->destroyAnimation( this->GetName() + "_animation"); if (this->dataPtr->onAnimationComplete) this->dataPtr->onAnimationComplete(); // event::Events::DisconnectPreRender(this->preRenderConnection); } } } ////////////////////////////////////////////////// void Visual::SetName(const std::string &_name) { this->dataPtr->name = _name; this->dataPtr->sdf->GetAttribute("name")->Set(_name); } ////////////////////////////////////////////////// std::string Visual::GetName() const { return this->dataPtr->name; } ////////////////////////////////////////////////// void Visual::AttachVisual(VisualPtr _vis) { if (!_vis) gzerr << "Visual is null" << std::endl; else { if (_vis->GetSceneNode()->getParentSceneNode()) { _vis->GetSceneNode()->getParentSceneNode()->removeChild( _vis->GetSceneNode()); } this->dataPtr->sceneNode->addChild(_vis->GetSceneNode()); this->dataPtr->children.push_back(_vis); _vis->dataPtr->parent = shared_from_this(); } } ////////////////////////////////////////////////// void Visual::DetachVisual(VisualPtr _vis) { this->DetachVisual(_vis->GetName()); } ////////////////////////////////////////////////// void Visual::DetachVisual(const std::string &_name) { std::vector::iterator iter; for (iter = this->dataPtr->children.begin(); iter != this->dataPtr->children.end(); ++iter) { if ((*iter)->GetName() == _name) { VisualPtr childVis = (*iter); this->dataPtr->children.erase(iter); if (this->dataPtr->sceneNode) this->dataPtr->sceneNode->removeChild(childVis->GetSceneNode()); break; } } } ////////////////////////////////////////////////// void Visual::AttachObject(Ogre::MovableObject *_obj) { // This code makes plane render before grids. This allows grids to overlay // planes, and then other elements to overlay both planes and grids. // if (this->dataPtr->sdf->HasElement("geometry")) // if (this->dataPtr->sdf->GetElement("geometry")->HasElement("plane")) // _obj->setRenderQueueGroup(Ogre::RENDER_QUEUE_SKIES_EARLY+1); if (!this->HasAttachedObject(_obj->getName())) { // update to use unique materials Ogre::Entity *entity = dynamic_cast(_obj); if (entity) { for (unsigned j = 0; j < entity->getNumSubEntities(); ++j) { Ogre::SubEntity *subEntity = entity->getSubEntity(j); Ogre::MaterialPtr material = subEntity->getMaterial(); if (!material.isNull() && material->getName().find("_MATERIAL_") == std::string::npos) { std::string newMaterialName; newMaterialName = this->dataPtr->sceneNode->getName() + "_MATERIAL_" + material->getName(); material = material->clone(newMaterialName); subEntity->setMaterial(material); } } } this->dataPtr->sceneNode->attachObject(_obj); if (this->dataPtr->useRTShader && this->dataPtr->scene->Initialized() && _obj->getName().find("__COLLISION_VISUAL__") == std::string::npos) { RTShaderSystem::Instance()->UpdateShaders(); } _obj->getUserObjectBindings().setUserAny(Ogre::Any(this->GetName())); } else gzerr << "Visual[" << this->GetName() << "] already has object[" << _obj->getName() << "] attached."; _obj->setVisibilityFlags(GZ_VISIBILITY_ALL); } ////////////////////////////////////////////////// bool Visual::HasAttachedObject(const std::string &_name) { for (unsigned int i = 0; i < this->dataPtr->sceneNode->numAttachedObjects(); ++i) { if (this->dataPtr->sceneNode->getAttachedObject(i)->getName() == _name) return true; } return false; } ////////////////////////////////////////////////// unsigned int Visual::GetAttachedObjectCount() const { return this->dataPtr->sceneNode->numAttachedObjects(); } ////////////////////////////////////////////////// void Visual::DetachObjects() { if (this->dataPtr->sceneNode) this->dataPtr->sceneNode->detachAllObjects(); this->dataPtr->meshName = ""; this->dataPtr->subMeshName = ""; this->dataPtr->myMaterialName = ""; } ////////////////////////////////////////////////// unsigned int Visual::GetChildCount() { return this->dataPtr->children.size(); } ////////////////////////////////////////////////// VisualPtr Visual::GetChild(unsigned int _num) { if (_num < this->dataPtr->children.size()) return this->dataPtr->children[_num]; return VisualPtr(); } ////////////////////////////////////////////////// void Visual::MakeStatic() { /*if (!this->staticGeom) this->staticGeom = this->dataPtr->sceneNode->getCreator()->createStaticGeometry( this->dataPtr->sceneNode->getName() + "_Static"); // Add the scene node to the static geometry this->staticGeom->addSceneNode(this->dataPtr->sceneNode); // Build the static geometry this->staticGeom->build(); // Prevent double rendering this->dataPtr->sceneNode->setVisible(false); this->dataPtr->sceneNode->detachAllObjects(); */ } ////////////////////////////////////////////////// Ogre::MovableObject *Visual::AttachMesh(const std::string &_meshName, const std::string &_subMesh, bool _centerSubmesh, const std::string &_objName) { if (_meshName.empty()) return NULL; this->dataPtr->meshName = _meshName; this->dataPtr->subMeshName = _subMesh; Ogre::MovableObject *obj; std::string objName = _objName; std::string meshName = _meshName; meshName += _subMesh.empty() ? "" : "::" + _subMesh; if (objName.empty()) objName = this->dataPtr->sceneNode->getName() + "_ENTITY_" + meshName; this->InsertMesh(_meshName, _subMesh, _centerSubmesh); if (this->dataPtr->sceneNode->getCreator()->hasEntity(objName)) { obj = (Ogre::MovableObject*) (this->dataPtr->sceneNode->getCreator()->getEntity(objName)); } else { // build tangent vectors if normal mapping in tangent space is specified if (this->GetShaderType() == "normal_map_tangent_space") { Ogre::MeshPtr ogreMesh = Ogre::MeshManager::getSingleton().getByName( _meshName); if (!ogreMesh.isNull()) { try { uint16_t src, dest; if (!ogreMesh->suggestTangentVectorBuildParams( Ogre::VES_TANGENT, src, dest)) { ogreMesh->buildTangentVectors(Ogre::VES_TANGENT, src, dest); } } catch(Ogre::Exception &e) { gzwarn << "Problem generating tangent vectors for " << _meshName << ". Normal map will not work: " << e.what() << std::endl; } } } obj = (Ogre::MovableObject*) (this->dataPtr->sceneNode->getCreator()->createEntity(objName, meshName)); } this->AttachObject(obj); return obj; } ////////////////////////////////////////////////// void Visual::SetScale(const math::Vector3 &_scale) { if (this->dataPtr->scale == _scale.Ign()) return; // update geom size based on scale. this->UpdateGeomSize( this->DerivedScale() / this->dataPtr->scale * _scale.Ign()); this->dataPtr->scale = _scale.Ign(); this->dataPtr->sceneNode->setScale( Conversions::Convert(math::Vector3(this->dataPtr->scale))); // Scale selection object in case we have one attached. Other children were // scaled from UpdateGeomSize for (auto child : this->dataPtr->children) { auto selectionObj = std::dynamic_pointer_cast(child); if (selectionObj) { selectionObj->UpdateSize(); break; } } } ////////////////////////////////////////////////// void Visual::UpdateGeomSize(const ignition::math::Vector3d &_scale) { for (std::vector::iterator iter = this->dataPtr->children.begin(); iter != this->dataPtr->children.end(); ++iter) { (*iter)->UpdateGeomSize(_scale * (*iter)->GetScale().Ign()); } // update the same way as server - see Link::UpdateVisualGeomSDF() if (!this->dataPtr->sdf->HasElement("geometry")) return; sdf::ElementPtr geomElem = this->dataPtr->sdf->GetElement("geometry"); if (geomElem->HasElement("box")) { ignition::math::Vector3d size = geomElem->GetElement("box")->Get("size"); ignition::math::Vector3d geomBoxSize = _scale/this->dataPtr->geomSize*size; geomElem->GetElement("box")->GetElement("size")->Set( geomBoxSize); this->dataPtr->geomSize = geomBoxSize; } else if (geomElem->HasElement("sphere")) { // update radius the same way as collision shapes double radius = geomElem->GetElement("sphere")->Get("radius"); double newRadius = _scale.Max(); double oldRadius = this->dataPtr->geomSize.Max(); double geomRadius = newRadius/oldRadius*radius; geomElem->GetElement("sphere")->GetElement("radius")->Set(geomRadius); this->dataPtr->geomSize = ignition::math::Vector3d( geomRadius*2.0, geomRadius*2.0, geomRadius*2.0); } else if (geomElem->HasElement("cylinder")) { // update radius the same way as collision shapes double radius = geomElem->GetElement("cylinder")->Get("radius"); double newRadius = std::max(_scale.X(), _scale.Y()); double oldRadius = std::max(this->dataPtr->geomSize.X(), this->dataPtr->geomSize.Y()); double length = geomElem->GetElement("cylinder")->Get("length"); double geomRadius = newRadius/oldRadius*radius; double geomLength = _scale.Z()/this->dataPtr->geomSize.Z()*length; geomElem->GetElement("cylinder")->GetElement("radius")->Set( geomRadius); geomElem->GetElement("cylinder")->GetElement("length")->Set( geomLength); this->dataPtr->geomSize = ignition::math::Vector3d(geomRadius*2.0, geomRadius*2.0, geomLength); } else if (geomElem->HasElement("mesh")) { geomElem->GetElement("mesh")->GetElement("scale")->Set(_scale); this->dataPtr->geomSize = _scale; } } ///////////////////////////////////////////////// ignition::math::Vector3d Visual::GetGeometrySize() const { return this->dataPtr->geomSize; } ////////////////////////////////////////////////// math::Vector3 Visual::GetScale() { return this->dataPtr->scale; } ////////////////////////////////////////////////// ignition::math::Vector3d Visual::DerivedScale() const { ignition::math::Vector3d derivedScale = this->dataPtr->scale; VisualPtr worldVis = this->dataPtr->scene->WorldVisual(); VisualPtr vis = this->GetParent(); while (vis && vis != worldVis) { derivedScale = derivedScale * vis->GetScale().Ign(); vis = vis->GetParent(); } return derivedScale; } ////////////////////////////////////////////////// void Visual::SetLighting(bool _lighting) { if (this->dataPtr->lighting == _lighting) return; this->dataPtr->lighting = _lighting; try { for (int i = 0; i < this->dataPtr->sceneNode->numAttachedObjects(); ++i) { Ogre::MovableObject *obj = this->dataPtr->sceneNode->getAttachedObject(i); Ogre::Entity *entity = dynamic_cast(obj); if (entity) { for (unsigned j = 0; j < entity->getNumSubEntities(); ++j) { Ogre::MaterialPtr mat = entity->getSubEntity(j)->getMaterial(); if (!mat.isNull()) { mat->setLightingEnabled(this->dataPtr->lighting); } } } } // Apply lighting to all child scene nodes for (unsigned int i = 0; i < this->dataPtr->sceneNode->numChildren(); ++i) { Ogre::SceneNode *sn = dynamic_cast( this->dataPtr->sceneNode->getChild(i)); for (int j = 0; j < sn->numAttachedObjects(); j++) { Ogre::MovableObject *obj = sn->getAttachedObject(j); Ogre::Entity *entity = dynamic_cast(obj); if (entity) { for (unsigned k = 0; k < entity->getNumSubEntities(); ++k) { Ogre::MaterialPtr mat = entity->getSubEntity(k)->getMaterial(); if (!mat.isNull()) { mat->setLightingEnabled(this->dataPtr->lighting); } } } } } } catch(Ogre::Exception &e) { gzwarn << "Unable to set lighting to Geometry[" << this->dataPtr->sceneNode->getName() << ".\n"; } // Apply lighting to all child visuals for (std::vector::iterator iter = this->dataPtr->children.begin(); iter != this->dataPtr->children.end(); ++iter) { (*iter)->SetLighting(this->dataPtr->lighting); } this->dataPtr->sdf->GetElement("material") ->GetElement("lighting")->Set(this->dataPtr->lighting); } ////////////////////////////////////////////////// bool Visual::GetLighting() const { return this->dataPtr->lighting; } ////////////////////////////////////////////////// void Visual::SetMaterial(const std::string &_materialName, bool _unique, const bool _cascade) { if (_materialName.empty() || _materialName == "__default__") return; common::Color matAmbient; common::Color matDiffuse; common::Color matSpecular; common::Color matEmissive; bool matColor = rendering::Material::GetMaterialAsColor( _materialName, matAmbient, matDiffuse, matSpecular, matEmissive); if (_unique) { // Create a custom material name std::string newMaterialName; newMaterialName = this->dataPtr->sceneNode->getName() + "_MATERIAL_" + _materialName; if (this->GetMaterialName() == newMaterialName && matAmbient == this->GetAmbient() && matDiffuse == this->GetDiffuse() && matSpecular == this->GetSpecular() && matEmissive == this->GetEmissive()) return; this->dataPtr->myMaterialName = newMaterialName; Ogre::MaterialPtr origMaterial; try { this->dataPtr->origMaterialName = _materialName; // Get the original material origMaterial = Ogre::MaterialManager::getSingleton().getByName(_materialName); } catch(Ogre::Exception &e) { gzwarn << "Unable to get Material[" << _materialName << "] for Geometry[" << this->dataPtr->sceneNode->getName() << ". Object will appear white.\n"; return; } if (origMaterial.isNull()) { gzwarn << "Unable to get Material[" << _materialName << "] for Geometry[" << this->dataPtr->sceneNode->getName() << ". Object will appear white\n"; return; } Ogre::MaterialPtr myMaterial; // Clone the material. This will allow us to change the look of each geom // individually. if (Ogre::MaterialManager::getSingleton().resourceExists( this->dataPtr->myMaterialName)) { myMaterial = (Ogre::MaterialPtr)(Ogre::MaterialManager::getSingleton().getByName( this->dataPtr->myMaterialName)); } else { myMaterial = origMaterial->clone(this->dataPtr->myMaterialName); } } else { if ( this->dataPtr->myMaterialName == _materialName) return; this->dataPtr->myMaterialName = _materialName; } try { for (unsigned int i = 0; i < this->dataPtr->sceneNode->numAttachedObjects(); ++i) { Ogre::MovableObject *obj = this->dataPtr->sceneNode->getAttachedObject(i); Ogre::Entity *entity = dynamic_cast(obj); if (entity) entity->setMaterialName(this->dataPtr->myMaterialName); else { Ogre::SimpleRenderable *simpleRenderable = dynamic_cast(obj); if (simpleRenderable) simpleRenderable->setMaterial(this->dataPtr->myMaterialName); } } // Apply material to all child scene nodes for (unsigned int i = 0; i < this->dataPtr->sceneNode->numChildren(); ++i) { Ogre::SceneNode *sn = dynamic_cast( this->dataPtr->sceneNode->getChild(i)); for (int j = 0; j < sn->numAttachedObjects(); ++j) { Ogre::MovableObject *obj = sn->getAttachedObject(j); MovableText *text = dynamic_cast(obj); if (text) { common::Color ambient, diffuse, specular, emissive; bool matFound = rendering::Material::GetMaterialAsColor( this->dataPtr->myMaterialName, ambient, diffuse, specular, emissive); if (matFound) { text->SetColor(ambient); } } else if (dynamic_cast(obj)) ((Ogre::Entity *)obj)->setMaterialName(this->dataPtr->myMaterialName); else { ((Ogre::SimpleRenderable *)obj)->setMaterial( this->dataPtr->myMaterialName); } } } } catch(Ogre::Exception &e) { gzwarn << "Unable to set Material[" << this->dataPtr->myMaterialName << "] to Geometry[" << this->dataPtr->sceneNode->getName() << ". Object will appear white.\n"; } // check if material has color components, if so, set them. if (matColor) { this->SetAmbient(matAmbient, false); this->SetDiffuse(matDiffuse, false); this->SetSpecular(matSpecular, false); this->SetEmissive(matEmissive, false); } // Re-apply the transparency filter for the last known transparency value this->SetTransparencyInnerLoop(this->dataPtr->sceneNode); // Apply material to all child visuals if (_cascade) { for (auto &child : this->dataPtr->children) { child->SetMaterial(_materialName, _unique, _cascade); } } if (this->dataPtr->useRTShader && this->dataPtr->scene->Initialized() && this->dataPtr->lighting && this->GetName().find("__COLLISION_VISUAL__") == std::string::npos) { RTShaderSystem::Instance()->UpdateShaders(); } this->dataPtr->sdf->GetElement("material")->GetElement("script") ->GetElement("name")->Set(_materialName); } ///////////////////////////////////////////////// void Visual::SetMaterialShaderParam(const std::string &_paramName, const std::string &_shaderType, const std::string &_value) { // currently only vertex and fragment shaders are supported if (_shaderType != "vertex" && _shaderType != "fragment") { gzerr << "Shader type: '" << _shaderType << "' is not supported" << std::endl; return; } // set the parameter based name and type defined in material script // and shaders auto setNamedParam = [](Ogre::GpuProgramParametersSharedPtr _params, const std::string &_name, const std::string &_v) { auto paramDef = _params->_findNamedConstantDefinition(_name); if (!paramDef) return; switch (paramDef->constType) { case Ogre::GCT_INT1: { int value = Ogre::StringConverter::parseInt(_v); _params->setNamedConstant(_name, value); break; } case Ogre::GCT_FLOAT1: { Ogre::Real value = Ogre::StringConverter::parseReal(_v); _params->setNamedConstant(_name, value); break; } #if (OGRE_VERSION >= ((1 << 16) | (9 << 8) | 0)) case Ogre::GCT_INT2: case Ogre::GCT_FLOAT2: { Ogre::Vector2 value = Ogre::StringConverter::parseVector2(_v); _params->setNamedConstant(_name, value); break; } #endif case Ogre::GCT_INT3: case Ogre::GCT_FLOAT3: { Ogre::Vector3 value = Ogre::StringConverter::parseVector3(_v); _params->setNamedConstant(_name, value); break; } case Ogre::GCT_INT4: case Ogre::GCT_FLOAT4: { Ogre::Vector4 value = Ogre::StringConverter::parseVector4(_v); _params->setNamedConstant(_name, value); break; } case Ogre::GCT_MATRIX_4X4: { Ogre::Matrix4 value = Ogre::StringConverter::parseMatrix4(_v); _params->setNamedConstant(_name, value); break; } default: break; } }; // loop through material techniques and passes to find the param Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().getByName( this->dataPtr->myMaterialName); if (mat.isNull()) { gzerr << "Failed to find material: '" << this->dataPtr->myMaterialName << std::endl; return; } for (unsigned int i = 0; i < mat->getNumTechniques(); ++i) { Ogre::Technique *technique = mat->getTechnique(i); if (!technique) continue; for (unsigned int j = 0; j < technique->getNumPasses(); ++j) { Ogre::Pass *pass = technique->getPass(j); if (!pass) continue; // check if pass is programmable, ie if they are using shaders if (!pass->isProgrammable()) continue; if (_shaderType == "vertex" && pass->hasVertexProgram()) { setNamedParam(pass->getVertexProgramParameters(), _paramName, _value); } else if (_shaderType == "fragment" && pass->hasFragmentProgram()) { setNamedParam(pass->getFragmentProgramParameters(), _paramName, _value); } else { gzerr << "Failed to retrieve shaders for material: '" << this->dataPtr->myMaterialName << "', technique: '" << technique->getName() << "', pass: '" << pass->getName() << "'" << std::endl; continue; } } } } ///////////////////////////////////////////////// void Visual::SetAmbient(const common::Color &_color, const bool _cascade) { if (!this->dataPtr->lighting) return; if (this->dataPtr->myMaterialName.empty()) { std::string matName = this->GetName() + "_MATERIAL_"; Ogre::MaterialManager::getSingleton().create(matName, "General"); this->SetMaterial(matName); } for (unsigned int i = 0; i < this->dataPtr->sceneNode->numAttachedObjects(); ++i) { Ogre::Entity *entity = NULL; Ogre::MovableObject *obj = this->dataPtr->sceneNode->getAttachedObject(i); entity = dynamic_cast(obj); if (!entity) continue; // For each ogre::entity for (unsigned int j = 0; j < entity->getNumSubEntities(); j++) { Ogre::SubEntity *subEntity = entity->getSubEntity(j); Ogre::MaterialPtr material = subEntity->getMaterial(); unsigned int techniqueCount, passCount; Ogre::Technique *technique; Ogre::Pass *pass; Ogre::ColourValue dc; for (techniqueCount = 0; techniqueCount < material->getNumTechniques(); techniqueCount++) { technique = material->getTechnique(techniqueCount); technique->setLightingEnabled(true); for (passCount = 0; passCount < technique->getNumPasses(); passCount++) { pass = technique->getPass(passCount); pass->setAmbient(Conversions::Convert(_color)); } } } } if (_cascade) { for (auto &child : this->dataPtr->children) { child->SetAmbient(_color, _cascade); } } this->dataPtr->ambient = _color; this->dataPtr->sdf->GetElement("material") ->GetElement("ambient")->Set(_color); } ///////////////////////////////////////////////// void Visual::SetDiffuse(const common::Color &_color, const bool _cascade) { if (!this->dataPtr->lighting) return; if (this->dataPtr->myMaterialName.empty()) { std::string matName = this->GetName() + "_MATERIAL_"; Ogre::MaterialManager::getSingleton().create(matName, "General"); this->SetMaterial(matName); } for (unsigned int i = 0; i < this->dataPtr->sceneNode->numAttachedObjects(); i++) { Ogre::Entity *entity = NULL; Ogre::MovableObject *obj = this->dataPtr->sceneNode->getAttachedObject(i); entity = dynamic_cast(obj); if (!entity) { continue; } // For each ogre::entity for (unsigned int j = 0; j < entity->getNumSubEntities(); j++) { Ogre::SubEntity *subEntity = entity->getSubEntity(j); Ogre::MaterialPtr material = subEntity->getMaterial(); unsigned int techniqueCount, passCount; Ogre::Technique *technique; Ogre::Pass *pass; Ogre::ColourValue dc; for (techniqueCount = 0; techniqueCount < material->getNumTechniques(); techniqueCount++) { technique = material->getTechnique(techniqueCount); technique->setLightingEnabled(true); for (passCount = 0; passCount < technique->getNumPasses(); passCount++) { pass = technique->getPass(passCount); dc = Conversions::Convert(_color); pass->setDiffuse(dc); this->dataPtr->transparency = 1.0f - dc.a; } } } } if (_cascade) { for (auto &child : this->dataPtr->children) { child->SetDiffuse(_color, _cascade); } } this->dataPtr->diffuse = _color; this->UpdateTransparency(); this->dataPtr->sdf->GetElement("material") ->GetElement("diffuse")->Set(_color); } ///////////////////////////////////////////////// void Visual::SetSpecular(const common::Color &_color, const bool _cascade) { if (!this->dataPtr->lighting) return; if (this->dataPtr->myMaterialName.empty()) { std::string matName = this->GetName() + "_MATERIAL_"; Ogre::MaterialManager::getSingleton().create(matName, "General"); this->SetMaterial(matName); } for (unsigned int i = 0; i < this->dataPtr->sceneNode->numAttachedObjects(); i++) { Ogre::Entity *entity = NULL; Ogre::MovableObject *obj = this->dataPtr->sceneNode->getAttachedObject(i); entity = dynamic_cast(obj); if (!entity) continue; // For each ogre::entity for (unsigned int j = 0; j < entity->getNumSubEntities(); j++) { Ogre::SubEntity *subEntity = entity->getSubEntity(j); Ogre::MaterialPtr material = subEntity->getMaterial(); unsigned int techniqueCount, passCount; Ogre::Technique *technique; Ogre::Pass *pass; Ogre::ColourValue dc; for (techniqueCount = 0; techniqueCount < material->getNumTechniques(); techniqueCount++) { technique = material->getTechnique(techniqueCount); technique->setLightingEnabled(true); for (passCount = 0; passCount < technique->getNumPasses(); passCount++) { pass = technique->getPass(passCount); pass->setSpecular(Conversions::Convert(_color)); } } } } if (_cascade) { for (auto &child : this->dataPtr->children) { child->SetSpecular(_color, _cascade); } } this->dataPtr->specular = _color; this->dataPtr->sdf->GetElement("material") ->GetElement("specular")->Set(_color); } ////////////////////////////////////////////////// void Visual::SetEmissive(const common::Color &_color, const bool _cascade) { for (unsigned int i = 0; i < this->dataPtr->sceneNode->numAttachedObjects(); i++) { Ogre::Entity *entity = NULL; Ogre::MovableObject *obj = this->dataPtr->sceneNode->getAttachedObject(i); entity = dynamic_cast(obj); if (!entity) continue; // For each ogre::entity for (unsigned int j = 0; j < entity->getNumSubEntities(); j++) { Ogre::SubEntity *subEntity = entity->getSubEntity(j); Ogre::MaterialPtr material = subEntity->getMaterial(); unsigned int techniqueCount, passCount; Ogre::Technique *technique; Ogre::Pass *pass; Ogre::ColourValue dc; for (techniqueCount = 0; techniqueCount < material->getNumTechniques(); techniqueCount++) { technique = material->getTechnique(techniqueCount); for (passCount = 0; passCount < technique->getNumPasses(); passCount++) { pass = technique->getPass(passCount); pass->setSelfIllumination(Conversions::Convert(_color)); } } } } if (_cascade) { for (auto &child : this->dataPtr->children) { child->SetEmissive(_color, _cascade); } } this->dataPtr->emissive = _color; this->dataPtr->sdf->GetElement("material") ->GetElement("emissive")->Set(_color); } ///////////////////////////////////////////////// common::Color Visual::GetAmbient() const { return this->dataPtr->ambient; } ///////////////////////////////////////////////// common::Color Visual::GetDiffuse() const { return this->dataPtr->diffuse; } ///////////////////////////////////////////////// common::Color Visual::GetSpecular() const { return this->dataPtr->specular; } ///////////////////////////////////////////////// common::Color Visual::GetEmissive() const { return this->dataPtr->emissive; } ////////////////////////////////////////////////// void Visual::SetWireframe(bool _show) { if (this->dataPtr->type == VT_GUI || this->dataPtr->type == VT_PHYSICS || this->dataPtr->type == VT_SENSOR) return; for (auto &iter : this->dataPtr->children) { iter->SetWireframe(_show); } if (this->dataPtr->wireframe == _show) return; this->dataPtr->wireframe = _show; for (unsigned int i = 0; i < this->dataPtr->sceneNode->numAttachedObjects(); i++) { Ogre::Entity *entity = NULL; Ogre::MovableObject *obj = this->dataPtr->sceneNode->getAttachedObject(i); entity = dynamic_cast(obj); if (!entity) continue; // For each ogre::entity for (unsigned int j = 0; j < entity->getNumSubEntities(); j++) { Ogre::SubEntity *subEntity = entity->getSubEntity(j); Ogre::MaterialPtr material = subEntity->getMaterial(); if (material.isNull()) continue; unsigned int techniqueCount, passCount; Ogre::Technique *technique; Ogre::Pass *pass; for (techniqueCount = 0; techniqueCount < material->getNumTechniques(); ++techniqueCount) { technique = material->getTechnique(techniqueCount); for (passCount = 0; passCount < technique->getNumPasses(); passCount++) { pass = technique->getPass(passCount); if (_show) pass->setPolygonMode(Ogre::PM_WIREFRAME); else pass->setPolygonMode(Ogre::PM_SOLID); } } } } } ////////////////////////////////////////////////// bool Visual::Wireframe() const { return this->dataPtr->wireframe; } ////////////////////////////////////////////////// void Visual::SetTransparencyInnerLoop(Ogre::SceneNode *_sceneNode) { float derivedTransparency = this->dataPtr->inheritTransparency ? this->DerivedTransparency() : this->dataPtr->transparency; for (unsigned int i = 0; i < _sceneNode->numAttachedObjects(); ++i) { Ogre::Entity *entity = NULL; Ogre::MovableObject *obj = _sceneNode->getAttachedObject(i); entity = dynamic_cast(obj); if (!entity) continue; // we may not need to check for this string anymore now that each visual // has a type if (entity->getName().find("__COLLISION_VISUAL__") != std::string::npos) continue; // For each ogre::entity for (unsigned int j = 0; j < entity->getNumSubEntities(); ++j) { Ogre::SubEntity *subEntity = entity->getSubEntity(j); Ogre::MaterialPtr material = subEntity->getMaterial(); unsigned int techniqueCount, passCount, unitStateCount; Ogre::Technique *technique; Ogre::Pass *pass; Ogre::ColourValue dc; for (techniqueCount = 0; techniqueCount < material->getNumTechniques(); ++techniqueCount) { technique = material->getTechnique(techniqueCount); for (passCount = 0; passCount < technique->getNumPasses(); ++passCount) { pass = technique->getPass(passCount); // Need to fix transparency if (!pass->isProgrammable() && pass->getPolygonMode() == Ogre::PM_SOLID) { pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); } if (derivedTransparency > 0.0) { pass->setDepthWriteEnabled(false); pass->setDepthCheckEnabled(true); } else { pass->setDepthWriteEnabled(true); pass->setDepthCheckEnabled(true); } dc = pass->getDiffuse(); dc.a = (1.0f - derivedTransparency); pass->setDiffuse(dc); this->dataPtr->diffuse = Conversions::Convert(dc); for (unitStateCount = 0; unitStateCount < pass->getNumTextureUnitStates(); ++unitStateCount) { auto textureUnitState = pass->getTextureUnitState(unitStateCount); if (textureUnitState->getColourBlendMode().operation == Ogre::LBX_SOURCE1) { textureUnitState->setAlphaOperation( Ogre::LBX_SOURCE1, Ogre::LBS_MANUAL, Ogre::LBS_CURRENT, 1.0 - derivedTransparency); } } } } } } } ////////////////////////////////////////////////// void Visual::UpdateTransparency(const bool _cascade) { this->SetTransparencyInnerLoop(this->dataPtr->sceneNode); if (_cascade) { for (auto &child : this->dataPtr->children) { // Don't change some visualizations when link changes if (!(this->GetType() == VT_LINK && (child->GetType() == VT_GUI || child->GetType() == VT_PHYSICS || child->GetType() == VT_SENSOR))) { child->UpdateTransparency(_cascade); } } } if (this->dataPtr->useRTShader && this->dataPtr->scene->Initialized()) RTShaderSystem::Instance()->UpdateShaders(); this->dataPtr->sdf->GetElement("transparency")->Set( this->dataPtr->transparency); } ////////////////////////////////////////////////// void Visual::SetTransparency(float _trans) { if (math::equal(this->dataPtr->transparency, _trans)) return; this->dataPtr->transparency = std::min( std::max(_trans, static_cast(0.0)), static_cast(1.0)); this->UpdateTransparency(true); } ////////////////////////////////////////////////// void Visual::SetInheritTransparency(const bool _inherit) { this->dataPtr->inheritTransparency = _inherit; } ////////////////////////////////////////////////// bool Visual::InheritTransparency() const { return this->dataPtr->inheritTransparency; } ////////////////////////////////////////////////// void Visual::SetHighlighted(bool _highlighted) { if (_highlighted) { math::Box bbox = this->GetBoundingBox(); // Create the bounding box if it's not already created. if (!this->dataPtr->boundingBox) { this->dataPtr->boundingBox = new WireBox(shared_from_this(), bbox); } else { this->dataPtr->boundingBox->Init(bbox); } this->dataPtr->boundingBox->SetVisible(true); } else if (this->dataPtr->boundingBox) { this->dataPtr->boundingBox->SetVisible(false); } // If this is a link, highlight frame visual if (this->GetType() == VT_LINK) { for (auto child : this->dataPtr->children) { if (child->GetName().find("LINK_FRAME_VISUAL__") != std::string::npos) child->SetHighlighted(_highlighted); } } } ////////////////////////////////////////////////// bool Visual::GetHighlighted() const { if (this->dataPtr->boundingBox) { return this->dataPtr->boundingBox->GetVisible(); } return false; } ////////////////////////////////////////////////// float Visual::GetTransparency() { return this->dataPtr->transparency; } ////////////////////////////////////////////////// float Visual::DerivedTransparency() const { if (!this->InheritTransparency()) return this->dataPtr->transparency; float derivedTransparency = this->dataPtr->transparency; VisualPtr worldVis = this->dataPtr->scene->WorldVisual(); VisualPtr vis = this->GetParent(); while (vis && vis != worldVis) { derivedTransparency = 1 - ((1 - derivedTransparency) * (1 - vis->GetTransparency())); if (!vis->InheritTransparency()) break; vis = vis->GetParent(); } return derivedTransparency; } ////////////////////////////////////////////////// void Visual::SetCastShadows(bool _shadows) { for (int i = 0; i < this->dataPtr->sceneNode->numAttachedObjects(); i++) { Ogre::MovableObject *obj = this->dataPtr->sceneNode->getAttachedObject(i); obj->setCastShadows(_shadows); } if (this->IsStatic() && this->dataPtr->staticGeom) this->dataPtr->staticGeom->setCastShadows(_shadows); this->dataPtr->castShadows = _shadows; this->dataPtr->sdf->GetElement("cast_shadows")->Set(_shadows); } ////////////////////////////////////////////////// bool Visual::GetCastShadows() const { return this->dataPtr->castShadows; } ////////////////////////////////////////////////// void Visual::SetVisible(bool _visible, bool _cascade) { if (this->dataPtr->sceneNode) this->dataPtr->sceneNode->setVisible(_visible, _cascade); if (_cascade) { for (auto child: this->dataPtr->children) child->SetVisible(_visible); } this->dataPtr->visible = _visible; } ////////////////////////////////////////////////// uint32_t Visual::GetVisibilityFlags() { return this->dataPtr->visibilityFlags; } ////////////////////////////////////////////////// void Visual::ToggleVisible() { this->SetVisible(!this->GetVisible(), true); } ////////////////////////////////////////////////// bool Visual::GetVisible() const { return this->dataPtr->visible; } ////////////////////////////////////////////////// void Visual::SetPosition(const math::Vector3 &_pos) { /*if (this->IsStatic() && this->staticGeom) { this->staticGeom->reset(); delete this->staticGeom; this->staticGeom = NULL; // this->staticGeom->setOrigin(Ogre::Vector3(pos.x, pos.y, pos.z)); }*/ GZ_ASSERT(this->dataPtr->sceneNode, "Visual SceneNode is NULL"); this->dataPtr->sceneNode->setPosition(_pos.x, _pos.y, _pos.z); this->dataPtr->sdf->GetElement("pose")->Set(this->GetPose()); } ////////////////////////////////////////////////// void Visual::SetRotation(const math::Quaternion &_rot) { GZ_ASSERT(this->dataPtr->sceneNode, "Visual SceneNode is NULL"); this->dataPtr->sceneNode->setOrientation( Ogre::Quaternion(_rot.w, _rot.x, _rot.y, _rot.z)); this->dataPtr->sdf->GetElement("pose")->Set(this->GetPose()); } ////////////////////////////////////////////////// void Visual::SetPose(const math::Pose &_pose) { this->SetPosition(_pose.pos); this->SetRotation(_pose.rot); } ////////////////////////////////////////////////// math::Vector3 Visual::GetPosition() const { return Conversions::Convert(this->dataPtr->sceneNode->getPosition()); } ////////////////////////////////////////////////// math::Quaternion Visual::GetRotation() const { return Conversions::Convert(this->dataPtr->sceneNode->getOrientation()); } ////////////////////////////////////////////////// math::Pose Visual::GetPose() const { math::Pose pos; pos.pos = this->GetPosition(); pos.rot = this->GetRotation(); return pos; } ////////////////////////////////////////////////// ignition::math::Pose3d Visual::InitialRelativePose() const { return this->dataPtr->initialRelativePose; } ////////////////////////////////////////////////// void Visual::SetWorldPose(const math::Pose &_pose) { this->SetWorldPosition(_pose.pos); this->SetWorldRotation(_pose.rot); } ////////////////////////////////////////////////// void Visual::SetWorldPosition(const math::Vector3 &_pos) { this->dataPtr->sceneNode->_setDerivedPosition(Conversions::Convert(_pos)); } ////////////////////////////////////////////////// void Visual::SetWorldRotation(const math::Quaternion &_q) { this->dataPtr->sceneNode->_setDerivedOrientation(Conversions::Convert(_q)); } ////////////////////////////////////////////////// math::Pose Visual::GetWorldPose() const { math::Pose pose; Ogre::Vector3 vpos; Ogre::Quaternion vquatern; if (this->dataPtr->sceneNode) { vpos = this->dataPtr->sceneNode->_getDerivedPosition(); pose.pos.x = vpos.x; pose.pos.y = vpos.y; pose.pos.z = vpos.z; vquatern = this->dataPtr->sceneNode->_getDerivedOrientation(); pose.rot.w = vquatern.w; pose.rot.x = vquatern.x; pose.rot.y = vquatern.y; pose.rot.z = vquatern.z; } return pose; } ////////////////////////////////////////////////// Ogre::SceneNode * Visual::GetSceneNode() const { return this->dataPtr->sceneNode; } ////////////////////////////////////////////////// bool Visual::IsStatic() const { return this->dataPtr->isStatic; } ////////////////////////////////////////////////// void Visual::EnableTrackVisual(VisualPtr _vis) { this->dataPtr->sceneNode->setAutoTracking(true, _vis->GetSceneNode()); } ////////////////////////////////////////////////// void Visual::DisableTrackVisual() { this->dataPtr->sceneNode->setAutoTracking(false); } ////////////////////////////////////////////////// std::string Visual::GetNormalMap() const { std::string file = this->dataPtr->sdf->GetElement("material")->GetElement( "shader")->GetElement("normal_map")->Get(); std::string uriFile = common::find_file(file); if (!uriFile.empty()) file = uriFile; return file; } ////////////////////////////////////////////////// void Visual::SetNormalMap(const std::string &_nmap) { this->dataPtr->sdf->GetElement("material")->GetElement( "shader")->GetElement("normal_map")->GetValue()->Set(_nmap); if (this->dataPtr->useRTShader && this->dataPtr->scene->Initialized()) RTShaderSystem::Instance()->UpdateShaders(); } ////////////////////////////////////////////////// std::string Visual::GetShaderType() const { return this->dataPtr->sdf->GetElement("material")->GetElement( "shader")->Get("type"); } ////////////////////////////////////////////////// void Visual::SetShaderType(const std::string &_type) { this->dataPtr->sdf->GetElement("material")->GetElement( "shader")->GetAttribute("type")->Set(_type); if (this->dataPtr->useRTShader && this->dataPtr->scene->Initialized()) RTShaderSystem::Instance()->UpdateShaders(); } ////////////////////////////////////////////////// void Visual::SetRibbonTrail(bool _value, const common::Color &_initialColor, const common::Color &_changeColor) { if (this->dataPtr->ribbonTrail == NULL) { this->dataPtr->ribbonTrail = this->dataPtr->scene->OgreSceneManager()->createRibbonTrail( this->GetName() + "_RibbonTrail"); this->dataPtr->ribbonTrail->setMaterialName("Gazebo/RibbonTrail"); // this->dataPtr->ribbonTrail->setTrailLength(100); this->dataPtr->ribbonTrail->setMaxChainElements(10000); // this->dataPtr->ribbonTrail->setNumberOfChains(1); this->dataPtr->ribbonTrail->setVisible(false); this->dataPtr->ribbonTrail->setCastShadows(false); this->dataPtr->ribbonTrail->setInitialWidth(0, 0.05); this->dataPtr->scene->OgreSceneManager()->getRootSceneNode()->attachObject( this->dataPtr->ribbonTrail); this->dataPtr->ribbonTrail->setInitialColour(0, Conversions::Convert(_initialColor)); this->dataPtr->ribbonTrail->setColourChange(0, Conversions::Convert(_changeColor)); } if (_value) { try { this->dataPtr->ribbonTrail->addNode(this->dataPtr->sceneNode); } catch(...) { gzerr << "Unable to create ribbon trail\n"; } } else { this->dataPtr->ribbonTrail->removeNode(this->dataPtr->sceneNode); this->dataPtr->ribbonTrail->clearChain(0); } this->dataPtr->ribbonTrail->setVisible(_value); } ////////////////////////////////////////////////// DynamicLines *Visual::CreateDynamicLine(RenderOpType _type) { this->dataPtr->preRenderConnection = event::Events::ConnectPreRender( boost::bind(&Visual::Update, this)); DynamicLines *line = new DynamicLines(_type); this->dataPtr->lines.push_back(line); this->AttachObject(line); return line; } ////////////////////////////////////////////////// void Visual::DeleteDynamicLine(DynamicLines *_line) { // delete instance from lines vector for (std::list::iterator iter = this->dataPtr->lines.begin(); iter != this->dataPtr->lines.end(); ++iter) { if (*iter == _line) { delete *iter; this->dataPtr->lines.erase(iter); break; } } } ////////////////////////////////////////////////// void Visual::AttachLineVertex(DynamicLines *_line, unsigned int _index) { this->dataPtr->lineVertices.push_back(std::make_pair(_line, _index)); _line->SetPoint(_index, this->GetWorldPose().pos.Ign()); } ////////////////////////////////////////////////// std::string Visual::GetMaterialName() const { return this->dataPtr->myMaterialName; } ////////////////////////////////////////////////// math::Box Visual::GetBoundingBox() const { math::Box box; this->GetBoundsHelper(this->GetSceneNode(), box); return box; } ////////////////////////////////////////////////// void Visual::GetBoundsHelper(Ogre::SceneNode *node, math::Box &box) const { node->_updateBounds(); node->_update(false, true); Ogre::Matrix4 invTransform = this->dataPtr->sceneNode->_getFullTransform().inverse(); Ogre::SceneNode::ChildNodeIterator it = node->getChildIterator(); for (int i = 0; i < node->numAttachedObjects(); i++) { Ogre::MovableObject *obj = node->getAttachedObject(i); if (obj->isVisible() && obj->getMovableType() != "gazebo::dynamiclines" && obj->getMovableType() != "BillboardSet" && obj->getVisibilityFlags() != GZ_VISIBILITY_GUI) { Ogre::Any any = obj->getUserObjectBindings().getUserAny(); if (any.getType() == typeid(std::string)) { std::string str = Ogre::any_cast(any); if (str.substr(0, 3) == "rot" || str.substr(0, 5) == "trans" || str.substr(0, 5) == "scale" || str.find("_APPLY_WRENCH_") != std::string::npos) continue; } Ogre::AxisAlignedBox bb = obj->getBoundingBox(); math::Vector3 min; math::Vector3 max; // Ogre does not return a valid bounding box for lights. if (obj->getMovableType() == "Light") { min = math::Vector3(-0.5, -0.5, -0.5); max = math::Vector3(0.5, 0.5, 0.5); } else { // Get transform to be applied to the current node. Ogre::Matrix4 transform = invTransform * node->_getFullTransform(); // Correct precision error which makes ogre's isAffine check fail. transform[3][0] = transform[3][1] = transform[3][2] = 0; transform[3][3] = 1; // get oriented bounding box in object's local space bb.transformAffine(transform); min = Conversions::Convert(bb.getMinimum()); max = Conversions::Convert(bb.getMaximum()); } box.Merge(math::Box(min, max)); } } while (it.hasMoreElements()) { Ogre::SceneNode *next = dynamic_cast(it.getNext()); this->GetBoundsHelper(next, box); } } ////////////////////////////////////////////////// void Visual::InsertMesh(const std::string &_meshName, const std::string &_subMesh, bool _centerSubmesh) { const common::Mesh *mesh; if (!common::MeshManager::Instance()->HasMesh(_meshName)) { mesh = common::MeshManager::Instance()->Load(_meshName); if (!mesh) { gzerr << "Unable to create a mesh from " << _meshName << "\n"; return; } } else { mesh = common::MeshManager::Instance()->GetMesh(_meshName); } this->InsertMesh(mesh, _subMesh, _centerSubmesh); // Add the mesh into OGRE /*if (!this->dataPtr->sceneNode->getCreator()->hasEntity(_meshName) && common::MeshManager::Instance()->HasMesh(_meshName)) { const common::Mesh *mesh = common::MeshManager::Instance()->GetMesh(_meshName); this->InsertMesh(mesh); }*/ } ////////////////////////////////////////////////// void Visual::InsertMesh(const common::Mesh *_mesh, const std::string &_subMesh, bool _centerSubmesh) { Ogre::MeshPtr ogreMesh; GZ_ASSERT(_mesh != NULL, "Unable to insert a NULL mesh"); RenderEngine::Instance()->AddResourcePath(_mesh->GetPath()); if (_mesh->GetSubMeshCount() == 0) { gzerr << "Visual::InsertMesh no submeshes, this is an invalid mesh\n"; return; } // Don't re-add existing meshes if (Ogre::MeshManager::getSingleton().resourceExists(_mesh->GetName())) { return; } try { // Create a new mesh specifically for manual definition. if (_subMesh.empty()) { ogreMesh = Ogre::MeshManager::getSingleton().createManual( _mesh->GetName(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); } else { ogreMesh = Ogre::MeshManager::getSingleton().createManual( _mesh->GetName() + "::" + _subMesh, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); } Ogre::SkeletonPtr ogreSkeleton; if (_mesh->HasSkeleton()) { common::Skeleton *skel = _mesh->GetSkeleton(); ogreSkeleton = Ogre::SkeletonManager::getSingleton().create( _mesh->GetName() + "_skeleton", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); for (unsigned int i = 0; i < skel->GetNumNodes(); i++) { common::SkeletonNode *node = skel->GetNodeByHandle(i); Ogre::Bone *bone = ogreSkeleton->createBone(node->GetName()); if (node->GetParent()) ogreSkeleton->getBone(node->GetParent()->GetName())->addChild(bone); ignition::math::Matrix4d trans = node->Transform(); ignition::math::Vector3d pos = trans.Translation(); ignition::math::Quaterniond q = trans.Rotation(); bone->setPosition(Ogre::Vector3(pos.X(), pos.Y(), pos.Z())); bone->setOrientation(Ogre::Quaternion(q.W(), q.X(), q.Y(), q.Z())); bone->setInheritOrientation(true); bone->setManuallyControlled(true); bone->setInitialState(); } ogreMesh->setSkeletonName(_mesh->GetName() + "_skeleton"); } for (unsigned int i = 0; i < _mesh->GetSubMeshCount(); i++) { if (!_subMesh.empty() && _mesh->GetSubMesh(i)->GetName() != _subMesh) continue; Ogre::SubMesh *ogreSubMesh; Ogre::VertexData *vertexData; Ogre::VertexDeclaration* vertexDecl; Ogre::HardwareVertexBufferSharedPtr vBuf; Ogre::HardwareIndexBufferSharedPtr iBuf; float *vertices; uint32_t *indices; size_t currOffset = 0; // Copy the original submesh. We may need to modify the vertices, and // we don't want to change the original. common::SubMesh subMesh(_mesh->GetSubMesh(i)); // Recenter the vertices if requested. if (_centerSubmesh) subMesh.Center(ignition::math::Vector3d::Zero); ogreSubMesh = ogreMesh->createSubMesh(); ogreSubMesh->useSharedVertices = false; if (subMesh.GetPrimitiveType() == common::SubMesh::TRIANGLES) ogreSubMesh->operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST; else if (subMesh.GetPrimitiveType() == common::SubMesh::LINES) ogreSubMesh->operationType = Ogre::RenderOperation::OT_LINE_LIST; else if (subMesh.GetPrimitiveType() == common::SubMesh::LINESTRIPS) ogreSubMesh->operationType = Ogre::RenderOperation::OT_LINE_STRIP; else if (subMesh.GetPrimitiveType() == common::SubMesh::TRIFANS) ogreSubMesh->operationType = Ogre::RenderOperation::OT_TRIANGLE_FAN; else if (subMesh.GetPrimitiveType() == common::SubMesh::TRISTRIPS) ogreSubMesh->operationType = Ogre::RenderOperation::OT_TRIANGLE_STRIP; else if (subMesh.GetPrimitiveType() == common::SubMesh::POINTS) ogreSubMesh->operationType = Ogre::RenderOperation::OT_POINT_LIST; else gzerr << "Unknown primitive type[" << subMesh.GetPrimitiveType() << "]\n"; ogreSubMesh->vertexData = new Ogre::VertexData(); vertexData = ogreSubMesh->vertexData; vertexDecl = vertexData->vertexDeclaration; // The vertexDecl should contain positions, blending weights, normals, // diffiuse colors, specular colors, tex coords. In that order. vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_POSITION); currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); // TODO: blending weights // normals if (subMesh.GetNormalCount() > 0) { vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); } // TODO: diffuse colors // TODO: specular colors // two dimensional texture coordinates if (subMesh.GetTexCoordCount() > 0) { vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0); currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); } // allocate the vertex buffer vertexData->vertexCount = subMesh.GetVertexCount(); vBuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer( vertexDecl->getVertexSize(0), vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); vertexData->vertexBufferBinding->setBinding(0, vBuf); vertices = static_cast(vBuf->lock( Ogre::HardwareBuffer::HBL_DISCARD)); if (_mesh->HasSkeleton()) { common::Skeleton *skel = _mesh->GetSkeleton(); for (unsigned int j = 0; j < subMesh.GetNodeAssignmentsCount(); j++) { common::NodeAssignment na = subMesh.GetNodeAssignment(j); Ogre::VertexBoneAssignment vba; vba.vertexIndex = na.vertexIndex; vba.boneIndex = ogreSkeleton->getBone(skel->GetNodeByHandle( na.nodeIndex)->GetName())->getHandle(); vba.weight = na.weight; ogreSubMesh->addBoneAssignment(vba); } } // allocate index buffer ogreSubMesh->indexData->indexCount = subMesh.GetIndexCount(); ogreSubMesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer( Ogre::HardwareIndexBuffer::IT_32BIT, ogreSubMesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); iBuf = ogreSubMesh->indexData->indexBuffer; indices = static_cast( iBuf->lock(Ogre::HardwareBuffer::HBL_DISCARD)); unsigned int j; // Add all the vertices for (j = 0; j < subMesh.GetVertexCount(); j++) { *vertices++ = subMesh.Vertex(j).X(); *vertices++ = subMesh.Vertex(j).Y(); *vertices++ = subMesh.Vertex(j).Z(); if (subMesh.GetNormalCount() > 0) { *vertices++ = subMesh.Normal(j).X(); *vertices++ = subMesh.Normal(j).Y(); *vertices++ = subMesh.Normal(j).Z(); } if (subMesh.GetTexCoordCount() > 0) { *vertices++ = subMesh.TexCoord(j).X(); *vertices++ = subMesh.TexCoord(j).Y(); } } // Add all the indices for (j = 0; j < subMesh.GetIndexCount(); j++) *indices++ = subMesh.GetIndex(j); const common::Material *material; material = _mesh->GetMaterial(subMesh.GetMaterialIndex()); if (material) { rendering::Material::Update(material); ogreSubMesh->setMaterialName(material->GetName()); } else { ogreSubMesh->setMaterialName("Gazebo/White"); } // Unlock vBuf->unlock(); iBuf->unlock(); } ignition::math::Vector3d max = _mesh->Max(); ignition::math::Vector3d min = _mesh->Min(); if (_mesh->HasSkeleton()) { min = ignition::math::Vector3d(-1, -1, -1); max = ignition::math::Vector3d(1, 1, 1); } if (!max.IsFinite()) gzthrow("Max bounding box is not finite[" << max << "]\n"); if (!min.IsFinite()) gzthrow("Min bounding box is not finite[" << min << "]\n"); ogreMesh->_setBounds(Ogre::AxisAlignedBox( Ogre::Vector3(min.X(), min.Y(), min.Z()), Ogre::Vector3(max.X(), max.Y(), max.Z())), false); // this line makes clear the mesh is loaded (avoids memory leaks) ogreMesh->load(); } catch(Ogre::Exception &e) { gzerr << "Unable to insert mesh[" << e.getDescription() << "]" << std::endl; } } ////////////////////////////////////////////////// void Visual::UpdateFromMsg(const boost::shared_ptr< msgs::Visual const> &_msg) { // TODO: Put back in, and check for performance improvements. /*if (msg->has_is_static() && msg->is_static()) this->MakeStatic(); */ // Set meta information if (_msg->has_meta()) { if (_msg->meta().has_layer()) { this->dataPtr->layer = _msg->meta().layer(); rendering::Events::newLayer(this->dataPtr->layer); } } if (_msg->has_pose()) this->SetPose(msgs::ConvertIgn(_msg->pose())); if (_msg->has_visible()) this->SetVisible(_msg->visible()); if (_msg->has_scale()) this->SetScale(msgs::ConvertIgn(_msg->scale())); if (_msg->has_geometry() && _msg->geometry().has_type()) { std::string newGeometryType = msgs::ConvertGeometryType(_msg->geometry().type()); std::string geometryType = this->GetGeometryType(); std::string geometryName = this->GetMeshName(); std::string newGeometryName = geometryName; if (_msg->geometry().has_mesh() && _msg->geometry().mesh().has_filename()) { std::string filename = _msg->geometry().mesh().filename(); newGeometryName = common::find_file(filename); } if (newGeometryType != geometryType || (newGeometryType == "mesh" && !newGeometryName.empty() && newGeometryName != geometryName)) { std::string origMaterial = this->dataPtr->myMaterialName; float origTransparency = this->dataPtr->transparency; bool origCastShadows = this->dataPtr->castShadows; sdf::ElementPtr geomElem = this->dataPtr->sdf->GetElement("geometry"); geomElem->ClearElements(); this->DetachObjects(); if (newGeometryType == "box" || newGeometryType == "cylinder" || newGeometryType == "sphere" || newGeometryType == "plane") { this->AttachMesh("unit_" + newGeometryType); sdf::ElementPtr shapeElem = geomElem->AddElement(newGeometryType); if (newGeometryType == "sphere" || newGeometryType == "cylinder") shapeElem->GetElement("radius")->Set(0.5); } else if (newGeometryType == "mesh") { std::string filename = _msg->geometry().mesh().filename(); std::string meshName = newGeometryName; std::string submeshName; bool centerSubmesh = false; if (meshName.empty()) { meshName = "unit_box"; gzerr << "No mesh found, setting mesh to a unit box" << std::endl; } else { if (_msg->geometry().mesh().has_submesh()) submeshName= _msg->geometry().mesh().submesh(); if (_msg->geometry().mesh().has_center_submesh()) centerSubmesh= _msg->geometry().mesh().center_submesh(); } this->AttachMesh(meshName, submeshName, centerSubmesh); sdf::ElementPtr meshElem = geomElem->AddElement(newGeometryType); if (!filename.empty()) meshElem->GetElement("uri")->Set(filename); if (!submeshName.empty()) { sdf::ElementPtr submeshElem = meshElem->GetElement("submesh"); submeshElem->GetElement("name")->Set(submeshName); submeshElem->GetElement("center")->Set(centerSubmesh); } } this->SetTransparency(origTransparency); this->SetMaterial(origMaterial); this->SetCastShadows(origCastShadows); } math::Vector3 geomScale(1, 1, 1); if (_msg->geometry().type() == msgs::Geometry::BOX) { geomScale = msgs::ConvertIgn(_msg->geometry().box().size()); } else if (_msg->geometry().type() == msgs::Geometry::CYLINDER) { geomScale.x = _msg->geometry().cylinder().radius() * 2.0; geomScale.y = _msg->geometry().cylinder().radius() * 2.0; geomScale.z = _msg->geometry().cylinder().length(); } else if (_msg->geometry().type() == msgs::Geometry::SPHERE) { geomScale.x = geomScale.y = geomScale.z = _msg->geometry().sphere().radius() * 2.0; } else if (_msg->geometry().type() == msgs::Geometry::PLANE) { if (_msg->geometry().plane().has_size()) { geomScale.x = _msg->geometry().plane().size().x(); geomScale.y = _msg->geometry().plane().size().y(); } } else if (_msg->geometry().type() == msgs::Geometry::IMAGE) { geomScale.x = geomScale.y = geomScale.z = _msg->geometry().image().scale(); } else if (_msg->geometry().type() == msgs::Geometry::HEIGHTMAP) { geomScale = msgs::ConvertIgn(_msg->geometry().heightmap().size()); } else if (_msg->geometry().type() == msgs::Geometry::MESH) { if (_msg->geometry().mesh().has_scale()) { geomScale = msgs::ConvertIgn(_msg->geometry().mesh().scale()); } } else if (_msg->geometry().type() == msgs::Geometry::EMPTY || _msg->geometry().type() == msgs::Geometry::POLYLINE) { // do nothing for now - keep unit scale. } else gzerr << "Unknown geometry type[" << _msg->geometry().type() << "]\n"; this->SetScale(geomScale * this->dataPtr->scale / this->DerivedScale()); } if (_msg->has_material()) { if (_msg->material().has_lighting()) { this->SetLighting(_msg->material().lighting()); } if (_msg->material().has_script()) { for (int i = 0; i < _msg->material().script().uri_size(); ++i) { RenderEngine::Instance()->AddResourcePath( _msg->material().script().uri(i)); } if (_msg->material().script().has_name() && !_msg->material().script().name().empty()) { this->SetMaterial(_msg->material().script().name()); } } if (_msg->material().has_ambient()) this->SetAmbient(msgs::Convert(_msg->material().ambient())); if (_msg->material().has_diffuse()) this->SetDiffuse(msgs::Convert(_msg->material().diffuse())); if (_msg->material().has_specular()) this->SetSpecular(msgs::Convert(_msg->material().specular())); if (_msg->material().has_emissive()) this->SetEmissive(msgs::Convert(_msg->material().emissive())); if (_msg->material().has_shader_type()) { if (_msg->material().shader_type() == msgs::Material::VERTEX) { this->SetShaderType("vertex"); } else if (_msg->material().shader_type() == msgs::Material::PIXEL) { this->SetShaderType("pixel"); } else if (_msg->material().shader_type() == msgs::Material::NORMAL_MAP_OBJECT_SPACE) { this->SetShaderType("normal_map_object_space"); } else if (_msg->material().shader_type() == msgs::Material::NORMAL_MAP_TANGENT_SPACE) { this->SetShaderType("normal_map_tangent_space"); } else { gzerr << "Unrecognized shader type" << std::endl; } if (_msg->material().has_normal_map()) this->SetNormalMap(_msg->material().normal_map()); } } if (_msg->has_transparency()) { this->SetTransparency(_msg->transparency()); } /*if (msg->points.size() > 0) { DynamicLines *lines = this->AddDynamicLine(RENDERING_LINE_LIST); for (unsigned int i = 0; i < msg->points.size(); i++) lines->AddPoint(msg->points[i]); } */ } ////////////////////////////////////////////////// VisualPtr Visual::GetParent() const { return this->dataPtr->parent; } ////////////////////////////////////////////////// VisualPtr Visual::GetRootVisual() { VisualPtr p = shared_from_this(); while (p->GetParent() && p->GetParent() != this->dataPtr->scene->WorldVisual()) { p = p->GetParent(); } return p; } ////////////////////////////////////////////////// VisualPtr Visual::GetNthAncestor(unsigned int _n) { // Get visual's depth unsigned int depth = this->GetDepth(); // Must be deeper than ancestor if (depth < _n) return NULL; // Get ancestor VisualPtr p = shared_from_this(); while (p->GetParent() && depth != _n) { p = p->GetParent(); --depth; } return p; } ///////////////////////////////////////////////// bool Visual::IsAncestorOf(const rendering::VisualPtr _visual) const { if (!_visual || !this->dataPtr->scene) return false; rendering::VisualPtr world = this->dataPtr->scene->WorldVisual(); rendering::VisualPtr vis = _visual->GetParent(); while (vis) { if (vis->GetName() == this->GetName()) return true; vis = vis->GetParent(); } return false; } ///////////////////////////////////////////////// bool Visual::IsDescendantOf(const rendering::VisualPtr _visual) const { if (!_visual || !this->dataPtr->scene) return false; rendering::VisualPtr world = this->dataPtr->scene->WorldVisual(); rendering::VisualPtr vis = this->GetParent(); while (vis) { if (vis->GetName() == _visual->GetName()) return true; vis = vis->GetParent(); } return false; } ////////////////////////////////////////////////// unsigned int Visual::GetDepth() const { std::shared_ptr p = shared_from_this(); unsigned int depth = 0; while (p->GetParent()) { p = p->GetParent(); ++depth; } return depth; } ////////////////////////////////////////////////// bool Visual::IsPlane() const { if (this->dataPtr->sdf->HasElement("geometry")) { sdf::ElementPtr geomElem = this->dataPtr->sdf->GetElement("geometry"); if (geomElem->HasElement("plane")) return true; } std::vector::const_iterator iter; for (iter = this->dataPtr->children.begin(); iter != this->dataPtr->children.end(); ++iter) { if ((*iter)->IsPlane()) return true; } return false; } ////////////////////////////////////////////////// std::string Visual::GetGeometryType() const { if (this->dataPtr->sdf->HasElement("geometry")) { sdf::ElementPtr geomElem = this->dataPtr->sdf->GetElement("geometry"); if (geomElem->HasElement("box")) return "box"; else if (geomElem->HasElement("sphere")) return "sphere"; else if (geomElem->HasElement("cylinder")) return "cylinder"; else if (geomElem->HasElement("plane")) return "plane"; else if (geomElem->HasElement("image")) return "image"; else if (geomElem->HasElement("polyline")) return "polyline"; else if (geomElem->HasElement("mesh")) return "mesh"; else if (geomElem->HasElement("heightmap")) return "heightmap"; } return ""; } ////////////////////////////////////////////////// std::string Visual::GetMeshName() const { if (!this->dataPtr->meshName.empty()) { return this->dataPtr->meshName; } if (this->dataPtr->sdf->HasElement("geometry")) { sdf::ElementPtr geomElem = this->dataPtr->sdf->GetElement("geometry"); if (geomElem->HasElement("box")) return "unit_box"; else if (geomElem->HasElement("sphere")) return "unit_sphere"; else if (geomElem->HasElement("cylinder")) return "unit_cylinder"; else if (geomElem->HasElement("plane")) return "unit_plane"; else if (geomElem->HasElement("polyline")) { std::string polyLineName = this->GetName(); common::MeshManager *meshManager = common::MeshManager::Instance(); if (!meshManager->IsValidFilename(polyLineName)) { sdf::ElementPtr polylineElem = geomElem->GetElement("polyline"); std::vector > polylines; while (polylineElem) { std::vector vertices; sdf::ElementPtr pointElem = polylineElem->GetElement("point"); while (pointElem) { ignition::math::Vector2d point = pointElem->Get(); vertices.push_back(point); pointElem = pointElem->GetNextElement("point"); } polylineElem = polylineElem->GetNextElement("polyline"); polylines.push_back(vertices); } meshManager->CreateExtrudedPolyline(polyLineName, polylines, geomElem->GetElement("polyline")->Get("height")); } if (meshManager->HasMesh(polyLineName)) return polyLineName; else return std::string(); } else if (geomElem->HasElement("mesh")) { sdf::ElementPtr tmpElem = geomElem->GetElement("mesh"); std::string filename; std::string uri = tmpElem->Get("uri"); if (uri.empty()) { gzerr << " element missing for geometry element:\n"; return std::string(); } filename = common::find_file(uri); if (filename == "__default__" || filename.empty()) gzerr << "No mesh specified\n"; return filename; } } return std::string(); } ////////////////////////////////////////////////// std::string Visual::GetSubMeshName() const { if (!this->dataPtr->subMeshName.empty()) { return this->dataPtr->subMeshName; } std::string result; if (this->dataPtr->sdf->HasElement("geometry")) { sdf::ElementPtr geomElem = this->dataPtr->sdf->GetElement("geometry"); if (geomElem->HasElement("mesh")) { sdf::ElementPtr tmpElem = geomElem->GetElement("mesh"); if (tmpElem->HasElement("submesh")) result = tmpElem->GetElement("submesh")->Get("name"); } } return result; } ////////////////////////////////////////////////// bool Visual::GetCenterSubMesh() const { bool result = false; if (this->dataPtr->sdf->HasElement("geometry")) { sdf::ElementPtr geomElem = this->dataPtr->sdf->GetElement("geometry"); if (geomElem->HasElement("mesh")) { sdf::ElementPtr tmpElem = geomElem->GetElement("mesh"); if (tmpElem->HasElement("submesh")) result = tmpElem->GetElement("submesh")->Get("center"); } } return result; } ////////////////////////////////////////////////// void Visual::MoveToPositions(const std::vector &_pts, double _time, boost::function _onComplete) { Ogre::TransformKeyFrame *key; math::Vector3 start = this->GetWorldPose().pos; this->dataPtr->onAnimationComplete = _onComplete; std::string animName = this->GetName() + "_animation"; Ogre::Animation *anim = this->dataPtr->sceneNode->getCreator()->createAnimation(animName, _time); anim->setInterpolationMode(Ogre::Animation::IM_SPLINE); Ogre::NodeAnimationTrack *strack = anim->createNodeTrack(0, this->dataPtr->sceneNode); key = strack->createNodeKeyFrame(0); key->setTranslate(Ogre::Vector3(start.x, start.y, start.z)); key->setRotation(this->dataPtr->sceneNode->getOrientation()); double dt = _time / (_pts.size()-1); double tt = 0; for (unsigned int i = 0; i < _pts.size(); i++) { key = strack->createNodeKeyFrame(tt); key->setTranslate(Ogre::Vector3( _pts[i].pos.x, _pts[i].pos.y, _pts[i].pos.z)); key->setRotation(Conversions::Convert(_pts[i].rot)); tt += dt; } this->dataPtr->animState = this->dataPtr->sceneNode->getCreator()->createAnimationState(animName); this->dataPtr->animState->setTimePosition(0); this->dataPtr->animState->setEnabled(true); this->dataPtr->animState->setLoop(false); this->dataPtr->prevAnimTime = common::Time::GetWallTime(); if (!this->dataPtr->preRenderConnection) { this->dataPtr->preRenderConnection = event::Events::ConnectPreRender(boost::bind(&Visual::Update, this)); } } ////////////////////////////////////////////////// void Visual::MoveToPosition(const math::Pose &_pose, double _time) { Ogre::TransformKeyFrame *key; math::Vector3 start = this->GetWorldPose().pos; math::Vector3 rpy = _pose.rot.GetAsEuler(); math::Quaternion rotFinal(0, rpy.y, rpy.z); std::string animName = this->GetName() + "_animation"; Ogre::Animation *anim = this->dataPtr->sceneNode->getCreator()->createAnimation(animName, _time); anim->setInterpolationMode(Ogre::Animation::IM_SPLINE); Ogre::NodeAnimationTrack *strack = anim->createNodeTrack(0, this->dataPtr->sceneNode); key = strack->createNodeKeyFrame(0); key->setTranslate(Ogre::Vector3(start.x, start.y, start.z)); key->setRotation(this->dataPtr->sceneNode->getOrientation()); key = strack->createNodeKeyFrame(_time); key->setTranslate(Ogre::Vector3(_pose.pos.x, _pose.pos.y, _pose.pos.z)); key->setRotation(Conversions::Convert(rotFinal)); this->dataPtr->animState = this->dataPtr->sceneNode->getCreator()->createAnimationState(animName); this->dataPtr->animState->setTimePosition(0); this->dataPtr->animState->setEnabled(true); this->dataPtr->animState->setLoop(false); this->dataPtr->prevAnimTime = common::Time::GetWallTime(); this->dataPtr->preRenderConnection = event::Events::ConnectPreRender(boost::bind(&Visual::Update, this)); } ////////////////////////////////////////////////// void Visual::ShowBoundingBox() { this->dataPtr->sceneNode->showBoundingBox(true); } ////////////////////////////////////////////////// void Visual::SetScene(ScenePtr _scene) { this->dataPtr->scene = _scene; } ////////////////////////////////////////////////// ScenePtr Visual::GetScene() const { return this->dataPtr->scene; } ////////////////////////////////////////////////// void Visual::ShowCollision(bool _show) { // If this is a collision visual, set it visible if (this->dataPtr->type == VT_COLLISION) { this->SetVisible(_show); } // If this is a link, check if there are pending collision visuals else if (_show && this->dataPtr->type == VT_LINK && !this->dataPtr->pendingChildren.empty()) { auto it = std::begin(this->dataPtr->pendingChildren); while (it != std::end(this->dataPtr->pendingChildren)) { if (it->first != VT_COLLISION) { ++it; continue; } auto msg = dynamic_cast(it->second); if (!msg) { gzerr << "Wrong message to generate collision visual." << std::endl; } else if (!this->dataPtr->scene->GetVisual(msg->name())) { // Set orange transparent material msg->mutable_material()->mutable_script()->add_uri( "file://media/materials/scripts/gazebo.material"); msg->mutable_material()->mutable_script()->set_name( "Gazebo/OrangeTransparent"); msg->set_cast_shadows(false); // Create visual VisualPtr visual; visual.reset(new Visual(msg->name(), shared_from_this())); if (msg->has_id()) visual->SetId(msg->id()); auto msgPtr = new ConstVisualPtr(msg); visual->LoadFromMsg(*msgPtr); visual->SetType(it->first); visual->SetVisible(_show); visual->SetVisibilityFlags(GZ_VISIBILITY_GUI); visual->SetWireframe(this->dataPtr->scene->Wireframe()); } delete msg; this->dataPtr->pendingChildren.erase(it); } } // Show for children for (auto &child : this->dataPtr->children) { child->ShowCollision(_show); } } ////////////////////////////////////////////////// void Visual::ShowSkeleton(bool _show) { double transp = 0.0; if (_show) transp = 0.5; /// make the rest of the model transparent this->SetTransparency(transp); if (this->GetName().find("__SKELETON_VISUAL__") != std::string::npos) this->SetVisible(_show); std::vector::iterator iter; for (iter = this->dataPtr->children.begin(); iter != this->dataPtr->children.end(); ++iter) { (*iter)->ShowSkeleton(_show); } } ////////////////////////////////////////////////// void Visual::SetVisibilityFlags(uint32_t _flags) { for (std::vector::iterator iter = this->dataPtr->children.begin(); iter != this->dataPtr->children.end(); ++iter) { (*iter)->SetVisibilityFlags(_flags); } for (int i = 0; i < this->dataPtr->sceneNode->numAttachedObjects(); ++i) { this->dataPtr->sceneNode->getAttachedObject(i)->setVisibilityFlags(_flags); } for (unsigned int i = 0; i < this->dataPtr->sceneNode->numChildren(); ++i) { Ogre::SceneNode *sn = (Ogre::SceneNode*)(this->dataPtr->sceneNode->getChild(i)); for (int j = 0; j < sn->numAttachedObjects(); ++j) sn->getAttachedObject(j)->setVisibilityFlags(_flags); } this->dataPtr->visibilityFlags = _flags; } ////////////////////////////////////////////////// void Visual::ShowJoints(bool _show) { // If this is a joint visual, set it visible if (this->dataPtr->type == VT_PHYSICS && this->GetName().find("JOINT_VISUAL__") != std::string::npos) { this->SetVisible(_show); } // If this is a link, check if there are pending joint visuals else if (_show && this->dataPtr->type == VT_LINK && !this->dataPtr->pendingChildren.empty()) { auto it = std::begin(this->dataPtr->pendingChildren); while (it != std::end(this->dataPtr->pendingChildren)) { if (it->first != VT_PHYSICS) { ++it; continue; } auto msg = dynamic_cast(it->second); if (!msg) { ++it; continue; } std::string jointVisName = msg->name() + "_JOINT_VISUAL__"; if (!this->dataPtr->scene->GetVisual(jointVisName)) { JointVisualPtr jointVis(new JointVisual(jointVisName, shared_from_this())); auto msgPtr = new ConstJointPtr(msg); jointVis->Load(*msgPtr); jointVis->SetVisible(_show); if (msg->has_id()) jointVis->SetId(msg->id()); } delete msg; this->dataPtr->pendingChildren.erase(it); } } for (auto &child : this->dataPtr->children) { child->ShowJoints(_show); } } ////////////////////////////////////////////////// void Visual::ShowCOM(bool _show) { // If this is a COM visual, set it visible if (this->dataPtr->type == VT_PHYSICS && this->GetName().find("COM_VISUAL__") != std::string::npos) { this->SetVisible(_show); } // If this is a link without COM visuals, create them else if (_show && this->dataPtr->type == VT_LINK && !this->dataPtr->scene->GetVisual(this->GetName() + "_COM_VISUAL__")) { auto msg = dynamic_cast(this->dataPtr->typeMsg); if (!msg) { gzerr << "Couldn't get link message for visual [" << this->GetName() << "]" << std::endl; return; } auto msgPtr = new ConstLinkPtr(msg); COMVisualPtr vis(new COMVisual(this->GetName() + "_COM_VISUAL__", shared_from_this())); vis->Load(*msgPtr); vis->SetVisible(_show); } // Show for children for (auto &child : this->dataPtr->children) { child->ShowCOM(_show); } } ////////////////////////////////////////////////// void Visual::ShowInertia(bool _show) { std::string suffix("_INERTIA_VISUAL__"); // If this is an inertia visual, set it visible if (this->dataPtr->type == VT_PHYSICS && this->GetName().find(suffix) != std::string::npos) { this->SetVisible(_show); } // If this is a link without inertia visuals, create them else if (_show && this->dataPtr->type == VT_LINK && this->dataPtr->typeMsg && !this->dataPtr->scene->GetVisual(this->GetName() + suffix)) { auto msg = dynamic_cast(this->dataPtr->typeMsg); if (!msg) { gzerr << "Couldn't get link message for visual [" << this->GetName() << "]" << std::endl; return; } auto msgPtr = new ConstLinkPtr(msg); InertiaVisualPtr vis(new InertiaVisual(this->GetName() + suffix, shared_from_this())); vis->Load(*msgPtr); vis->SetVisible(_show); } // Show for children for (auto &child : this->dataPtr->children) { child->ShowInertia(_show); } } ////////////////////////////////////////////////// void Visual::ShowLinkFrame(bool _show) { // If this is a link frame visual, set it visible if (this->dataPtr->type == VT_PHYSICS && this->GetName().find("LINK_FRAME_VISUAL__") != std::string::npos) { this->SetVisible(_show); } // If this is a link without link frame visuals, create them else if (_show && this->dataPtr->type == VT_LINK && this->dataPtr->typeMsg && !this->dataPtr->scene->GetVisual(this->GetName() + "_LINK_FRAME_VISUAL__")) { LinkFrameVisualPtr vis(new LinkFrameVisual(this->GetName() + "_LINK_FRAME_VISUAL__", shared_from_this())); vis->Load(); vis->SetVisible(_show); } // Show for children for (auto &child : this->dataPtr->children) { child->ShowLinkFrame(_show); } } ////////////////////////////////////////////////// void Visual::SetSkeletonPose(const msgs::PoseAnimation &_pose) { if (!this->dataPtr->skeleton) { gzerr << "Visual " << this->GetName() << " has no skeleton.\n"; return; } for (int i = 0; i < _pose.pose_size(); i++) { const msgs::Pose& bonePose = _pose.pose(i); if (!this->dataPtr->skeleton->hasBone(bonePose.name())) continue; Ogre::Bone *bone = this->dataPtr->skeleton->getBone(bonePose.name()); Ogre::Vector3 p(bonePose.position().x(), bonePose.position().y(), bonePose.position().z()); Ogre::Quaternion quat(Ogre::Quaternion(bonePose.orientation().w(), bonePose.orientation().x(), bonePose.orientation().y(), bonePose.orientation().z())); bone->setManuallyControlled(true); bone->setPosition(p); bone->setOrientation(quat); } } ////////////////////////////////////////////////// void Visual::LoadPlugins() { if (this->dataPtr->sdf->HasElement("plugin")) { sdf::ElementPtr pluginElem = this->dataPtr->sdf->GetElement("plugin"); while (pluginElem) { this->LoadPlugin(pluginElem); pluginElem = pluginElem->GetNextElement("plugin"); } } for (std::vector::iterator iter = this->dataPtr->plugins.begin(); iter != this->dataPtr->plugins.end(); ++iter) { (*iter)->Init(); } } ////////////////////////////////////////////////// void Visual::LoadPlugin(const std::string &_filename, const std::string &_name, sdf::ElementPtr _sdf) { gazebo::VisualPluginPtr plugin = gazebo::VisualPlugin::Create(_filename, _name); if (plugin) { if (plugin->GetType() != VISUAL_PLUGIN) { gzerr << "Visual[" << this->GetName() << "] is attempting to load " << "a plugin, but detected an incorrect plugin type. " << "Plugin filename[" << _filename << "] name[" << _name << "]\n"; return; } plugin->Load(shared_from_this(), _sdf); this->dataPtr->plugins.push_back(plugin); if (this->dataPtr->initialized) plugin->Init(); } } ////////////////////////////////////////////////// void Visual::RemovePlugin(const std::string &_name) { std::vector::iterator iter; for (iter = this->dataPtr->plugins.begin(); iter != this->dataPtr->plugins.end(); ++iter) { if ((*iter)->GetHandle() == _name) { this->dataPtr->plugins.erase(iter); break; } } } ////////////////////////////////////////////////// void Visual::LoadPlugin(sdf::ElementPtr _sdf) { std::string pluginName = _sdf->Get("name"); std::string filename = _sdf->Get("filename"); this->LoadPlugin(filename, pluginName, _sdf); } ////////////////////////////////////////////////// uint32_t Visual::GetId() const { return this->dataPtr->id; } ////////////////////////////////////////////////// void Visual::SetId(uint32_t _id) { if (this->dataPtr->id == _id) return; // set new id and also let the scene know that the id has changed. this->dataPtr->scene->SetVisualId(shared_from_this(), _id); this->dataPtr->id = _id; } ////////////////////////////////////////////////// sdf::ElementPtr Visual::GetSDF() const { return this->dataPtr->sdf; } ////////////////////////////////////////////////// Visual::VisualType Visual::GetType() const { return this->dataPtr->type; } ////////////////////////////////////////////////// void Visual::SetType(const Visual::VisualType _type) { this->dataPtr->type = _type; } ////////////////////////////////////////////////// void Visual::ToggleLayer(const int32_t _layer) { // Visuals with negative layers are always visible if (this->dataPtr->layer < 0) return; if (this->dataPtr->layer == _layer) { this->ToggleVisible(); } } ////////////////////////////////////////////////// Visual::VisualType Visual::ConvertVisualType(const msgs::Visual::Type &_type) { Visual::VisualType visualType = Visual::VT_ENTITY; switch (_type) { case msgs::Visual::ENTITY: visualType = Visual::VT_ENTITY; break; case msgs::Visual::MODEL: visualType = Visual::VT_MODEL; break; case msgs::Visual::LINK: visualType = Visual::VT_LINK; break; case msgs::Visual::VISUAL: visualType = Visual::VT_VISUAL; break; case msgs::Visual::COLLISION: visualType = Visual::VT_COLLISION; break; case msgs::Visual::SENSOR: visualType = Visual::VT_SENSOR; break; case msgs::Visual::GUI: visualType = Visual::VT_GUI; break; case msgs::Visual::PHYSICS: visualType = Visual::VT_PHYSICS; break; default: gzerr << "Cannot convert visual type. Defaults to 'VT_ENTITY'" << std::endl; break; } return visualType; } ////////////////////////////////////////////////// msgs::Visual::Type Visual::ConvertVisualType(const Visual::VisualType &_type) { msgs::Visual::Type visualType = msgs::Visual::ENTITY; switch (_type) { case Visual::VT_ENTITY: visualType = msgs::Visual::ENTITY; break; case Visual::VT_MODEL: visualType = msgs::Visual::MODEL; break; case Visual::VT_LINK: visualType = msgs::Visual::LINK; break; case Visual::VT_VISUAL: visualType = msgs::Visual::VISUAL; break; case Visual::VT_COLLISION: visualType = msgs::Visual::COLLISION; break; case Visual::VT_SENSOR: visualType = msgs::Visual::SENSOR; break; case Visual::VT_GUI: visualType = msgs::Visual::GUI; break; case Visual::VT_PHYSICS: visualType = msgs::Visual::PHYSICS; break; default: gzerr << "Cannot convert visual type. Defaults to 'msgs::Visual::ENTITY'" << std::endl; break; } return visualType; } ////////////////////////////////////////////////// bool Visual::UseRTShader() const { return this->dataPtr->useRTShader; } ////////////////////////////////////////////////// void Visual::SetTypeMsg(const google::protobuf::Message *_msg) { if (!_msg) { gzerr << "Null type message." << std::endl; return; } this->dataPtr->typeMsg = _msg->New(); this->dataPtr->typeMsg->CopyFrom(*_msg); } ////////////////////////////////////////////////// void Visual::AddPendingChild(std::pair _pair) { // Copy msg auto msg = _pair.second->New(); msg->CopyFrom(*_pair.second); this->dataPtr->pendingChildren.push_back(std::make_pair(_pair.first, msg)); }