pxmlw6n2f/Gazebo_Distributed_MPI/gazebo/rendering/Camera.cc

2228 lines
61 KiB
C++

/*
* 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.
*
*/
#ifdef _WIN32
// Ensure that Winsock2.h is included before Windows.h, which can get
// pulled in by anybody (e.g., Boost).
#include <Winsock2.h>
#endif
#include <sstream>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <sdf/sdf.hh>
#ifndef _WIN32
#include <dirent.h>
#else
#include "gazebo/common/win_dirent.h"
#endif
// Moved to top to avoid osx compilation errors
#include "gazebo/math/Rand.hh"
#include "gazebo/rendering/skyx/include/SkyX.h"
#include "gazebo/common/Assert.hh"
#include "gazebo/common/Events.hh"
#include "gazebo/common/Console.hh"
#include "gazebo/common/Exception.hh"
#include "gazebo/math/Pose.hh"
#include "gazebo/rendering/ogre_gazebo.h"
#include "gazebo/rendering/RTShaderSystem.hh"
#include "gazebo/rendering/RenderEngine.hh"
#include "gazebo/rendering/Visual.hh"
#include "gazebo/rendering/Conversions.hh"
#include "gazebo/rendering/Scene.hh"
#include "gazebo/rendering/Distortion.hh"
#include "gazebo/rendering/CameraPrivate.hh"
#include "gazebo/rendering/Camera.hh"
using namespace gazebo;
using namespace rendering;
unsigned int CameraPrivate::cameraCounter = 0;
//////////////////////////////////////////////////
Camera::Camera(const std::string &_name, ScenePtr _scene,
bool _autoRender)
: dataPtr(new CameraPrivate)
{
this->initialized = false;
this->sdf.reset(new sdf::Element);
sdf::initFile("camera.sdf", this->sdf);
this->animState = NULL;
this->windowId = 0;
this->scene = _scene;
this->newData = false;
this->textureWidth = this->textureHeight = 0;
this->saveFrameBuffer = NULL;
this->saveCount = 0;
this->bayerFrameBuffer = NULL;
this->name = _name;
this->scopedName = this->scene->Name() + "::" + _name;
this->scopedUniqueName = this->scopedName + "(" +
boost::lexical_cast<std::string>(++this->dataPtr->cameraCounter) + ")";
this->renderTarget = NULL;
this->renderTexture = NULL;
this->captureData = false;
this->captureDataOnce = false;
this->camera = NULL;
this->viewport = NULL;
this->sceneNode = NULL;
this->screenshotPath = getenv("HOME");
this->screenshotPath += "/.gazebo/pictures";
// Connect to the render signal
this->connections.push_back(
event::Events::ConnectPostRender(std::bind(&Camera::Update, this)));
if (_autoRender)
{
this->connections.push_back(event::Events::ConnectRender(
std::bind(&Camera::Render, this, false)));
this->connections.push_back(
event::Events::ConnectPostRender(
std::bind(&Camera::PostRender, this)));
}
this->lastRenderWallTime = common::Time::GetWallTime();
// Set default render rate to unlimited
this->SetRenderRate(0.0);
this->dataPtr->node = transport::NodePtr(new transport::Node());
this->dataPtr->node->Init();
}
//////////////////////////////////////////////////
Camera::~Camera()
{
this->Fini();
}
//////////////////////////////////////////////////
void Camera::Load(sdf::ElementPtr _sdf)
{
this->sdf->Copy(_sdf);
this->Load();
}
//////////////////////////////////////////////////
void Camera::Load()
{
sdf::ElementPtr imgElem = this->sdf->GetElement("image");
if (imgElem)
{
this->imageWidth = imgElem->Get<int>("width");
this->imageHeight = imgElem->Get<int>("height");
this->imageFormat = this->OgrePixelFormat(
imgElem->Get<std::string>("format"));
}
else
gzthrow("Camera has no <image> tag.");
// Create the directory to store frames
if (this->sdf->HasElement("save") &&
this->sdf->GetElement("save")->Get<bool>("enabled"))
{
sdf::ElementPtr elem = this->sdf->GetElement("save");
std::string command;
command = "mkdir " + elem->Get<std::string>("path")+ " 2>>/dev/null";
if (system(command.c_str()) < 0)
gzerr << "Error making directory\n";
}
if (this->sdf->HasElement("horizontal_fov"))
{
sdf::ElementPtr elem = this->sdf->GetElement("horizontal_fov");
ignition::math::Angle angle = elem->Get<double>();
if (angle < 0.01 || angle > M_PI*2)
{
gzthrow("Camera horizontal field of view invalid.");
}
this->SetHFOV(angle);
}
// Only create a command subscription for real cameras. Ignore camera's
// created for visualization purposes.
if (this->name.find("_GUIONLY_") == std::string::npos)
{
std::string topicName = this->Name();
boost::replace_all(topicName, "::", "/");
this->dataPtr->cmdSub = this->dataPtr->node->Subscribe(
"~/" + topicName + "/cmd", &Camera::OnCmdMsg, this, true);
}
if (this->sdf->HasElement("distortion"))
{
this->dataPtr->distortion.reset(new Distortion());
this->dataPtr->distortion->Load(this->sdf->GetElement("distortion"));
}
}
//////////////////////////////////////////////////
void Camera::Init()
{
this->SetSceneNode(
this->scene->OgreSceneManager()->getRootSceneNode()->createChildSceneNode(
this->scopedUniqueName + "_SceneNode"));
this->CreateCamera();
this->sceneNode->attachObject(this->camera);
this->camera->setAutoAspectRatio(true);
this->sceneNode->setInheritScale(false);
this->saveCount = 0;
this->SetClipDist();
}
//////////////////////////////////////////////////
void Camera::Fini()
{
if (this->saveFrameBuffer)
delete [] this->saveFrameBuffer;
this->saveFrameBuffer = NULL;
if (this->bayerFrameBuffer)
delete [] this->bayerFrameBuffer;
this->bayerFrameBuffer = NULL;
this->initialized = false;
this->dataPtr->cmdSub.reset();
if (this->dataPtr->node)
this->dataPtr->node->Fini();
this->dataPtr->node.reset();
this->dataPtr->distortion.reset();
this->dataPtr->trackedVisual.reset();
if (this->viewport && this->scene)
RTShaderSystem::DetachViewport(this->viewport, this->scene);
if (this->renderTarget)
this->renderTarget->removeAllViewports();
this->renderTarget = NULL;
if (this->renderTexture)
Ogre::TextureManager::getSingleton().remove(this->renderTexture->getName());
this->renderTexture = NULL;
if (this->camera)
{
this->scene->OgreSceneManager()->destroyCamera(this->scopedUniqueName);
this->camera = NULL;
}
this->sceneNode = NULL;
this->viewport = NULL;
this->scene.reset();
this->connections.clear();
if (this->sdf)
this->sdf->Reset();
this->sdf.reset();
}
//////////////////////////////////////////////////
void Camera::SetWindowId(unsigned int _windowId)
{
this->windowId = _windowId;
}
//////////////////////////////////////////////////
unsigned int Camera::GetWindowId() const
{
return this->WindowId();
}
//////////////////////////////////////////////////
unsigned int Camera::WindowId() const
{
return this->windowId;
}
//////////////////////////////////////////////////
void Camera::SetScene(ScenePtr _scene)
{
this->scene = _scene;
}
//////////////////////////////////////////////////
void Camera::Update()
{
std::lock_guard<std::mutex> lock(this->dataPtr->receiveMutex);
// Process all the command messages.
for (CameraPrivate::CameraCmdMsgs_L::iterator iter =
this->dataPtr->commandMsgs.begin();
iter != this->dataPtr->commandMsgs.end(); ++iter)
{
if ((*iter)->has_follow_model())
this->TrackVisual((*iter)->follow_model());
}
this->dataPtr->commandMsgs.clear();
std::list<msgs::Request>::iterator iter = this->requests.begin();
while (iter != this->requests.end())
{
bool erase = false;
if ((*iter).request() == "track_visual")
{
if (this->TrackVisualImpl((*iter).data()))
erase = true;
}
else if ((*iter).request() == "attach_visual")
{
msgs::TrackVisual msg;
msg.ParseFromString((*iter).data());
bool result = false;
if (msg.id() < GZ_UINT32_MAX)
result = this->AttachToVisualImpl(msg.id(),
msg.inherit_orientation(), msg.min_dist(), msg.max_dist());
else
result = this->AttachToVisualImpl(msg.name(),
msg.inherit_orientation(), msg.min_dist(), msg.max_dist());
if (result)
erase = true;
}
if (erase)
iter = this->requests.erase(iter);
else
++iter;
}
// Update animations
if (this->animState)
{
if (this->animState->hasEnded())
{
try
{
this->scene->OgreSceneManager()->destroyAnimation(
std::string(this->animState->getAnimationName()));
} catch(Ogre::Exception &_e)
{
}
this->animState = NULL;
this->AnimationComplete();
if (this->onAnimationComplete)
this->onAnimationComplete();
if (!this->dataPtr->moveToPositionQueue.empty())
{
this->MoveToPosition(this->dataPtr->moveToPositionQueue[0].first,
this->dataPtr->moveToPositionQueue[0].second);
this->dataPtr->moveToPositionQueue.pop_front();
}
}
else
{
common::Time wallTime = common::Time::GetWallTime();
this->animState->addTime((wallTime - this->prevAnimTime).Double());
this->prevAnimTime = wallTime;
}
}
else if (this->dataPtr->trackedVisual)
{
ignition::math::Vector3d direction =
this->dataPtr->trackedVisual->GetWorldPose().pos.Ign() -
this->WorldPose().Pos();
double yaw = atan2(direction.Y(), direction.X());
double pitch = atan2(-direction.Z(),
sqrt(pow(direction.X(), 2) + pow(direction.Y(), 2)));
Ogre::Quaternion localRotOgre = this->sceneNode->getOrientation();
ignition::math::Quaterniond localRot = ignition::math::Quaterniond(
localRotOgre.w, localRotOgre.x, localRotOgre.y, localRotOgre.z);
double currPitch = localRot.Euler().Y();
double currYaw = localRot.Euler().Z();
double pitchError = currPitch - pitch;
double yawError = currYaw - yaw;
if (yawError > M_PI)
yawError -= M_PI*2;
if (yawError < -M_PI)
yawError += M_PI*2;
double pitchAdj = this->dataPtr->trackVisualPitchPID.Update(
pitchError, 0.01);
double yawAdj = this->dataPtr->trackVisualYawPID.Update(
yawError, 0.01);
this->SetWorldRotation(ignition::math::Quaterniond(0, currPitch + pitchAdj,
currYaw + yawAdj));
double origDistance = 8.0;
double distance = direction.Length();
double error = origDistance - distance;
double scaling = this->dataPtr->trackVisualPID.Update(error, 0.3);
ignition::math::Vector3d displacement = direction;
displacement.Normalize();
displacement *= scaling;
ignition::math::Vector3d localPos =
Conversions::ConvertIgn(this->sceneNode->_getDerivedPosition());
ignition::math::Vector3d pos = localPos + displacement;
this->SetWorldPosition(pos);
}
}
//////////////////////////////////////////////////
void Camera::Render(const bool _force)
{
if (this->initialized && (_force ||
common::Time::GetWallTime() - this->lastRenderWallTime >=
this->dataPtr->renderPeriod))
{
this->newData = true;
this->RenderImpl();
}
}
//////////////////////////////////////////////////
void Camera::RenderImpl()
{
if (this->renderTarget)
{
this->renderTarget->update();
}
}
//////////////////////////////////////////////////
void Camera::ReadPixelBuffer()
{
if (this->newData && (this->captureData || this->captureDataOnce))
{
size_t size;
unsigned int width = this->ImageWidth();
unsigned int height = this->ImageHeight();
// Get access to the buffer and make an image and write it to file
size = Ogre::PixelUtil::getMemorySize(width, height, 1,
static_cast<Ogre::PixelFormat>(this->imageFormat));
// Allocate buffer
if (!this->saveFrameBuffer)
this->saveFrameBuffer = new unsigned char[size];
memset(this->saveFrameBuffer, 128, size);
Ogre::PixelBox box(width, height, 1,
static_cast<Ogre::PixelFormat>(this->imageFormat),
this->saveFrameBuffer);
#if OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR < 8
// Case for UserCamera where there is no RenderTexture but
// a RenderTarget (RenderWindow) exists. We can not call SetRenderTarget
// because that overrides the this->renderTarget variable
if (this->renderTarget && !this->renderTexture)
{
// Create the render texture
this->renderTexture = (Ogre::TextureManager::getSingleton().createManual(
this->renderTarget->getName() + "_tex",
"General",
Ogre::TEX_TYPE_2D,
this->ImageWidth(),
this->ImageHeight(),
0,
(Ogre::PixelFormat)this->imageFormat,
Ogre::TU_RENDERTARGET)).getPointer();
Ogre::RenderTexture *rtt
= this->renderTexture->getBuffer()->getRenderTarget();
// Setup the viewport to use the texture
Ogre::Viewport *vp = rtt->addViewport(this->camera);
vp->setClearEveryFrame(true);
vp->setShadowsEnabled(true);
vp->setOverlaysEnabled(false);
}
// This update is only needed for client side data captures
if (this->renderTexture->getBuffer()->getRenderTarget()
!= this->renderTarget)
this->renderTexture->getBuffer()->getRenderTarget()->update();
// The code below is equivalent to
// this->viewport->getTarget()->copyContentsToMemory(box);
// which causes problems on some machines if running ogre-1.7.4
Ogre::HardwarePixelBufferSharedPtr pixelBuffer;
pixelBuffer = this->renderTexture->getBuffer();
pixelBuffer->blitToMemory(box);
#else
// There is a fix in ogre-1.8 for a buffer overrun problem in
// OgreGLXWindow.cpp's copyContentsToMemory(). It fixes reading
// pixels from buffer into memory.
this->viewport->getTarget()->copyContentsToMemory(box);
#endif
}
}
//////////////////////////////////////////////////
common::Time Camera::GetLastRenderWallTime()
{
return this->LastRenderWallTime();
}
//////////////////////////////////////////////////
common::Time Camera::LastRenderWallTime() const
{
return this->lastRenderWallTime;
}
//////////////////////////////////////////////////
void Camera::PostRender()
{
this->ReadPixelBuffer();
// Only record last render time if data was actually generated
// (If a frame was rendered).
if (this->newData)
this->lastRenderWallTime = common::Time::GetWallTime();
if (this->newData && (this->captureData || this->captureDataOnce))
{
if (this->captureDataOnce)
{
this->SaveFrame(this->FrameFilename());
this->captureDataOnce = false;
}
if (this->sdf->HasElement("save") &&
this->sdf->GetElement("save")->Get<bool>("enabled"))
{
this->SaveFrame(this->FrameFilename());
}
unsigned int width = this->ImageWidth();
unsigned int height = this->ImageHeight();
const unsigned char *buffer = this->saveFrameBuffer;
// do last minute conversion if Bayer pattern is requested, go from R8G8B8
if ((this->ImageFormat() == "BAYER_RGGB8") ||
(this->ImageFormat() == "BAYER_BGGR8") ||
(this->ImageFormat() == "BAYER_GBRG8") ||
(this->ImageFormat() == "BAYER_GRBG8"))
{
if (!this->bayerFrameBuffer)
this->bayerFrameBuffer = new unsigned char[width * height];
this->ConvertRGBToBAYER(this->bayerFrameBuffer,
this->saveFrameBuffer, this->ImageFormat(),
width, height);
buffer = this->bayerFrameBuffer;
}
this->newImageFrame(buffer, width, height, this->ImageDepth(),
this->ImageFormat());
}
this->newData = false;
}
//////////////////////////////////////////////////
math::Vector3 Camera::GetWorldPosition() const
{
return Conversions::Convert(this->sceneNode->_getDerivedPosition());
}
//////////////////////////////////////////////////
ignition::math::Vector3d Camera::WorldPosition() const
{
return Conversions::ConvertIgn(this->sceneNode->_getDerivedPosition());
}
//////////////////////////////////////////////////
math::Quaternion Camera::GetWorldRotation() const
{
Ogre::Quaternion rot = this->sceneNode->_getDerivedOrientation();
return math::Quaternion(rot.w, rot.x, rot.y, rot.z);
}
//////////////////////////////////////////////////
ignition::math::Quaterniond Camera::WorldRotation() const
{
Ogre::Quaternion rot = this->sceneNode->_getDerivedOrientation();
return ignition::math::Quaterniond(rot.w, rot.x, rot.y, rot.z);
}
//////////////////////////////////////////////////
void Camera::SetWorldPose(const math::Pose &_pose)
{
this->SetWorldPosition(_pose.pos.Ign());
this->SetWorldRotation(_pose.rot.Ign());
}
//////////////////////////////////////////////////
void Camera::SetWorldPose(const ignition::math::Pose3d &_pose)
{
this->SetWorldPosition(_pose.Pos());
this->SetWorldRotation(_pose.Rot());
}
//////////////////////////////////////////////////
math::Pose Camera::GetWorldPose() const
{
return WorldPose();
}
//////////////////////////////////////////////////
ignition::math::Pose3d Camera::WorldPose() const
{
return ignition::math::Pose3d(this->WorldPosition(), this->WorldRotation());
}
//////////////////////////////////////////////////
void Camera::SetWorldPosition(const math::Vector3 &_pos)
{
this->SetWorldPosition(_pos.Ign());
}
//////////////////////////////////////////////////
void Camera::SetWorldPosition(const ignition::math::Vector3d &_pos)
{
if (this->animState)
return;
this->sceneNode->_setDerivedPosition(Conversions::Convert(_pos));
this->sceneNode->needUpdate();
}
//////////////////////////////////////////////////
void Camera::SetWorldRotation(const math::Quaternion &_quat)
{
this->SetWorldRotation(_quat.Ign());
}
//////////////////////////////////////////////////
void Camera::SetWorldRotation(const ignition::math::Quaterniond &_quat)
{
if (this->animState)
return;
ignition::math::Vector3d rpy = _quat.Euler();
// Set the roll and yaw for sceneNode
ignition::math::Quaterniond s(rpy.X(), rpy.Y(), rpy.Z());
this->sceneNode->_setDerivedOrientation(Conversions::Convert(s));
this->sceneNode->needUpdate();
}
//////////////////////////////////////////////////
void Camera::Translate(const math::Vector3 &_direction)
{
this->Translate(_direction.Ign());
}
//////////////////////////////////////////////////
void Camera::Translate(const ignition::math::Vector3d &_direction)
{
this->sceneNode->translate(this->sceneNode->getOrientation() *
Conversions::Convert(_direction));
}
//////////////////////////////////////////////////
void Camera::Roll(const math::Angle &_angle,
Ogre::Node::TransformSpace _relativeTo)
{
this->Roll(_angle.Ign(), Conversions::Convert(_relativeTo));
}
//////////////////////////////////////////////////
void Camera::Roll(const ignition::math::Angle &_angle,
ReferenceFrame _relativeTo)
{
this->sceneNode->pitch(Ogre::Radian(_angle.Radian()),
Conversions::Convert(_relativeTo));
}
//////////////////////////////////////////////////
void Camera::Yaw(const math::Angle &_angle,
Ogre::Node::TransformSpace _relativeTo)
{
this->Yaw(_angle.Ign(), Conversions::Convert(_relativeTo));
}
//////////////////////////////////////////////////
void Camera::Yaw(const ignition::math::Angle &_angle,
ReferenceFrame _relativeTo)
{
this->sceneNode->roll(Ogre::Radian(_angle.Radian()),
Conversions::Convert(_relativeTo));
}
//////////////////////////////////////////////////
void Camera::Pitch(const math::Angle &_angle,
Ogre::Node::TransformSpace _relativeTo)
{
this->Pitch(_angle.Ign(), Conversions::Convert(_relativeTo));
}
//////////////////////////////////////////////////
void Camera::Pitch(const ignition::math::Angle &_angle,
ReferenceFrame _relativeTo)
{
this->sceneNode->yaw(Ogre::Radian(_angle.Radian()),
Conversions::Convert(_relativeTo));
}
//////////////////////////////////////////////////
void Camera::SetClipDist()
{
sdf::ElementPtr clipElem = this->sdf->GetElement("clip");
if (!clipElem)
gzthrow("Camera has no <clip> tag.");
if (this->camera)
{
this->camera->setNearClipDistance(clipElem->Get<double>("near"));
this->camera->setFarClipDistance(clipElem->Get<double>("far"));
this->camera->setRenderingDistance(clipElem->Get<double>("far"));
}
else
gzerr << "Setting clip distances failed -- no camera yet\n";
}
//////////////////////////////////////////////////
void Camera::SetClipDist(const float _near, const float _far)
{
sdf::ElementPtr elem = this->sdf->GetElement("clip");
elem->GetElement("near")->Set(_near);
elem->GetElement("far")->Set(_far);
this->SetClipDist();
}
//////////////////////////////////////////////////
void Camera::SetHFOV(math::Angle _angle)
{
this->SetHFOV(_angle.Ign());
}
//////////////////////////////////////////////////
void Camera::SetHFOV(const ignition::math::Angle &_angle)
{
this->sdf->GetElement("horizontal_fov")->Set(_angle.Radian());
this->UpdateFOV();
}
//////////////////////////////////////////////////
math::Angle Camera::GetHFOV() const
{
return math::Angle(this->sdf->Get<double>("horizontal_fov"));
}
//////////////////////////////////////////////////
ignition::math::Angle Camera::HFOV() const
{
return ignition::math::Angle(this->sdf->Get<double>("horizontal_fov"));
}
//////////////////////////////////////////////////
math::Angle Camera::GetVFOV() const
{
return math::Angle(this->camera->getFOVy().valueRadians());
}
//////////////////////////////////////////////////
ignition::math::Angle Camera::VFOV() const
{
return ignition::math::Angle(this->camera->getFOVy().valueRadians());
}
//////////////////////////////////////////////////
void Camera::SetImageSize(const unsigned int _w, const unsigned int _h)
{
this->SetImageWidth(_w);
this->SetImageHeight(_h);
}
//////////////////////////////////////////////////
void Camera::SetImageWidth(const unsigned int _w)
{
sdf::ElementPtr elem = this->sdf->GetElement("image");
elem->GetElement("width")->Set(_w);
}
//////////////////////////////////////////////////
void Camera::SetImageHeight(const unsigned int _h)
{
sdf::ElementPtr elem = this->sdf->GetElement("image");
elem->GetElement("height")->Set(_h);
}
//////////////////////////////////////////////////
unsigned int Camera::GetImageWidth() const
{
return this->ImageWidth();
}
//////////////////////////////////////////////////
unsigned int Camera::ImageWidth() const
{
unsigned int width = 0;
if (this->viewport)
{
width = this->viewport->getActualWidth();
}
else
{
sdf::ElementPtr elem = this->sdf->GetElement("image");
width = elem->Get<int>("width");
}
return width;
}
//////////////////////////////////////////////////
unsigned int Camera::GetImageHeight() const
{
return this->ImageHeight();
}
//////////////////////////////////////////////////
unsigned int Camera::ImageHeight() const
{
unsigned int height = 0;
if (this->viewport)
{
height = this->viewport->getActualHeight();
}
else
{
sdf::ElementPtr elem = this->sdf->GetElement("image");
height = elem->Get<int>("height");
}
return height;
}
//////////////////////////////////////////////////
unsigned int Camera::GetImageDepth() const
{
return this->ImageDepth();
}
//////////////////////////////////////////////////
unsigned int Camera::ImageDepth() const
{
sdf::ElementPtr imgElem = this->sdf->GetElement("image");
std::string imgFmt = imgElem->Get<std::string>("format");
if (imgFmt == "L8" || imgFmt == "L_INT8")
return 1;
else if (imgFmt == "L16" || imgFmt == "L_INT16" || imgFmt == "L_UINT16")
return 2;
else if (imgFmt == "R8G8B8" || imgFmt == "RGB_INT8")
return 3;
else if (imgFmt == "B8G8R8" || imgFmt == "BGR_INT8")
return 3;
else if (imgFmt == "R16G16B16" || imgFmt == "RGB_INT16"
|| imgFmt == "RGB_UINT16")
return 6;
else if ((imgFmt == "BAYER_RGGB8") || (imgFmt == "BAYER_BGGR8") ||
(imgFmt == "BAYER_GBRG8") || (imgFmt == "BAYER_GRBG8"))
return 1;
else
{
gzerr << "Error parsing image format ("
<< imgFmt << "), using default Ogre::PF_R8G8B8\n";
return 3;
}
}
//////////////////////////////////////////////////
unsigned int Camera::ImageMemorySize() const
{
return Ogre::PixelUtil::getMemorySize(this->ImageWidth(),
this->ImageHeight(), 1, static_cast<Ogre::PixelFormat>(
this->imageFormat));
}
//////////////////////////////////////////////////
std::string Camera::GetImageFormat() const
{
return this->ImageFormat();
}
//////////////////////////////////////////////////
std::string Camera::ImageFormat() const
{
sdf::ElementPtr imgElem = this->sdf->GetElement("image");
return imgElem->Get<std::string>("format");
}
//////////////////////////////////////////////////
unsigned int Camera::GetTextureWidth() const
{
return this->TextureWidth();
}
//////////////////////////////////////////////////
unsigned int Camera::TextureWidth() const
{
return this->renderTexture->getBuffer(0, 0)->getWidth();
}
//////////////////////////////////////////////////
unsigned int Camera::GetTextureHeight() const
{
return this->TextureHeight();
}
//////////////////////////////////////////////////
unsigned int Camera::TextureHeight() const
{
return this->renderTexture->getBuffer(0, 0)->getHeight();
}
//////////////////////////////////////////////////
size_t Camera::GetImageByteSize() const
{
return this->ImageByteSize();
}
//////////////////////////////////////////////////
size_t Camera::ImageByteSize() const
{
sdf::ElementPtr elem = this->sdf->GetElement("image");
return this->ImageByteSize(elem->Get<int>("width"),
elem->Get<int>("height"),
this->ImageFormat());
}
//////////////////////////////////////////////////
size_t Camera::GetImageByteSize(unsigned int _width, unsigned int _height,
const std::string &_format)
{
return ImageByteSize(_width, _height, _format);
}
//////////////////////////////////////////////////
size_t Camera::ImageByteSize(const unsigned int _width,
const unsigned int _height, const std::string &_format)
{
Ogre::PixelFormat fmt =
(Ogre::PixelFormat)(Camera::OgrePixelFormat(_format));
return Ogre::PixelUtil::getMemorySize(_width, _height, 1, fmt);
}
//////////////////////////////////////////////////
int Camera::OgrePixelFormat(const std::string &_format)
{
int result;
if (_format == "L8" || _format == "L_INT8")
result = static_cast<int>(Ogre::PF_L8);
else if (_format == "L16" || _format == "L_INT16" || _format == "L_UINT16")
result = static_cast<int>(Ogre::PF_L16);
else if (_format == "R8G8B8" || _format == "RGB_INT8")
result = static_cast<int>(Ogre::PF_BYTE_RGB);
else if (_format == "B8G8R8" || _format == "BGR_INT8")
result = static_cast<int>(Ogre::PF_BYTE_BGR);
else if (_format == "FLOAT32")
result = static_cast<int>(Ogre::PF_FLOAT32_R);
else if (_format == "FLOAT16")
result = static_cast<int>(Ogre::PF_FLOAT16_R);
else if (_format == "R16G16B16" || _format == "RGB_INT16"
|| _format == "RGB_UINT16")
result = static_cast<int>(Ogre::PF_SHORT_RGB);
else if ((_format == "BAYER_RGGB8") ||
(_format == "BAYER_BGGR8") ||
(_format == "BAYER_GBRG8") ||
(_format == "BAYER_GRBG8"))
{
// let ogre generate rgb8 images for all bayer format requests
// then post process to produce actual bayer images
result = static_cast<int>(Ogre::PF_BYTE_RGB);
}
else
{
gzerr << "Error parsing image format (" << _format
<< "), using default Ogre::PF_R8G8B8\n";
result = static_cast<int>(Ogre::PF_R8G8B8);
}
return result;
}
//////////////////////////////////////////////////
void Camera::EnableSaveFrame(const bool _enable)
{
sdf::ElementPtr elem = this->sdf->GetElement("save");
elem->GetAttribute("enabled")->Set(_enable);
this->captureData = _enable;
}
//////////////////////////////////////////////////
bool Camera::GetCaptureData() const
{
return this->CaptureData();
}
//////////////////////////////////////////////////
bool Camera::CaptureData() const
{
return this->captureData;
}
//////////////////////////////////////////////////
void Camera::SetSaveFramePathname(const std::string &_pathname)
{
sdf::ElementPtr elem = this->sdf->GetElement("save");
elem->GetElement("path")->Set(_pathname);
// Create the directory to store frames
if (elem->Get<bool>("enabled"))
{
std::string command;
command = "mkdir -p " + _pathname + " 2>>/dev/null";
if (system(command.c_str()) <0)
gzerr << "Error making directory\n";
}
}
//////////////////////////////////////////////////
Ogre::Camera *Camera::GetOgreCamera() const
{
return this->OgreCamera();
}
//////////////////////////////////////////////////
Ogre::Camera *Camera::OgreCamera() const
{
return this->camera;
}
//////////////////////////////////////////////////
Ogre::Viewport *Camera::GetViewport() const
{
return this->OgreViewport();
}
//////////////////////////////////////////////////
Ogre::Viewport *Camera::OgreViewport() const
{
return this->viewport;
}
//////////////////////////////////////////////////
double Camera::GetNearClip()
{
return this->NearClip();
}
//////////////////////////////////////////////////
double Camera::NearClip() const
{
if (this->camera)
return this->camera->getNearClipDistance();
else
return 0;
}
//////////////////////////////////////////////////
double Camera::GetFarClip()
{
return this->FarClip();
}
//////////////////////////////////////////////////
double Camera::FarClip() const
{
if (this->camera)
return this->camera->getFarClipDistance();
else
return 0;
}
//////////////////////////////////////////////////
unsigned int Camera::GetViewportWidth() const
{
return this->ViewportWidth();
}
//////////////////////////////////////////////////
unsigned int Camera::ViewportWidth() const
{
if (this->renderTarget)
return this->renderTarget->getViewport(0)->getActualWidth();
else if (this->camera && this->camera->getViewport())
return this->camera->getViewport()->getActualWidth();
else
return 0;
}
//////////////////////////////////////////////////
unsigned int Camera::GetViewportHeight() const
{
return this->ViewportHeight();
}
//////////////////////////////////////////////////
unsigned int Camera::ViewportHeight() const
{
if (this->renderTarget)
return this->renderTarget->getViewport(0)->getActualHeight();
else if (this->camera && this->camera->getViewport())
return this->camera->getViewport()->getActualHeight();
else
return 0;
}
//////////////////////////////////////////////////
void Camera::SetAspectRatio(const float ratio)
{
this->camera->setAspectRatio(ratio);
}
//////////////////////////////////////////////////
float Camera::GetAspectRatio() const
{
return this->AspectRatio();
}
//////////////////////////////////////////////////
float Camera::AspectRatio() const
{
return this->camera->getAspectRatio();
}
//////////////////////////////////////////////////
math::Vector3 Camera::GetUp()
{
Ogre::Vector3 up = this->camera->getRealUp();
return math::Vector3(up.x, up.y, up.z);
}
//////////////////////////////////////////////////
ignition::math::Vector3d Camera::Up() const
{
Ogre::Vector3 up = this->camera->getRealUp();
return ignition::math::Vector3d(up.x, up.y, up.z);
}
//////////////////////////////////////////////////
math::Vector3 Camera::GetRight()
{
Ogre::Vector3 right = this->camera->getRealRight();
return math::Vector3(right.x, right.y, right.z);
}
//////////////////////////////////////////////////
ignition::math::Vector3d Camera::Right() const
{
Ogre::Vector3 right = this->camera->getRealRight();
return ignition::math::Vector3d(right.x, right.y, right.z);
}
//////////////////////////////////////////////////
void Camera::SetSceneNode(Ogre::SceneNode *_node)
{
this->sceneNode = _node;
}
//////////////////////////////////////////////////
Ogre::SceneNode *Camera::GetSceneNode() const
{
return this->SceneNode();
}
//////////////////////////////////////////////////
Ogre::SceneNode *Camera::SceneNode() const
{
return this->sceneNode;
}
//////////////////////////////////////////////////
const unsigned char *Camera::GetImageData(unsigned int _i)
{
return this->ImageData(_i);
}
//////////////////////////////////////////////////
const unsigned char *Camera::ImageData(const unsigned int _i) const
{
if (_i != 0)
gzerr << "Camera index must be zero for cam";
// do last minute conversion if Bayer pattern is requested, go from R8G8B8
if ((this->ImageFormat() == "BAYER_RGGB8") ||
(this->ImageFormat() == "BAYER_BGGR8") ||
(this->ImageFormat() == "BAYER_GBRG8") ||
(this->ImageFormat() == "BAYER_GRBG8"))
{
return this->bayerFrameBuffer;
}
else
return this->saveFrameBuffer;
}
//////////////////////////////////////////////////
std::string Camera::GetName() const
{
return this->Name();
}
//////////////////////////////////////////////////
std::string Camera::Name() const
{
return this->name;
}
//////////////////////////////////////////////////
std::string Camera::GetScopedName() const
{
return this->ScopedName();
}
//////////////////////////////////////////////////
std::string Camera::ScopedName() const
{
return this->scopedName;
}
//////////////////////////////////////////////////
bool Camera::SaveFrame(const std::string &_filename)
{
return Camera::SaveFrame(this->saveFrameBuffer, this->ImageWidth(),
this->ImageHeight(), this->ImageDepth(),
this->ImageFormat(), _filename);
}
//////////////////////////////////////////////////
std::string Camera::GetFrameFilename()
{
return FrameFilename();
}
//////////////////////////////////////////////////
std::string Camera::FrameFilename()
{
sdf::ElementPtr saveElem = this->sdf->GetElement("save");
std::string path = saveElem->Get<std::string>("path");
boost::filesystem::path pathToFile;
std::string friendlyName = this->scopedUniqueName;
boost::replace_all(friendlyName, "::", "_");
if (this->captureDataOnce)
{
pathToFile = this->screenshotPath;
std::string timestamp = common::Time::GetWallTimeAsISOString();
boost::replace_all(timestamp, ":", "_");
pathToFile /= friendlyName + "-" + timestamp + ".jpg";
}
else
{
pathToFile = (path.empty()) ? "." : path;
pathToFile /= str(boost::format("%s-%04d.jpg")
% friendlyName.c_str() % this->saveCount);
this->saveCount++;
}
// Create a directory if not present
if (!boost::filesystem::exists(pathToFile.parent_path()))
boost::filesystem::create_directories(pathToFile.parent_path());
return pathToFile.string();
}
/////////////////////////////////////////////////
std::string Camera::GetScreenshotPath() const
{
return this->ScreenshotPath();
}
/////////////////////////////////////////////////
std::string Camera::ScreenshotPath() const
{
return this->screenshotPath;
}
/////////////////////////////////////////////////
bool Camera::SaveFrame(const unsigned char *_image,
const unsigned int _width, const unsigned int _height,
const int _depth,
const std::string &_format,
const std::string &_filename)
{
if (!_image)
{
gzerr << "Can't save an empty image\n";
return false;
}
Ogre::ImageCodec::ImageData *imgData;
Ogre::Codec * pCodec;
size_t size, pos;
// Create image data structure
imgData = new Ogre::ImageCodec::ImageData();
imgData->width = _width;
imgData->height = _height;
imgData->depth = _depth;
imgData->format = (Ogre::PixelFormat)Camera::OgrePixelFormat(_format);
size = Camera::ImageByteSize(_width, _height, _format);
// Wrap buffer in a chunk
Ogre::MemoryDataStreamPtr stream(
new Ogre::MemoryDataStream(const_cast<unsigned char*>(_image),
size, false));
// Get codec
Ogre::String filename = _filename;
pos = filename.find_last_of(".");
Ogre::String extension;
while (pos != filename.length() - 1)
extension += filename[++pos];
// Get the codec
pCodec = Ogre::Codec::getCodec(extension);
// Write out
Ogre::Codec::CodecDataPtr codecDataPtr(imgData);
// OGRE 1.9 renames codeToFile to encodeToFile
// Looks like 1.9RC, which we're using on Windows, doesn't have this change.
#if (OGRE_VERSION < ((1 << 16) | (9 << 8) | 0)) || defined(_WIN32)
pCodec->codeToFile(stream, filename, codecDataPtr);
#else
pCodec->encodeToFile(stream, filename, codecDataPtr);
#endif
return true;
}
//////////////////////////////////////////////////
void Camera::ToggleShowWireframe()
{
if (this->camera)
{
if (this->camera->getPolygonMode() == Ogre::PM_WIREFRAME)
this->camera->setPolygonMode(Ogre::PM_SOLID);
else
this->camera->setPolygonMode(Ogre::PM_WIREFRAME);
}
}
//////////////////////////////////////////////////
void Camera::ShowWireframe(const bool s)
{
if (this->camera)
{
if (s)
{
this->camera->setPolygonMode(Ogre::PM_WIREFRAME);
}
else
{
this->camera->setPolygonMode(Ogre::PM_SOLID);
}
}
}
//////////////////////////////////////////////////
void Camera::GetCameraToViewportRay(int _screenx, int _screeny,
math::Vector3 &_origin,
math::Vector3 &_dir)
{
Ogre::Ray ray = this->camera->getCameraToViewportRay(
static_cast<float>(_screenx) / this->ViewportWidth(),
static_cast<float>(_screeny) / this->ViewportHeight());
_origin.Set(ray.getOrigin().x, ray.getOrigin().y, ray.getOrigin().z);
_dir.Set(ray.getDirection().x, ray.getDirection().y, ray.getDirection().z);
}
//////////////////////////////////////////////////
void Camera::CameraToViewportRay(const int _screenx, const int _screeny,
ignition::math::Vector3d &_origin,
ignition::math::Vector3d &_dir) const
{
Ogre::Ray ray = this->camera->getCameraToViewportRay(
static_cast<float>(_screenx) / this->ViewportWidth(),
static_cast<float>(_screeny) / this->ViewportHeight());
_origin.Set(ray.getOrigin().x, ray.getOrigin().y, ray.getOrigin().z);
_dir.Set(ray.getDirection().x, ray.getDirection().y, ray.getDirection().z);
}
//////////////////////////////////////////////////
void Camera::ConvertRGBToBAYER(unsigned char *_dst,
const unsigned char *_src, const std::string &_format, const int _width,
const int _height)
{
if (_src)
{
// do last minute conversion if Bayer pattern is requested, go from R8G8B8
if (_format == "BAYER_RGGB8")
{
for (int i = 0; i < _width; i++)
{
for (int j = 0; j < _height; j++)
{
//
// RG
// GB
//
// determine position
if (j%2) // even column
if (i%2) // even row, red
_dst[i+j*_width] = _src[i*3+j*_width*3+2];
else // odd row, green
_dst[i+j*_width] = _src[i*3+j*_width*3+1];
else // odd column
if (i%2) // even row, green
_dst[i+j*_width] = _src[i*3+j*_width*3+1];
else // odd row, blue
_dst[i+j*_width] = _src[i*3+j*_width*3+0];
}
}
}
else if (_format == "BAYER_BGGR8")
{
for (int i = 0; i < _width; i++)
{
for (int j = 0; j < _height; j++)
{
//
// BG
// GR
//
// determine position
if (j%2) // even column
if (i%2) // even row, blue
_dst[i+j*_width] = _src[i*3+j*_width*3+0];
else // odd row, green
_dst[i+j*_width] = _src[i*3+j*_width*3+1];
else // odd column
if (i%2) // even row, green
_dst[i+j*_width] = _src[i*3+j*_width*3+1];
else // odd row, red
_dst[i+j*_width] = _src[i*3+j*_width*3+2];
}
}
}
else if (_format == "BAYER_GBRG8")
{
for (int i = 0; i < _width; i++)
{
for (int j = 0; j < _height; j++)
{
//
// GB
// RG
//
// determine position
if (j%2) // even column
if (i%2) // even row, green
_dst[i+j*_width] = _src[i*3+j*_width*3+1];
else // odd row, blue
_dst[i+j*_width] = _src[i*3+j*_width*3+2];
else // odd column
if (i%2) // even row, red
_dst[i+j*_width] = _src[i*3+j*_width*3+0];
else // odd row, green
_dst[i+j*_width] = _src[i*3+j*_width*3+1];
}
}
}
else if (_format == "BAYER_GRBG8")
{
for (int i = 0; i < _width; i++)
{
for (int j = 0; j < _height; j++)
{
//
// GR
// BG
//
// determine position
if (j%2) // even column
if (i%2) // even row, green
_dst[i+j*_width] = _src[i*3+j*_width*3+1];
else // odd row, red
_dst[i+j*_width] = _src[i*3+j*_width*3+0];
else // odd column
if (i%2) // even row, blue
_dst[i+j*_width] = _src[i*3+j*_width*3+2];
else // odd row, green
_dst[i+j*_width] = _src[i*3+j*_width*3+1];
}
}
}
}
}
//////////////////////////////////////////////////
void Camera::SetCaptureData(const bool _value)
{
this->captureData = _value;
}
//////////////////////////////////////////////////
void Camera::SetCaptureDataOnce()
{
this->captureDataOnce = true;
}
//////////////////////////////////////////////////
void Camera::CreateRenderTexture(const std::string &_textureName)
{
unsigned int fsaa = 0;
std::vector<unsigned int> fsaaLevels =
RenderEngine::Instance()->FSAALevels();
// check if target fsaa is supported
unsigned int targetFSAA = 4;
auto const it = std::find(fsaaLevels.begin(), fsaaLevels.end(), targetFSAA);
if (it != fsaaLevels.end())
fsaa = targetFSAA;
// Full-screen anti-aliasing only works correctly in 1.8 and above
#if OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR < 8
fsaa = 0;
#endif
// Create the render texture
this->renderTexture = (Ogre::TextureManager::getSingleton().createManual(
_textureName,
"General",
Ogre::TEX_TYPE_2D,
this->ImageWidth(),
this->ImageHeight(),
0,
static_cast<Ogre::PixelFormat>(this->imageFormat),
Ogre::TU_RENDERTARGET,
0,
false,
fsaa)).getPointer();
this->SetRenderTarget(this->renderTexture->getBuffer()->getRenderTarget());
this->initialized = true;
}
//////////////////////////////////////////////////
ScenePtr Camera::GetScene() const
{
return this->scene;
}
//////////////////////////////////////////////////
void Camera::CreateCamera()
{
this->camera = this->scene->OgreSceneManager()->createCamera(
this->scopedUniqueName);
if (this->sdf->HasElement("projection_type"))
this->SetProjectionType(this->sdf->Get<std::string>("projection_type"));
this->camera->setFixedYawAxis(false);
this->camera->yaw(Ogre::Degree(-90.0));
this->camera->roll(Ogre::Degree(-90.0));
}
//////////////////////////////////////////////////
bool Camera::GetWorldPointOnPlane(int _x, int _y,
const math::Plane &_plane,
math::Vector3 &_result)
{
#ifndef _WIN32
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
math::Vector3 origin, dir;
double dist;
// Cast two rays from the camera into the world
this->GetCameraToViewportRay(_x, _y, origin, dir);
dist = _plane.Distance(origin, dir);
_result = origin + dir * dist;
if (!math::equal(dist, -1.0))
return true;
else
return false;
#ifndef _WIN32
#pragma GCC diagnostic pop
#endif
}
//////////////////////////////////////////////////
bool Camera::WorldPointOnPlane(const int _x, const int _y,
const ignition::math::Planed &_plane,
ignition::math::Vector3d &_result)
{
ignition::math::Vector3d origin, dir;
double dist;
// Cast two rays from the camera into the world
this->CameraToViewportRay(_x, _y, origin, dir);
dist = _plane.Distance(origin, dir);
_result = origin + dir * dist;
if (!ignition::math::equal(dist, -1.0))
return true;
else
return false;
}
//////////////////////////////////////////////////
void Camera::SetRenderTarget(Ogre::RenderTarget *_target)
{
this->renderTarget = _target;
if (this->renderTarget)
{
// Setup the viewport to use the texture
this->viewport = this->renderTarget->addViewport(this->camera);
this->viewport->setClearEveryFrame(true);
this->viewport->setShadowsEnabled(true);
this->viewport->setOverlaysEnabled(false);
if (this->camera->getProjectionType() == Ogre::PT_ORTHOGRAPHIC)
this->scene->SetShadowsEnabled(false);
RTShaderSystem::AttachViewport(this->viewport, this->GetScene());
this->viewport->setBackgroundColour(
Conversions::Convert(this->scene->BackgroundColor()));
this->viewport->setVisibilityMask(GZ_VISIBILITY_ALL &
~(GZ_VISIBILITY_GUI | GZ_VISIBILITY_SELECTABLE));
this->UpdateFOV();
// Setup Deferred rendering for the camera
if (RenderEngine::Instance()->GetRenderPathType() == RenderEngine::DEFERRED)
{
// Deferred shading GBuffer compositor
this->dataPtr->dsGBufferInstance =
Ogre::CompositorManager::getSingleton().addCompositor(this->viewport,
"DeferredShading/GBuffer");
// Deferred lighting GBuffer compositor
this->dataPtr->dlGBufferInstance =
Ogre::CompositorManager::getSingleton().addCompositor(this->viewport,
"DeferredLighting/GBuffer");
// Deferred shading: Merging compositor
this->dataPtr->dsMergeInstance =
Ogre::CompositorManager::getSingleton().addCompositor(this->viewport,
"DeferredShading/ShowLit");
// Deferred lighting: Merging compositor
this->dataPtr->dlMergeInstance =
Ogre::CompositorManager::getSingleton().addCompositor(this->viewport,
"DeferredLighting/ShowLit");
// Screen space ambient occlusion
// this->dataPtr->this->ssaoInstance =
// Ogre::CompositorManager::getSingleton().addCompositor(this->viewport,
// "DeferredShading/SSAO");
this->dataPtr->dsGBufferInstance->setEnabled(false);
this->dataPtr->dsMergeInstance->setEnabled(false);
this->dataPtr->dlGBufferInstance->setEnabled(true);
this->dataPtr->dlMergeInstance->setEnabled(true);
// this->dataPtr->this->ssaoInstance->setEnabled(false);
}
if (this->dataPtr->distortion)
this->dataPtr->distortion->SetCamera(shared_from_this());
if (this->GetScene()->GetSkyX() != NULL)
this->renderTarget->addListener(this->GetScene()->GetSkyX());
}
}
//////////////////////////////////////////////////
void Camera::AttachToVisual(const uint32_t _visualId,
const bool _inheritOrientation,
const double _minDist, const double _maxDist)
{
msgs::Request request;
msgs::TrackVisual track;
track.set_name(this->Name() + "_attach_to_visual_track");
track.set_id(_visualId);
track.set_min_dist(_minDist);
track.set_max_dist(_maxDist);
track.set_inherit_orientation(_inheritOrientation);
std::string *serializedData = request.mutable_data();
track.SerializeToString(serializedData);
request.set_request("attach_visual");
request.set_id(_visualId);
this->requests.push_back(request);
}
//////////////////////////////////////////////////
void Camera::AttachToVisual(const std::string &_visualName,
const bool _inheritOrientation,
const double _minDist, const double _maxDist)
{
msgs::Request request;
msgs::TrackVisual track;
VisualPtr visual = this->scene->GetVisual(_visualName);
if (visual)
track.set_id(visual->GetId());
else
{
gzerr << "Unable to attach to visual with name[" << _visualName << "]\n";
track.set_id(GZ_UINT32_MAX);
}
track.set_name(_visualName);
track.set_min_dist(_minDist);
track.set_max_dist(_maxDist);
track.set_inherit_orientation(_inheritOrientation);
std::string *serializedData = request.mutable_data();
track.SerializeToString(serializedData);
request.set_request("attach_visual");
request.set_id(0);
this->requests.push_back(request);
}
//////////////////////////////////////////////////
void Camera::TrackVisual(const std::string &_name)
{
msgs::Request request;
request.set_request("track_visual");
request.set_data(_name);
request.set_id(0);
this->requests.push_back(request);
}
//////////////////////////////////////////////////
bool Camera::AttachToVisualImpl(const uint32_t _id,
const bool _inheritOrientation, const double _minDist,
const double _maxDist)
{
VisualPtr visual = this->scene->GetVisual(_id);
return this->AttachToVisualImpl(visual, _inheritOrientation,
_minDist, _maxDist);
}
//////////////////////////////////////////////////
bool Camera::AttachToVisualImpl(const std::string &_name,
const bool _inheritOrientation, const double _minDist,
const double _maxDist)
{
VisualPtr visual = this->scene->GetVisual(_name);
return this->AttachToVisualImpl(visual, _inheritOrientation,
_minDist, _maxDist);
}
//////////////////////////////////////////////////
bool Camera::AttachToVisualImpl(VisualPtr _visual,
const bool _inheritOrientation,
const double /*_minDist*/, const double /*_maxDist*/)
{
if (this->sceneNode->getParent())
this->sceneNode->getParent()->removeChild(this->sceneNode);
if (_visual)
{
_visual->GetSceneNode()->addChild(this->sceneNode);
this->sceneNode->setInheritOrientation(_inheritOrientation);
return true;
}
return false;
}
//////////////////////////////////////////////////
bool Camera::TrackVisualImpl(const std::string &_name)
{
VisualPtr visual = this->scene->GetVisual(_name);
if (visual)
return this->TrackVisualImpl(visual);
else
this->dataPtr->trackedVisual.reset();
if (_name.empty())
return true;
return false;
}
//////////////////////////////////////////////////
bool Camera::TrackVisualImpl(VisualPtr _visual)
{
// if (this->sceneNode->getParent())
// this->sceneNode->getParent()->removeChild(this->sceneNode);
bool result = false;
if (_visual)
{
this->dataPtr->trackVisualPID.Init(0.25, 0, 0, 0, 0, 1.0, 0.0);
this->dataPtr->trackVisualPitchPID.Init(0.05, 0, 0, 0, 0, 1.0, 0.0);
this->dataPtr->trackVisualYawPID.Init(0.05, 0, 0, 0, 0, 1.0, 0.0);
this->dataPtr->trackedVisual = _visual;
result = true;
}
else
{
this->dataPtr->trackedVisual.reset();
}
return result;
}
//////////////////////////////////////////////////
Ogre::Texture *Camera::GetRenderTexture() const
{
return this->RenderTexture();
}
//////////////////////////////////////////////////
Ogre::Texture *Camera::RenderTexture() const
{
return this->renderTexture;
}
/////////////////////////////////////////////////
math::Vector3 Camera::GetDirection() const
{
return this->Direction();
}
/////////////////////////////////////////////////
ignition::math::Vector3d Camera::Direction() const
{
return Conversions::ConvertIgn(this->camera->getDerivedDirection());
}
/////////////////////////////////////////////////
bool Camera::IsVisible(VisualPtr _visual)
{
if (this->camera && _visual)
{
ignition::math::Box bbox = _visual->GetBoundingBox().Ign();
Ogre::AxisAlignedBox box;
box.setMinimum(bbox.Min().X(), bbox.Min().Y(), bbox.Min().Z());
box.setMaximum(bbox.Max().X(), bbox.Max().Y(), bbox.Max().Z());
box.transformAffine(_visual->GetSceneNode()->_getFullTransform());
return this->camera->isVisible(box);
}
return false;
}
/////////////////////////////////////////////////
bool Camera::IsVisible(const std::string &_visualName)
{
return this->IsVisible(this->scene->GetVisual(_visualName));
}
/////////////////////////////////////////////////
bool Camera::IsAnimating() const
{
return this->animState != NULL;
}
/////////////////////////////////////////////////
bool Camera::MoveToPosition(const math::Pose &_pose, const double _time)
{
return this->MoveToPosition(_pose.Ign(), _time);
}
/////////////////////////////////////////////////
bool Camera::MoveToPosition(const ignition::math::Pose3d &_pose,
const double _time)
{
if (this->animState)
{
this->dataPtr->moveToPositionQueue.push_back(std::make_pair(_pose, _time));
return false;
}
Ogre::TransformKeyFrame *key;
ignition::math::Vector3d rpy = _pose.Rot().Euler();
ignition::math::Vector3d start = this->WorldPose().Pos();
Ogre::Quaternion localRotOgre = this->sceneNode->getOrientation();
ignition::math::Quaterniond localRot = ignition::math::Quaterniond(
localRotOgre.w, localRotOgre.x, localRotOgre.y, localRotOgre.z);
double dyaw = localRot.Euler().Z() - rpy.Z();
if (dyaw > M_PI)
rpy.Z() += 2*M_PI;
else if (dyaw < -M_PI)
rpy.Z() -= 2*M_PI;
ignition::math::Quaterniond pitchYawOnly(0, rpy.Y(), rpy.Z());
Ogre::Quaternion pitchYawFinal(pitchYawOnly.W(), pitchYawOnly.X(),
pitchYawOnly.Y(), pitchYawOnly.Z());
std::string trackName = "cameratrack";
int i = 0;
while (this->scene->OgreSceneManager()->hasAnimation(trackName))
{
trackName = std::string("cameratrack_") +
boost::lexical_cast<std::string>(i);
i++;
}
Ogre::Animation *anim =
this->scene->OgreSceneManager()->createAnimation(trackName, _time);
anim->setInterpolationMode(Ogre::Animation::IM_SPLINE);
Ogre::NodeAnimationTrack *strack = anim->createNodeTrack(0, this->sceneNode);
key = strack->createNodeKeyFrame(0);
key->setTranslate(Ogre::Vector3(start.X(), start.Y(), start.Z()));
key->setRotation(this->sceneNode->getOrientation());
key = strack->createNodeKeyFrame(_time);
key->setTranslate(Ogre::Vector3(_pose.Pos().X(), _pose.Pos().Y(),
_pose.Pos().Z()));
key->setRotation(pitchYawFinal);
this->animState =
this->scene->OgreSceneManager()->createAnimationState(trackName);
this->animState->setTimePosition(0);
this->animState->setEnabled(true);
this->animState->setLoop(false);
this->prevAnimTime = common::Time::GetWallTime();
return true;
}
/////////////////////////////////////////////////
bool Camera::MoveToPositions(const std::vector<math::Pose> &_pts,
const double _time,
std::function<void()> _onComplete)
{
std::vector<ignition::math::Pose3d> pts;
for (auto const p : _pts)
pts.push_back(p.Ign());
return this->MoveToPositions(pts, _time, _onComplete);
}
/////////////////////////////////////////////////
bool Camera::MoveToPositions(const std::vector<ignition::math::Pose3d> &_pts,
const double _time,
std::function<void()> _onComplete)
{
if (this->animState)
return false;
this->onAnimationComplete = _onComplete;
Ogre::TransformKeyFrame *key;
ignition::math::Vector3d start = this->WorldPose().Pos();
std::string trackName = "cameratrack";
int i = 0;
while (this->scene->OgreSceneManager()->hasAnimation(trackName))
{
trackName = std::string("cameratrack_") +
boost::lexical_cast<std::string>(i);
i++;
}
Ogre::Animation *anim =
this->scene->OgreSceneManager()->createAnimation(trackName, _time);
anim->setInterpolationMode(Ogre::Animation::IM_SPLINE);
Ogre::NodeAnimationTrack *strack = anim->createNodeTrack(0, this->sceneNode);
key = strack->createNodeKeyFrame(0);
key->setTranslate(Ogre::Vector3(start.X(), start.Y(), start.Z()));
key->setRotation(this->sceneNode->getOrientation());
double dt = _time / (_pts.size()-1);
double tt = 0;
Ogre::Quaternion localRotOgre = this->sceneNode->getOrientation();
ignition::math::Quaterniond localRot = ignition::math::Quaterniond(
localRotOgre.w, localRotOgre.x, localRotOgre.y, localRotOgre.z);
double prevYaw = localRot.Euler().Z();
for (unsigned int j = 0; j < _pts.size(); j++)
{
ignition::math::Vector3d pos = _pts[j].Pos();
ignition::math::Vector3d rpy = _pts[j].Rot().Euler();
double dyaw = prevYaw - rpy.Z();
if (dyaw > M_PI)
rpy.Z() += 2*M_PI;
else if (dyaw < -M_PI)
rpy.Z() -= 2*M_PI;
prevYaw = rpy.Z();
ignition::math::Quaterniond pitchYawOnly(0, rpy.Y(), rpy.Z());
Ogre::Quaternion pitchYawFinal(pitchYawOnly.W(), pitchYawOnly.X(),
pitchYawOnly.Y(), pitchYawOnly.Z());
key = strack->createNodeKeyFrame(tt);
key->setTranslate(Ogre::Vector3(pos.X(), pos.Y(), pos.Z()));
key->setRotation(pitchYawFinal);
tt += dt;
}
this->animState =
this->scene->OgreSceneManager()->createAnimationState(trackName);
this->animState->setTimePosition(0);
this->animState->setEnabled(true);
this->animState->setLoop(false);
this->prevAnimTime = common::Time::GetWallTime();
return true;
}
//////////////////////////////////////////////////
void Camera::SetRenderRate(const double _hz)
{
if (_hz > 0.0)
this->dataPtr->renderPeriod = 1.0 / _hz;
else
this->dataPtr->renderPeriod = 0.0;
}
//////////////////////////////////////////////////
double Camera::GetRenderRate() const
{
return this->RenderRate();
}
//////////////////////////////////////////////////
double Camera::RenderRate() const
{
return 1.0 / this->dataPtr->renderPeriod.Double();
}
//////////////////////////////////////////////////
void Camera::AnimationComplete()
{
}
//////////////////////////////////////////////////
bool Camera::GetInitialized() const
{
return this->Initialized();
}
//////////////////////////////////////////////////
bool Camera::Initialized() const
{
return this->initialized && this->scene->Initialized();
}
//////////////////////////////////////////////////
void Camera::OnCmdMsg(ConstCameraCmdPtr &_msg)
{
std::lock_guard<std::mutex> lock(this->dataPtr->receiveMutex);
this->dataPtr->commandMsgs.push_back(_msg);
}
//////////////////////////////////////////////////
DistortionPtr Camera::GetDistortion() const
{
return this->dataPtr->distortion;
}
//////////////////////////////////////////////////
DistortionPtr Camera::LensDistortion() const
{
return this->dataPtr->distortion;
}
//////////////////////////////////////////////////
void Camera::UpdateFOV()
{
if (this->viewport)
{
this->viewport->setDimensions(0, 0, 1, 1);
double ratio = static_cast<double>(this->viewport->getActualWidth()) /
static_cast<double>(this->viewport->getActualHeight());
double hfov = this->HFOV().Radian();
double vfov = 2.0 * atan(tan(hfov / 2.0) / ratio);
this->camera->setAspectRatio(ratio);
this->camera->setFOVy(Ogre::Radian(vfov));
}
}
//////////////////////////////////////////////////
float Camera::GetAvgFPS() const
{
return this->AvgFPS();
}
//////////////////////////////////////////////////
float Camera::AvgFPS() const
{
if (this->renderTarget)
return this->renderTarget->getAverageFPS();
else
return 0.0f;
}
//////////////////////////////////////////////////
unsigned int Camera::GetTriangleCount() const
{
return this->TriangleCount();
}
//////////////////////////////////////////////////
unsigned int Camera::TriangleCount() const
{
return this->renderTarget->getTriangleCount();
}
//////////////////////////////////////////////////
bool Camera::SetProjectionType(const std::string &_type)
{
bool result = true;
if (_type == "orthographic")
{
// Shadows do not work properly with orthographic projection
this->scene->SetShadowsEnabled(false);
this->camera->setProjectionType(Ogre::PT_ORTHOGRAPHIC);
}
else if (_type == "perspective")
{
this->camera->setProjectionType(Ogre::PT_PERSPECTIVE);
this->camera->setCustomProjectionMatrix(false);
this->scene->SetShadowsEnabled(true);
}
else
{
gzerr << "Invalid projection type[" << _type << "]. "
<< "Valid values are 'perspective' and 'orthographic'.\n";
result = false;
}
return result;
}
//////////////////////////////////////////////////
std::string Camera::GetProjectionType() const
{
return this->ProjectionType();
}
//////////////////////////////////////////////////
std::string Camera::ProjectionType() const
{
if (this->camera->getProjectionType() == Ogre::PT_ORTHOGRAPHIC)
{
return "orthographic";
}
// There are only two types of projection in OGRE.
else
{
return "perspective";
}
}
//////////////////////////////////////////////////
ignition::math::Matrix4d Camera::ProjectionMatrix() const
{
return Conversions::ConvertIgn(this->camera->getProjectionMatrix());
}
//////////////////////////////////////////////////
event::ConnectionPtr Camera::ConnectNewImageFrame(
std::function<void (const unsigned char *, unsigned int, unsigned int,
unsigned int, const std::string &)> _subscriber)
{
return this->newImageFrame.Connect(_subscriber);
}
//////////////////////////////////////////////////
void Camera::DisconnectNewImageFrame(event::ConnectionPtr &_c)
{
this->newImageFrame.Disconnect(_c);
}
/////////////////////////////////////////////////
ignition::math::Vector2i Camera::Project(
const ignition::math::Vector3d &_pt) const
{
// Convert from 3D world pos to 2D screen pos
Ogre::Vector3 pos = this->OgreCamera()->getProjectionMatrix() *
this->OgreCamera()->getViewMatrix() * Conversions::Convert(_pt);
ignition::math::Vector2i screenPos;
screenPos.X() = ((pos.x / 2.0) + 0.5) * this->ViewportWidth();
screenPos.Y() = (1 - ((pos.y / 2.0) + 0.5)) * this->ViewportHeight();
return screenPos;
}