Created
September 16, 2016 06:17
-
-
Save safijari/937e7ee4baa9ac96de637ce4bc9134f7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2012-2014 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 <dirent.h> | |
#include <sstream> | |
#include <boost/filesystem.hpp> | |
// 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/Camera.hh" | |
using namespace gazebo; | |
using namespace rendering; | |
unsigned int Camera::cameraCounter = 0; | |
namespace gazebo | |
{ | |
namespace rendering | |
{ | |
// We'll create an instance of this class for each camera, to be used to inject | |
// random values on each render call. | |
class GaussianNoiseCompositorListener | |
: public Ogre::CompositorInstance::Listener | |
{ | |
/// \brief Constructor, setting mean and standard deviation. | |
public: GaussianNoiseCompositorListener(double _mean, double _stddev): | |
mean(_mean), stddev(_stddev) {} | |
/// \brief Callback that OGRE will invoke for us on each render call | |
public: virtual void notifyMaterialRender(unsigned int _pass_id, | |
Ogre::MaterialPtr & _mat) | |
{ | |
// modify material here (wont alter the base material!), called for | |
// every drawn geometry instance (i.e. compositor render_quad) | |
// Sample three values within the range [0,1.0] and set them for use in | |
// the fragment shader, which will interpret them as offsets from (0,0) | |
// to use when computing pseudo-random values. | |
Ogre::Vector3 offsets(math::Rand::GetDblUniform(0.0, 1.0), | |
math::Rand::GetDblUniform(0.0, 1.0), | |
math::Rand::GetDblUniform(0.0, 1.0)); | |
// These calls are setting parameters that are declared in two places: | |
// 1. media/materials/scripts/gazebo.material, in | |
// fragment_program Gazebo/GaussianCameraNoiseFS | |
// 2. media/materials/scripts/camera_noise_gaussian_fs.glsl | |
_mat->getTechnique(0)->getPass(_pass_id)-> | |
getFragmentProgramParameters()-> | |
setNamedConstant("offsets", offsets); | |
_mat->getTechnique(0)->getPass(_pass_id)-> | |
getFragmentProgramParameters()-> | |
setNamedConstant("mean", (Ogre::Real)this->mean); | |
_mat->getTechnique(0)->getPass(_pass_id)-> | |
getFragmentProgramParameters()-> | |
setNamedConstant("stddev", (Ogre::Real)this->stddev); | |
} | |
/// \brief Mean that we'll pass down to the GLSL fragment shader. | |
private: double mean; | |
/// \brief Standard deviation that we'll pass down to the GLSL fragment | |
/// shader. | |
private: double stddev; | |
}; | |
} // namespace rendering | |
} // namespace gazebo | |
////////////////////////////////////////////////// | |
Camera::Camera(const std::string &_namePrefix, ScenePtr _scene, | |
bool _autoRender) | |
{ | |
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; | |
std::ostringstream stream; | |
stream << _namePrefix << "(" << this->cameraCounter++ << ")"; | |
this->name = stream.str(); | |
this->renderTarget = NULL; | |
this->renderTexture = NULL; | |
this->captureData = false; | |
this->captureDataOnce = false; | |
this->camera = NULL; | |
this->viewport = NULL; | |
this->pitchNode = NULL; | |
this->sceneNode = NULL; | |
this->screenshotPath = getenv("HOME"); | |
this->screenshotPath += "/.gazebo/pictures"; | |
// Connect to the render signal | |
this->connections.push_back( | |
event::Events::ConnectPostRender(boost::bind(&Camera::Update, this))); | |
if (_autoRender) | |
{ | |
this->connections.push_back(event::Events::ConnectRender( | |
boost::bind(&Camera::Render, this, false))); | |
this->connections.push_back( | |
event::Events::ConnectPostRender( | |
boost::bind(&Camera::PostRender, this))); | |
} | |
this->lastRenderWallTime = common::Time::GetWallTime(); | |
// Set default render rate to unlimited | |
this->SetRenderRate(0.0); | |
} | |
////////////////////////////////////////////////// | |
Camera::~Camera() | |
{ | |
delete [] this->saveFrameBuffer; | |
delete [] this->bayerFrameBuffer; | |
this->pitchNode = NULL; | |
this->sceneNode = NULL; | |
if (this->renderTexture && this->scene->GetInitialized()) | |
Ogre::TextureManager::getSingleton().remove(this->renderTexture->getName()); | |
this->renderTexture = NULL; | |
this->renderTarget = NULL; | |
if (this->camera && this->scene && this->scene->GetManager()) | |
{ | |
this->scene->GetManager()->destroyCamera(this->name); | |
this->camera = NULL; | |
} | |
this->connections.clear(); | |
this->sdf->Reset(); | |
this->imageElem.reset(); | |
this->sdf.reset(); | |
} | |
////////////////////////////////////////////////// | |
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->GetOgrePixelFormat( | |
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"); | |
double angle = elem->Get<double>(); | |
if (angle < 0.01 || angle > M_PI) | |
{ | |
gzthrow("Camera horizontal field of view invalid."); | |
} | |
this->SetHFOV(angle); | |
} | |
// Handle noise model settings. | |
this->noiseActive = false; | |
if (this->sdf->HasElement("noise")) | |
{ | |
sdf::ElementPtr noiseElem = this->sdf->GetElement("noise"); | |
std::string type = noiseElem->Get<std::string>("type"); | |
if (type == "gaussian") | |
{ | |
this->noiseType = GAUSSIAN; | |
this->noiseMean = noiseElem->Get<double>("mean"); | |
this->noiseStdDev = noiseElem->Get<double>("stddev"); | |
this->noiseActive = true; | |
this->gaussianNoiseCompositorListener.reset(new | |
GaussianNoiseCompositorListener(this->noiseMean, this->noiseStdDev)); | |
gzlog << "applying Gaussian noise model with mean " << this->noiseMean << | |
" and stddev " << this->noiseStdDev << std::endl; | |
} | |
else | |
gzwarn << "ignoring unknown noise model type \"" << type << "\"" << | |
std::endl; | |
} | |
} | |
////////////////////////////////////////////////// | |
void Camera::Init() | |
{ | |
this->SetSceneNode( | |
this->scene->GetManager()->getRootSceneNode()->createChildSceneNode( | |
this->GetName() + "_SceneNode")); | |
this->CreateCamera(); | |
// Create a scene node to control pitch motion | |
this->sceneNode->attachObject(this->camera); | |
this->camera->setAutoAspectRatio(true); | |
this->sceneNode->setInheritScale(false); | |
this->saveCount = 0; | |
this->SetClipDist(); | |
} | |
////////////////////////////////////////////////// | |
void Camera::Fini() | |
{ | |
this->initialized = false; | |
this->connections.clear(); | |
if (this->gaussianNoiseCompositorListener) | |
{ | |
this->gaussianNoiseInstance->removeListener( | |
this->gaussianNoiseCompositorListener.get()); | |
} | |
RTShaderSystem::DetachViewport(this->viewport, this->scene); | |
if (this->renderTarget && this->scene->GetInitialized()) | |
this->renderTarget->removeAllViewports(); | |
this->viewport = NULL; | |
this->renderTarget = NULL; | |
this->connections.clear(); | |
} | |
////////////////////////////////////////////////// | |
void Camera::SetWindowId(unsigned int windowId_) | |
{ | |
this->windowId = windowId_; | |
} | |
////////////////////////////////////////////////// | |
unsigned int Camera::GetWindowId() const | |
{ | |
return this->windowId; | |
} | |
////////////////////////////////////////////////// | |
void Camera::SetScene(ScenePtr _scene) | |
{ | |
this->scene = _scene; | |
} | |
////////////////////////////////////////////////// | |
void Camera::Update() | |
{ | |
std::list<msgs::Request>::iterator iter = this->requests.begin(); | |
while (iter != this->requests.end()) | |
{ | |
bool erase = false; | |
if ((*iter).request() == "track_visual") | |
{ | |
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) | |
{ | |
this->animState->addTime( | |
(common::Time::GetWallTime() - this->prevAnimTime).Double()); | |
this->prevAnimTime = common::Time::GetWallTime(); | |
if (this->animState->hasEnded()) | |
{ | |
try | |
{ | |
this->scene->GetManager()->destroyAnimation( | |
std::string(this->animState->getAnimationName())); | |
} catch(Ogre::Exception &_e) | |
{ | |
} | |
this->animState = NULL; | |
this->AnimationComplete(); | |
if (this->onAnimationComplete) | |
this->onAnimationComplete(); | |
if (!this->moveToPositionQueue.empty()) | |
{ | |
this->MoveToPosition(this->moveToPositionQueue[0].first, | |
this->moveToPositionQueue[0].second); | |
this->moveToPositionQueue.pop_front(); | |
} | |
} | |
} | |
else if (this->trackedVisual) | |
{ | |
math::Vector3 direction = this->trackedVisual->GetWorldPose().pos - | |
this->GetWorldPose().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(); | |
math::Quaternion localRot = math::Quaternion( | |
localRotOgre.w, localRotOgre.x, localRotOgre.y, localRotOgre.z); | |
double currPitch = localRot.GetAsEuler().y; | |
double currYaw = localRot.GetAsEuler().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->trackVisualPitchPID.Update(pitchError, 0.01); | |
double yawAdj = this->trackVisualYawPID.Update(yawError, 0.01); | |
this->SetWorldRotation(math::Quaternion(0, currPitch + pitchAdj, | |
currYaw + yawAdj)); | |
double origDistance = 8.0; | |
double distance = direction.GetLength(); | |
double error = origDistance - distance; | |
double scaling = this->trackVisualPID.Update(error, 0.3); | |
math::Vector3 displacement = direction; | |
displacement.Normalize(); | |
displacement *= scaling; | |
math::Vector3 localPos = | |
Conversions::Convert(this->sceneNode->_getDerivedPosition()); | |
math::Vector3 pos = localPos + displacement; | |
this->SetWorldPosition(pos); | |
} | |
} | |
////////////////////////////////////////////////// | |
void Camera::Render() | |
{ | |
this->Render(false); | |
} | |
////////////////////////////////////////////////// | |
void Camera::Render(bool _force) | |
{ | |
if (this->initialized && (_force || | |
common::Time::GetWallTime() - this->lastRenderWallTime >= | |
this->renderPeriod)) | |
{ | |
this->newData = true; | |
this->RenderImpl(); | |
} | |
} | |
////////////////////////////////////////////////// | |
void Camera::RenderImpl() | |
{ | |
if (this->renderTarget) | |
{ | |
// Render, but don't swap buffers. | |
this->renderTarget->update(false); | |
this->lastRenderWallTime = common::Time::GetWallTime(); | |
} | |
} | |
////////////////////////////////////////////////// | |
common::Time Camera::GetLastRenderWallTime() | |
{ | |
return this->lastRenderWallTime; | |
} | |
////////////////////////////////////////////////// | |
void Camera::PostRender() | |
{ | |
this->renderTarget->swapBuffers(); | |
if (this->newData && (this->captureData || this->captureDataOnce)) | |
{ | |
size_t size; | |
unsigned int width = this->GetImageWidth(); | |
unsigned int height = this->GetImageHeight(); | |
// 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); | |
this->viewport->getTarget()->copyContentsToMemory(box); | |
if (this->captureDataOnce) | |
{ | |
this->SaveFrame(this->GetFrameFilename()); | |
this->captureDataOnce = false; | |
} | |
if (this->sdf->HasElement("save") && | |
this->sdf->GetElement("save")->Get<bool>("enabled")) | |
{ | |
this->SaveFrame(this->GetFrameFilename()); | |
} | |
const unsigned char *buffer = this->saveFrameBuffer; | |
// do last minute conversion if Bayer pattern is requested, go from R8G8B8 | |
if ((this->GetImageFormat() == "BAYER_RGGB8") || | |
(this->GetImageFormat() == "BAYER_BGGR8") || | |
(this->GetImageFormat() == "BAYER_GBRG8") || | |
(this->GetImageFormat() == "BAYER_GRBG8")) | |
{ | |
if (!this->bayerFrameBuffer) | |
this->bayerFrameBuffer = new unsigned char[width * height]; | |
this->ConvertRGBToBAYER(this->bayerFrameBuffer, | |
this->saveFrameBuffer, this->GetImageFormat(), | |
width, height); | |
buffer = this->bayerFrameBuffer; | |
} | |
this->newImageFrame(buffer, width, height, this->GetImageDepth(), | |
this->GetImageFormat()); | |
} | |
this->newData = false; | |
} | |
////////////////////////////////////////////////// | |
math::Pose Camera::GetWorldPose() | |
{ | |
return math::Pose(this->GetWorldPosition(), this->GetWorldRotation()); | |
} | |
////////////////////////////////////////////////// | |
math::Vector3 Camera::GetWorldPosition() const | |
{ | |
return Conversions::Convert(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); | |
} | |
////////////////////////////////////////////////// | |
void Camera::SetWorldPose(const math::Pose &_pose) | |
{ | |
this->SetWorldPosition(_pose.pos); | |
this->SetWorldRotation(_pose.rot); | |
} | |
////////////////////////////////////////////////// | |
void Camera::SetWorldPosition(const math::Vector3 &_pos) | |
{ | |
if (this->animState) | |
return; | |
this->sceneNode->_setDerivedPosition(Ogre::Vector3(_pos.x, _pos.y, _pos.z)); | |
this->sceneNode->needUpdate(); | |
} | |
////////////////////////////////////////////////// | |
void Camera::SetWorldRotation(const math::Quaternion &_quant) | |
{ | |
if (this->animState) | |
return; | |
math::Vector3 rpy = _quant.GetAsEuler(); | |
// Set the roll and yaw for sceneNode | |
math::Quaternion s(rpy.x, rpy.y, rpy.z); | |
this->sceneNode->_setDerivedOrientation(Ogre::Quaternion(s.w, s.x, s.y, s.z)); | |
this->sceneNode->needUpdate(); | |
} | |
////////////////////////////////////////////////// | |
void Camera::Translate(const math::Vector3 &direction) | |
{ | |
Ogre::Vector3 vec(direction.x, direction.y, direction.z); | |
this->sceneNode->translate(this->sceneNode->getOrientation() * | |
this->sceneNode->getOrientation() * vec); | |
} | |
////////////////////////////////////////////////// | |
void Camera::RotateYaw(math::Angle _angle) | |
{ | |
this->sceneNode->roll(Ogre::Radian(_angle.Radian()), Ogre::Node::TS_WORLD); | |
} | |
////////////////////////////////////////////////// | |
void Camera::RotatePitch(math::Angle _angle) | |
{ | |
this->sceneNode->yaw(Ogre::Radian(_angle.Radian())); | |
} | |
////////////////////////////////////////////////// | |
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(float _near, 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->sdf->GetElement("horizontal_fov")->Set(_angle.Radian()); | |
} | |
////////////////////////////////////////////////// | |
math::Angle Camera::GetHFOV() const | |
{ | |
return math::Angle(this->sdf->Get<double>("horizontal_fov")); | |
} | |
////////////////////////////////////////////////// | |
math::Angle Camera::GetVFOV() const | |
{ | |
return math::Angle(this->camera->getFOVy().valueRadians()); | |
} | |
////////////////////////////////////////////////// | |
void Camera::SetImageSize(unsigned int _w, unsigned int _h) | |
{ | |
this->SetImageWidth(_w); | |
this->SetImageHeight(_h); | |
} | |
////////////////////////////////////////////////// | |
void Camera::SetImageWidth(unsigned int _w) | |
{ | |
sdf::ElementPtr elem = this->sdf->GetElement("image"); | |
elem->GetElement("width")->Set(_w); | |
} | |
////////////////////////////////////////////////// | |
void Camera::SetImageHeight(unsigned int _h) | |
{ | |
sdf::ElementPtr elem = this->sdf->GetElement("image"); | |
elem->GetElement("height")->Set(_h); | |
} | |
////////////////////////////////////////////////// | |
unsigned int Camera::GetImageWidth() 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 | |
{ | |
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 | |
{ | |
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 == "R8G8B8" || imgFmt == "RGB_INT8") | |
return 3; | |
else if (imgFmt == "B8G8R8" || imgFmt == "BGR_INT8") | |
return 3; | |
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; | |
} | |
} | |
////////////////////////////////////////////////// | |
std::string Camera::GetImageFormat() const | |
{ | |
sdf::ElementPtr imgElem = this->sdf->GetElement("image"); | |
return imgElem->Get<std::string>("format"); | |
} | |
////////////////////////////////////////////////// | |
unsigned int Camera::GetTextureWidth() const | |
{ | |
return this->renderTexture->getBuffer(0, 0)->getWidth(); | |
} | |
////////////////////////////////////////////////// | |
unsigned int Camera::GetTextureHeight() const | |
{ | |
return this->renderTexture->getBuffer(0, 0)->getHeight(); | |
} | |
////////////////////////////////////////////////// | |
size_t Camera::GetImageByteSize() const | |
{ | |
sdf::ElementPtr elem = this->sdf->GetElement("image"); | |
return this->GetImageByteSize(elem->Get<int>("width"), | |
elem->Get<int>("height"), | |
this->GetImageFormat()); | |
} | |
// Get the image size in bytes | |
size_t Camera::GetImageByteSize(unsigned int _width, unsigned int _height, | |
const std::string &_format) | |
{ | |
Ogre::PixelFormat fmt = | |
(Ogre::PixelFormat)(Camera::GetOgrePixelFormat(_format)); | |
return Ogre::PixelUtil::getMemorySize(_width, _height, 1, fmt); | |
} | |
int Camera::GetOgrePixelFormat(const std::string &_format) | |
{ | |
int result; | |
if (_format == "L8" || _format == "L_INT8") | |
result = static_cast<int>(Ogre::PF_L8); | |
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 == "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(bool _enable) | |
{ | |
sdf::ElementPtr elem = this->sdf->GetElement("save"); | |
elem->GetAttribute("enabled")->Set(_enable); | |
this->captureData = _enable; | |
} | |
////////////////////////////////////////////////// | |
bool Camera::GetCaptureData() 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->camera; | |
} | |
////////////////////////////////////////////////// | |
Ogre::Viewport *Camera::GetViewport() const | |
{ | |
return this->viewport; | |
} | |
////////////////////////////////////////////////// | |
double Camera::GetNearClip() | |
{ | |
if (this->camera) | |
return this->camera->getNearClipDistance(); | |
else | |
return 0; | |
} | |
////////////////////////////////////////////////// | |
double Camera::GetFarClip() | |
{ | |
if (this->camera) | |
return this->camera->getFarClipDistance(); | |
else | |
return 0; | |
} | |
////////////////////////////////////////////////// | |
unsigned int Camera::GetViewportWidth() 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 | |
{ | |
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(float ratio) | |
{ | |
this->camera->setAspectRatio(ratio); | |
} | |
////////////////////////////////////////////////// | |
float Camera::GetAspectRatio() const | |
{ | |
return this->camera->getAspectRatio(); | |
} | |
////////////////////////////////////////////////// | |
math::Vector3 Camera::GetUp() | |
{ | |
Ogre::Vector3 up = this->camera->getRealUp(); | |
return math::Vector3(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); | |
} | |
////////////////////////////////////////////////// | |
void Camera::SetSceneNode(Ogre::SceneNode *node) | |
{ | |
this->sceneNode = node; | |
} | |
////////////////////////////////////////////////// | |
Ogre::SceneNode *Camera::GetSceneNode() const | |
{ | |
return this->sceneNode; | |
} | |
////////////////////////////////////////////////// | |
Ogre::SceneNode *Camera::GetPitchNode() const | |
{ | |
gzerr << "Camera::GetPitchNode() is deprecated, will return sceneNode " | |
<< "which contains all rotations of the Camera. " | |
<< "Use GetSceneNode() instead.\n"; | |
return this->sceneNode; | |
} | |
////////////////////////////////////////////////// | |
const unsigned char *Camera::GetImageData(unsigned int _i) | |
{ | |
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->GetImageFormat() == "BAYER_RGGB8") || | |
(this->GetImageFormat() == "BAYER_BGGR8") || | |
(this->GetImageFormat() == "BAYER_GBRG8") || | |
(this->GetImageFormat() == "BAYER_GRBG8")) | |
{ | |
return this->bayerFrameBuffer; | |
} | |
else | |
return this->saveFrameBuffer; | |
} | |
////////////////////////////////////////////////// | |
std::string Camera::GetName() const | |
{ | |
return this->name; | |
} | |
////////////////////////////////////////////////// | |
bool Camera::SaveFrame(const std::string &_filename) | |
{ | |
return Camera::SaveFrame(this->saveFrameBuffer, this->GetImageWidth(), | |
this->GetImageHeight(), this->GetImageDepth(), | |
this->GetImageFormat(), _filename); | |
} | |
////////////////////////////////////////////////// | |
std::string Camera::GetFrameFilename() | |
{ | |
sdf::ElementPtr saveElem = this->sdf->GetElement("save"); | |
std::string path = saveElem->Get<std::string>("path"); | |
boost::filesystem::path pathToFile; | |
std::string friendlyName = this->GetName(); | |
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; | |
} | |
///////////////////////////////////////////////// | |
bool Camera::SaveFrame(const unsigned char *_image, | |
unsigned int _width, unsigned int _height, 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::GetOgrePixelFormat(_format); | |
size = Camera::GetImageByteSize(_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 | |
#if (OGRE_VERSION < ((1 << 16) | (9 << 8) | 0)) | |
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(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->GetViewportWidth(), | |
static_cast<float>(_screeny) / this->GetViewportHeight()); | |
_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, unsigned char* src, | |
std::string format, int width, 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(bool _value) | |
{ | |
this->captureData = _value; | |
} | |
////////////////////////////////////////////////// | |
void Camera::SetCaptureDataOnce() | |
{ | |
this->captureDataOnce = true; | |
} | |
////////////////////////////////////////////////// | |
void Camera::CreateRenderTexture(const std::string &_textureName) | |
{ | |
// Create the render texture | |
this->renderTexture = (Ogre::TextureManager::getSingleton().createManual( | |
_textureName, | |
"General", | |
Ogre::TEX_TYPE_2D, | |
this->GetImageWidth(), | |
this->GetImageHeight(), | |
0, | |
(Ogre::PixelFormat)this->imageFormat, | |
Ogre::TU_RENDERTARGET, | |
0, | |
false, | |
0)).getPointer(); | |
this->SetRenderTarget(this->renderTexture->getBuffer()->getRenderTarget()); | |
this->initialized = true; | |
} | |
////////////////////////////////////////////////// | |
ScenePtr Camera::GetScene() const | |
{ | |
return this->scene; | |
} | |
////////////////////////////////////////////////// | |
void Camera::CreateCamera() | |
{ | |
this->camera = this->scene->GetManager()->createCamera(this->name); | |
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) | |
{ | |
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; | |
} | |
////////////////////////////////////////////////// | |
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); | |
RTShaderSystem::AttachViewport(this->viewport, this->GetScene()); | |
this->viewport->setBackgroundColour( | |
Conversions::Convert(this->scene->GetBackgroundColor())); | |
this->viewport->setVisibilityMask(GZ_VISIBILITY_ALL & | |
~(GZ_VISIBILITY_GUI | GZ_VISIBILITY_SELECTABLE)); | |
double ratio = static_cast<double>(this->viewport->getActualWidth()) / | |
static_cast<double>(this->viewport->getActualHeight()); | |
double hfov = this->GetHFOV().Radian(); | |
double vfov = 2.0 * atan(tan(hfov / 2.0) / ratio); | |
this->camera->setAspectRatio(ratio); | |
this->camera->setFOVy(Ogre::Radian(vfov)); | |
// Setup Deferred rendering for the camera | |
if (RenderEngine::Instance()->GetRenderPathType() == RenderEngine::DEFERRED) | |
{ | |
// Deferred shading GBuffer compositor | |
this->dsGBufferInstance = | |
Ogre::CompositorManager::getSingleton().addCompositor(this->viewport, | |
"DeferredShading/GBuffer"); | |
// Deferred lighting GBuffer compositor | |
this->dlGBufferInstance = | |
Ogre::CompositorManager::getSingleton().addCompositor(this->viewport, | |
"DeferredLighting/GBuffer"); | |
// Deferred shading: Merging compositor | |
this->dsMergeInstance = | |
Ogre::CompositorManager::getSingleton().addCompositor(this->viewport, | |
"DeferredShading/ShowLit"); | |
// Deferred lighting: Merging compositor | |
this->dlMergeInstance = | |
Ogre::CompositorManager::getSingleton().addCompositor(this->viewport, | |
"DeferredLighting/ShowLit"); | |
// Screen space ambient occlusion | |
// this->ssaoInstance = | |
// Ogre::CompositorManager::getSingleton().addCompositor(this->viewport, | |
// "DeferredShading/SSAO"); | |
this->dsGBufferInstance->setEnabled(false); | |
this->dsMergeInstance->setEnabled(false); | |
this->dlGBufferInstance->setEnabled(true); | |
this->dlMergeInstance->setEnabled(true); | |
// this->ssaoInstance->setEnabled(false); | |
} | |
// Noise | |
if (this->noiseActive) | |
{ | |
switch (this->noiseType) | |
{ | |
case GAUSSIAN: | |
this->gaussianNoiseInstance = | |
Ogre::CompositorManager::getSingleton().addCompositor( | |
this->viewport, "CameraNoise/Gaussian"); | |
this->gaussianNoiseInstance->setEnabled(true); | |
// gaussianNoiseCompositorListener was allocated in Load() | |
this->gaussianNoiseInstance->addListener( | |
this->gaussianNoiseCompositorListener.get()); | |
break; | |
default: | |
GZ_ASSERT(false, "Invalid noise model type"); | |
} | |
} | |
if (this->GetScene()->skyx != NULL) | |
this->renderTarget->addListener(this->GetScene()->skyx); | |
} | |
} | |
////////////////////////////////////////////////// | |
void Camera::AttachToVisual(uint32_t _visualId, | |
bool _inheritOrientation, | |
double _minDist, double _maxDist) | |
{ | |
msgs::Request request; | |
msgs::TrackVisual track; | |
track.set_name(this->GetName() + "_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, | |
bool _inheritOrientation, | |
double _minDist, double _maxDist) | |
{ | |
msgs::Request request; | |
msgs::TrackVisual track; | |
VisualPtr visual = this->scene->GetVisual(_visualName); | |
if (visual) | |
track.set_id(visual->GetId()); | |
else | |
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(uint32_t _id, | |
bool _inheritOrientation, double _minDist, double _maxDist) | |
{ | |
VisualPtr visual = this->scene->GetVisual(_id); | |
return this->AttachToVisualImpl(visual, _inheritOrientation, | |
_minDist, _maxDist); | |
} | |
////////////////////////////////////////////////// | |
bool Camera::AttachToVisualImpl(const std::string &_name, | |
bool _inheritOrientation, double _minDist, double _maxDist) | |
{ | |
VisualPtr visual = this->scene->GetVisual(_name); | |
return this->AttachToVisualImpl(visual, _inheritOrientation, | |
_minDist, _maxDist); | |
} | |
////////////////////////////////////////////////// | |
bool Camera::AttachToVisualImpl(VisualPtr _visual, bool _inheritOrientation, | |
double /*_minDist*/, 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->trackedVisual.reset(); | |
return false; | |
} | |
////////////////////////////////////////////////// | |
bool Camera::TrackVisualImpl(VisualPtr _visual) | |
{ | |
// if (this->sceneNode->getParent()) | |
// this->sceneNode->getParent()->removeChild(this->sceneNode); | |
if (_visual) | |
{ | |
this->trackVisualPID.Init(0.25, 0, 0, 0, 0, 1.0, 0.0); | |
this->trackVisualPitchPID.Init(0.05, 0, 0, 0, 0, 1.0, 0.0); | |
this->trackVisualYawPID.Init(0.05, 0, 0, 0, 0, 1.0, 0.0); | |
this->trackedVisual = _visual; | |
} | |
else | |
this->trackedVisual.reset(); | |
return true; | |
} | |
////////////////////////////////////////////////// | |
Ogre::Texture *Camera::GetRenderTexture() const | |
{ | |
return this->renderTexture; | |
} | |
///////////////////////////////////////////////// | |
math::Vector3 Camera::GetDirection() const | |
{ | |
return Conversions::Convert(this->camera->getDerivedDirection()); | |
} | |
///////////////////////////////////////////////// | |
bool Camera::IsVisible(VisualPtr _visual) | |
{ | |
if (this->camera && _visual) | |
{ | |
math::Box bbox = _visual->GetBoundingBox(); | |
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); | |
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, double _time) | |
{ | |
if (this->animState) | |
{ | |
this->moveToPositionQueue.push_back(std::make_pair(_pose, _time)); | |
return false; | |
} | |
Ogre::TransformKeyFrame *key; | |
math::Vector3 rpy = _pose.rot.GetAsEuler(); | |
math::Vector3 start = this->GetWorldPose().pos; | |
Ogre::Quaternion localRotOgre = this->sceneNode->getOrientation(); | |
math::Quaternion localRot = math::Quaternion( | |
localRotOgre.w, localRotOgre.x, localRotOgre.y, localRotOgre.z); | |
double dyaw = localRot.GetAsEuler().z - rpy.z; | |
if (dyaw > M_PI) | |
rpy.z += 2*M_PI; | |
else if (dyaw < -M_PI) | |
rpy.z -= 2*M_PI; | |
math::Quaternion 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->GetManager()->hasAnimation(trackName)) | |
{ | |
trackName = std::string("cameratrack_") + | |
boost::lexical_cast<std::string>(i); | |
i++; | |
} | |
Ogre::Animation *anim = | |
this->scene->GetManager()->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->GetManager()->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, | |
double _time, boost::function<void()> _onComplete) | |
{ | |
if (this->animState) | |
return false; | |
this->onAnimationComplete = _onComplete; | |
Ogre::TransformKeyFrame *key; | |
math::Vector3 start = this->GetWorldPose().pos; | |
std::string trackName = "cameratrack"; | |
int i = 0; | |
while (this->scene->GetManager()->hasAnimation(trackName)) | |
{ | |
trackName = std::string("cameratrack_") + | |
boost::lexical_cast<std::string>(i); | |
i++; | |
} | |
Ogre::Animation *anim = | |
this->scene->GetManager()->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(); | |
math::Quaternion localRot = math::Quaternion( | |
localRotOgre.w, localRotOgre.x, localRotOgre.y, localRotOgre.z); | |
double prevYaw = localRot.GetAsEuler().z; | |
for (unsigned int j = 0; j < _pts.size(); j++) | |
{ | |
math::Vector3 pos = _pts[j].pos; | |
math::Vector3 rpy = _pts[j].rot.GetAsEuler(); | |
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; | |
math::Quaternion 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->GetManager()->createAnimationState(trackName); | |
this->animState->setTimePosition(0); | |
this->animState->setEnabled(true); | |
this->animState->setLoop(false); | |
this->prevAnimTime = common::Time::GetWallTime(); | |
return true; | |
} | |
////////////////////////////////////////////////// | |
void Camera::SetRenderRate(double _hz) | |
{ | |
if (_hz > 0.0) | |
this->renderPeriod = 1.0 / _hz; | |
else | |
this->renderPeriod = 0.0; | |
} | |
////////////////////////////////////////////////// | |
double Camera::GetRenderRate() const | |
{ | |
return 1.0 / this->renderPeriod.Double(); | |
} | |
////////////////////////////////////////////////// | |
void Camera::AnimationComplete() | |
{ | |
} | |
////////////////////////////////////////////////// | |
bool Camera::GetInitialized() const | |
{ | |
return this->initialized && this->scene->GetInitialized(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment