/* * 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. * */ #ifndef _WIN32 #include #else // Ensure that Winsock2.h is included before Windows.h, which can get // pulled in by anybody (e.g., Boost). #include #include "gazebo/common/win_dirent.h" #endif #include "gazebo/common/Events.hh" #include "gazebo/common/Console.hh" #include "gazebo/rendering/ogre_gazebo.h" #include "gazebo/rendering/Conversions.hh" #include "gazebo/rendering/Scene.hh" #include "gazebo/rendering/DepthCamera.hh" #include "gazebo/rendering/DepthCameraPrivate.hh" using namespace gazebo; using namespace rendering; ////////////////////////////////////////////////// DepthCamera::DepthCamera(const std::string &_namePrefix, ScenePtr _scene, bool _autoRender) : Camera(_namePrefix, _scene, _autoRender), dataPtr(new DepthCameraPrivate) { this->depthTarget = NULL; this->dataPtr->depthBuffer = NULL; this->dataPtr->depthMaterial = NULL; this->dataPtr->pcdTarget = NULL; this->dataPtr->pcdBuffer = NULL; this->dataPtr->pcdMaterial = NULL; this->dataPtr->outputPoints = false; } ////////////////////////////////////////////////// DepthCamera::~DepthCamera() { if (this->dataPtr->depthBuffer) delete [] this->dataPtr->depthBuffer; if (this->dataPtr->pcdBuffer) delete [] this->dataPtr->pcdBuffer; } ////////////////////////////////////////////////// void DepthCamera::Load(sdf::ElementPtr _sdf) { Camera::Load(_sdf); this->dataPtr->outputPoints = (_sdf->GetElement("depth_camera")->Get("output") == "points"); } ////////////////////////////////////////////////// void DepthCamera::Load() { Camera::Load(); } ////////////////////////////////////////////////// void DepthCamera::Init() { Camera::Init(); } ////////////////////////////////////////////////// void DepthCamera::Fini() { Camera::Fini(); } ////////////////////////////////////////////////// void DepthCamera::CreateDepthTexture(const std::string &_textureName) { // Create the depth buffer std::string depthMaterialName = this->Name() + "_RttMat_Camera_Depth"; this->depthTexture = Ogre::TextureManager::getSingleton().createManual( _textureName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, this->ImageWidth(), this->ImageHeight(), 0, Ogre::PF_FLOAT32_R, Ogre::TU_RENDERTARGET).getPointer(); this->depthTarget = this->depthTexture->getBuffer()->getRenderTarget(); this->depthTarget->setAutoUpdated(false); this->SetDepthTarget(this->depthTarget); this->depthViewport->setOverlaysEnabled(false); this->depthViewport->setBackgroundColour( Ogre::ColourValue(Ogre::ColourValue(0, 0, 0))); // Create materials for all the render textures. Ogre::MaterialPtr matPtr = Ogre::MaterialManager::getSingleton().create( depthMaterialName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); matPtr->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); matPtr->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); matPtr->getTechnique(0)->getPass(0)->setLightingEnabled(false); matPtr->getTechnique(0)->getPass(0)->createTextureUnitState( _textureName); this->dataPtr->depthMaterial = (Ogre::Material*)( Ogre::MaterialManager::getSingleton().getByName("Gazebo/DepthMap").get()); this->dataPtr->depthMaterial->load(); if (this->dataPtr->outputPoints) { this->dataPtr->pcdTexture = Ogre::TextureManager::getSingleton().createManual( _textureName + "_pcd", "General", Ogre::TEX_TYPE_2D, this->ImageWidth(), this->ImageHeight(), 0, Ogre::PF_FLOAT32_RGBA, Ogre::TU_RENDERTARGET).getPointer(); this->dataPtr->pcdTarget = this->dataPtr->pcdTexture->getBuffer()->getRenderTarget(); this->dataPtr->pcdTarget->setAutoUpdated(false); this->dataPtr->pcdViewport = this->dataPtr->pcdTarget->addViewport(this->camera); this->dataPtr->pcdViewport->setClearEveryFrame(true); this->dataPtr->pcdViewport->setBackgroundColour( Conversions::Convert(this->scene->BackgroundColor())); this->dataPtr->pcdViewport->setOverlaysEnabled(false); this->dataPtr->pcdViewport->setVisibilityMask( GZ_VISIBILITY_ALL & ~(GZ_VISIBILITY_GUI | GZ_VISIBILITY_SELECTABLE)); this->dataPtr->pcdMaterial = (Ogre::Material*)( Ogre::MaterialManager::getSingleton().getByName("Gazebo/XYZPoints").get()); this->dataPtr->pcdMaterial->getTechnique(0)->getPass(0)-> createTextureUnitState(this->renderTexture->getName()); this->dataPtr->pcdMaterial->load(); } /* // Create a custom render queue invocation sequence for the depth // render texture Ogre::RenderQueueInvocationSequence* invocationSequence = Ogre::Root::getSingleton().createRenderQueueInvocationSequence(_textureName + "_DepthMap"); // Add a render queue invocation to the sequence, and disable shadows for it Ogre::RenderQueueInvocation* invocation = invocationSequence->add(Ogre::RENDER_QUEUE_MAIN, _textureName + "_main"); invocation->setSuppressShadows(true); // Set the render queue invocation sequence for the depth render texture // viewport this->depthViewport->setRenderQueueInvocationSequenceName( _textureName + "_DepthMap"); */ } ////////////////////////////////////////////////// void DepthCamera::PostRender() { this->depthTarget->swapBuffers(); if (this->dataPtr->outputPoints) this->dataPtr->pcdTarget->swapBuffers(); if (this->newData && this->captureData) { unsigned int width = this->ImageWidth(); unsigned int height = this->ImageHeight(); if (!this->dataPtr->outputPoints) { Ogre::HardwarePixelBufferSharedPtr pixelBuffer; // Get access to the buffer and make an image and write it to file pixelBuffer = this->depthTexture->getBuffer(); size_t size = Ogre::PixelUtil::getMemorySize(width, height, 1, Ogre::PF_FLOAT32_R); // Blit the depth buffer if needed if (!this->dataPtr->depthBuffer) this->dataPtr->depthBuffer = new float[size]; Ogre::PixelBox dstBox(width, height, 1, Ogre::PF_FLOAT32_R, this->dataPtr->depthBuffer); pixelBuffer->lock(Ogre::HardwarePixelBuffer::HBL_NORMAL); pixelBuffer->blitToMemory(dstBox); pixelBuffer->unlock(); // FIXME: do we need to lock/unlock still? this->dataPtr->newDepthFrame( this->dataPtr->depthBuffer, width, height, 1, "FLOAT32"); } else { Ogre::HardwarePixelBufferSharedPtr pcdPixelBuffer; // Get access to the buffer and make an image and write it to file pcdPixelBuffer = this->dataPtr->pcdTexture->getBuffer(); // Blit the depth buffer if needed if (!this->dataPtr->pcdBuffer) this->dataPtr->pcdBuffer = new float[width * height * 4]; memset(this->dataPtr->pcdBuffer, 0, width * height * 4); Ogre::Box pcd_src_box(0, 0, width, height); Ogre::PixelBox pcd_dst_box(width, height, 1, Ogre::PF_FLOAT32_RGBA, this->dataPtr->pcdBuffer); pcdPixelBuffer->lock(Ogre::HardwarePixelBuffer::HBL_NORMAL); pcdPixelBuffer->blitToMemory(pcd_src_box, pcd_dst_box); pcdPixelBuffer->unlock(); this->dataPtr->newRGBPointCloud( this->dataPtr->pcdBuffer, width, height, 1, "RGBPOINTS"); } } // also new image frame for camera texture Camera::PostRender(); this->newData = false; } ////////////////////////////////////////////////// void DepthCamera::UpdateRenderTarget(Ogre::RenderTarget *_target, Ogre::Material *_material, const std::string &_matName) { Ogre::RenderSystem *renderSys; Ogre::Viewport *vp = NULL; Ogre::SceneManager *sceneMgr = this->scene->OgreSceneManager(); Ogre::Pass *pass; renderSys = this->scene->OgreSceneManager()->getDestinationRenderSystem(); // Get pointer to the material pass pass = _material->getBestTechnique()->getPass(0); // Render the depth texture // OgreSceneManager::_render function automatically sets farClip to 0. // Which normally equates to infinite distance. We don't want this. So // we have to set the distance every time. this->OgreCamera()->setFarClipDistance(this->FarClip()); Ogre::AutoParamDataSource autoParamDataSource; vp = _target->getViewport(0); // return 0 in case no renderable object is inside frustrum vp->setBackgroundColour(Ogre::ColourValue(Ogre::ColourValue(0, 0, 0))); Ogre::CompositorManager::getSingleton().setCompositorEnabled( vp, _matName, true); // Need this line to render the ground plane. No idea why it's necessary. renderSys->_setViewport(vp); sceneMgr->_setPass(pass, true, false); autoParamDataSource.setCurrentPass(pass); autoParamDataSource.setCurrentViewport(vp); autoParamDataSource.setCurrentRenderTarget(_target); autoParamDataSource.setCurrentSceneManager(sceneMgr); autoParamDataSource.setCurrentCamera(this->OgreCamera(), true); renderSys->setLightingEnabled(false); renderSys->_setFog(Ogre::FOG_NONE); // These two lines don't seem to do anything useful renderSys->_setProjectionMatrix( this->OgreCamera()->getProjectionMatrixRS()); renderSys->_setViewMatrix(this->OgreCamera()->getViewMatrix(true)); #if OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR == 6 pass->_updateAutoParamsNoLights(&autoParamDataSource); #else pass->_updateAutoParams(&autoParamDataSource, 1); #endif // NOTE: We MUST bind parameters AFTER updating the autos if (pass->hasVertexProgram()) { renderSys->bindGpuProgram( pass->getVertexProgram()->_getBindingDelegate()); #if OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR == 6 renderSys->bindGpuProgramParameters(Ogre::GPT_VERTEX_PROGRAM, pass->getVertexProgramParameters()); #else renderSys->bindGpuProgramParameters(Ogre::GPT_VERTEX_PROGRAM, pass->getVertexProgramParameters(), 1); #endif } if (pass->hasFragmentProgram()) { renderSys->bindGpuProgram( pass->getFragmentProgram()->_getBindingDelegate()); #if OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR == 6 renderSys->bindGpuProgramParameters(Ogre::GPT_FRAGMENT_PROGRAM, pass->getFragmentProgramParameters()); #else renderSys->bindGpuProgramParameters(Ogre::GPT_FRAGMENT_PROGRAM, pass->getFragmentProgramParameters(), 1); #endif } } ////////////////////////////////////////////////// void DepthCamera::RenderImpl() { Ogre::SceneManager *sceneMgr = this->scene->OgreSceneManager(); Ogre::ShadowTechnique shadowTech = sceneMgr->getShadowTechnique(); sceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_NONE); sceneMgr->_suppressRenderStateChanges(true); this->UpdateRenderTarget(this->depthTarget, this->dataPtr->depthMaterial, "Gazebo/DepthMap"); // Does actual rendering this->depthTarget->update(false); sceneMgr->_suppressRenderStateChanges(false); sceneMgr->setShadowTechnique(shadowTech); // for camera image Camera::RenderImpl(); if (this->dataPtr->outputPoints) { sceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_NONE); sceneMgr->_suppressRenderStateChanges(true); this->UpdateRenderTarget(this->dataPtr->pcdTarget, this->dataPtr->pcdMaterial, "Gazebo/XYZPoints"); this->dataPtr->pcdTarget->update(false); sceneMgr->_suppressRenderStateChanges(false); sceneMgr->setShadowTechnique(shadowTech); } } ////////////////////////////////////////////////// const float* DepthCamera::GetDepthData() { return this->DepthData(); } ////////////////////////////////////////////////// const float* DepthCamera::DepthData() const { return this->dataPtr->depthBuffer; } ////////////////////////////////////////////////// void DepthCamera::SetDepthTarget(Ogre::RenderTarget *_target) { this->depthTarget = _target; if (this->depthTarget) { // Setup the viewport to use the texture this->depthViewport = this->depthTarget->addViewport(this->camera); this->depthViewport->setClearEveryFrame(true); this->depthViewport->setBackgroundColour( Conversions::Convert(this->scene->BackgroundColor())); this->depthViewport->setVisibilityMask( GZ_VISIBILITY_ALL & ~(GZ_VISIBILITY_GUI | GZ_VISIBILITY_SELECTABLE)); double ratio = static_cast(this->depthViewport->getActualWidth()) / static_cast(this->depthViewport->getActualHeight()); double hfov = this->HFOV().Radian(); double vfov = 2.0 * atan(tan(hfov / 2.0) / ratio); // gzerr << "debug " << hfov << " " << vfov << " " << ratio << "\n"; this->camera->setAspectRatio(ratio); this->camera->setFOVy(Ogre::Radian(vfov)); } } ////////////////////////////////////////////////// event::ConnectionPtr DepthCamera::ConnectNewDepthFrame( std::function _subscriber) { return this->dataPtr->newDepthFrame.Connect(_subscriber); } ////////////////////////////////////////////////// void DepthCamera::DisconnectNewDepthFrame(event::ConnectionPtr &_c) { this->dataPtr->newDepthFrame.Disconnect(_c); } ////////////////////////////////////////////////// event::ConnectionPtr DepthCamera::ConnectNewRGBPointCloud( std::function _subscriber) { return this->dataPtr->newRGBPointCloud.Connect(_subscriber); } ////////////////////////////////////////////////// void DepthCamera::DisconnectNewRGBPointCloud(event::ConnectionPtr &_c) { this->dataPtr->newRGBPointCloud.Disconnect(_c); }