00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <string>
00031 #include <iostream>
00032
00033 #include <QWidget>
00034 #include <QDesktopWidget>
00035 #include <QApplication>
00036
00037 #include <OVR.h>
00038
00039 #include <boost/bind.hpp>
00040
00041 #include <OGRE/OgreRoot.h>
00042 #include <OGRE/OgreSceneNode.h>
00043 #include <OGRE/OgreRenderWindow.h>
00044
00045 #include <ros/package.h>
00046
00047 #include <rviz/properties/bool_property.h>
00048 #include <rviz/properties/status_property.h>
00049 #include <rviz/properties/float_property.h>
00050 #include <rviz/properties/string_property.h>
00051 #include <rviz/properties/tf_frame_property.h>
00052 #include <rviz/properties/vector_property.h>
00053
00054 #include <rviz/window_manager_interface.h>
00055 #include <rviz/view_manager.h>
00056 #include <rviz/render_panel.h>
00057 #include <rviz/display_context.h>
00058 #include <rviz/ogre_helpers/render_widget.h>
00059 #include <rviz/ogre_helpers/render_system.h>
00060 #include <rviz/frame_manager.h>
00061
00062 #include "oculus_rviz_plugins/oculus_display.h"
00063 #include "oculus_rviz_plugins/ogre_oculus.h"
00064
00065 namespace oculus_rviz_plugins
00066 {
00067
00068 OculusDisplay::OculusDisplay()
00069 : render_widget_(0)
00070 , scene_node_(0)
00071 {
00072 std::string rviz_path = ros::package::getPath(ROS_PACKAGE_NAME);
00073 Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media", "FileSystem", ROS_PACKAGE_NAME );
00074 Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(ROS_PACKAGE_NAME);
00075
00076 connect( QApplication::desktop(), SIGNAL( screenCountChanged ( int ) ), this, SLOT( onScreenCountChanged(int)) );
00077 }
00078
00079 OculusDisplay::~OculusDisplay()
00080 {
00081 oculus_.reset();
00082 delete render_widget_;
00083 }
00084
00085
00086 void OculusDisplay::onInitialize()
00087 {
00088 fullscreen_property_ = new rviz::BoolProperty( "Render to Oculus", false,
00089 "If checked, will render fullscreen on your secondary screen. Otherwise, shows a window.",
00090 this, SLOT(onFullScreenChanged()));
00091
00092 prediction_dt_property_ = new rviz::FloatProperty( "Motion prediction (ms)", 30.0,
00093 "Time in ms to predict head motion. Decreases overall latency and motion sickness.",
00094 this, SLOT(onPredictionDtChanged()) );
00095
00096 near_clip_property_ = new rviz::FloatProperty( "Near Clip Distance", 0.02,
00097 "Minimum rendering distance for Oculus camera.",
00098 this );
00099
00100 horizontal_property_ = new rviz::BoolProperty( "Fixed Horizon", true,
00101 "If checked, will ignore the pitch component of the RViz camera.", this);
00102
00103 follow_cam_property_ = new rviz::BoolProperty( "Follow RViz Camera", true,
00104 "If checked, will set the Oculus camera to the same position as the main view camera.",
00105 this, SLOT( onFollowCamChanged() ) );
00106
00107 tf_frame_property_ = new rviz::TfFrameProperty( "Target Frame", "<Fixed Frame>",
00108 "Tf frame that the Oculus camera should follow.", this, context_->getFrameManager(), true );
00109
00110 offset_property_ = new rviz::VectorProperty( "Offset", Ogre::Vector3(0,0,0),
00111 "Additional offset of the Oculus camera from the followed RViz camera or target frame.", this );
00112
00113 pub_tf_property_ = new rviz::BoolProperty( "Publish tf", true,
00114 "If checked, will publish the pose of the Oculus camera as a tf frame.",
00115 this, SLOT( onPubTfChanged() ) );
00116
00117 pub_tf_frame_property_ = new rviz::StringProperty( "Tf Frame", "oculus",
00118 "Name of the published tf frame.", this );
00119
00120 render_widget_ = new rviz::RenderWidget( rviz::RenderSystem::get() );
00121 render_widget_->setVisible(false);
00122 render_widget_->setWindowTitle( "Oculus View" );
00123
00124 render_widget_->setParent( context_->getWindowManager()->getParentWindow() );
00125 render_widget_->setWindowFlags( Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowMaximizeButtonHint );
00126
00127 Ogre::RenderWindow *window = render_widget_->getRenderWindow();
00128 window->setVisible(false);
00129 window->setAutoUpdated(false);
00130 window->addListener(this);
00131
00132 scene_node_ = scene_manager_->getRootSceneNode()->createChildSceneNode();
00133 }
00134
00135
00136 void OculusDisplay::onFollowCamChanged()
00137 {
00138 tf_frame_property_->setHidden( follow_cam_property_->getBool() );
00139 }
00140
00141 void OculusDisplay::onPubTfChanged()
00142 {
00143 pub_tf_frame_property_->setHidden( !pub_tf_property_->getBool() );
00144 }
00145
00146 void OculusDisplay::onPredictionDtChanged( )
00147 {
00148 if ( !oculus_ || !isEnabled() )
00149 {
00150 return;
00151 }
00152
00153 oculus_->setPredictionDt( prediction_dt_property_->getFloat() * 0.001 );
00154 }
00155
00156
00157 void OculusDisplay::onScreenCountChanged( int newCount )
00158 {
00159 if ( newCount == 1 )
00160 {
00161 fullscreen_property_->setBool(false);
00162 fullscreen_property_->setHidden(true);
00163 setStatus( rviz::StatusProperty::Error, "Screen", "No secondary screen detected. Cannot render to Oculus device.");
00164 }
00165 else
00166 {
00167 fullscreen_property_->setHidden(false);
00168 setStatus( rviz::StatusProperty::Ok, "Screen", "Using screen #2.");
00169 }
00170 }
00171
00172
00173 void OculusDisplay::onFullScreenChanged()
00174 {
00175 if ( !oculus_ || !isEnabled() )
00176 {
00177 return;
00178 }
00179
00180 if ( fullscreen_property_->getBool() && QApplication::desktop()->numScreens() > 1 )
00181 {
00182 QRect screen_res = QApplication::desktop()->screenGeometry(1);
00183
00184 render_widget_->setGeometry( screen_res );
00185
00186 render_widget_->showFullScreen();
00187 }
00188 else
00189 {
00190 int x_res = 1280;
00191 int y_res = 800;
00192 if ( oculus_->getHMDDevice() )
00193 {
00194 OVR::HMDInfo info;
00195 oculus_->getHMDDevice()->GetDeviceInfo( &info );
00196 x_res = info.HResolution;
00197 y_res = info.VResolution;
00198 }
00199 int primary_screen = QApplication::desktop()->primaryScreen();
00200 QRect screen_res = QApplication::desktop()->screenGeometry( primary_screen );
00201 render_widget_->setGeometry( screen_res.x(), screen_res.y(), x_res, y_res );
00202 render_widget_->showNormal();
00203 }
00204 }
00205
00206 void OculusDisplay::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
00207 {
00208 if ( !oculus_ )
00209 {
00210 return;
00211 }
00212 updateCamera();
00213 }
00214
00215 void OculusDisplay::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
00216 {
00217 if ( !oculus_ )
00218 {
00219 return;
00220 }
00221 Ogre::RenderWindow *window = render_widget_->getRenderWindow();
00222 window->swapBuffers();
00223 }
00224
00225 void OculusDisplay::onEnable()
00226 {
00227 if ( oculus_ )
00228 {
00229 return;
00230 }
00231
00232 oculus_.reset( new Oculus() );
00233 oculus_->setupOculus();
00234
00235 if ( !oculus_->isOculusReady() )
00236 {
00237 oculus_.reset();
00238 setStatusStd( rviz::StatusProperty::Error, "Oculus", "No Oculus device found!" );
00239 return;
00240 }
00241
00242 setStatusStd( rviz::StatusProperty::Ok, "Oculus", "Oculus is ready." );
00243
00244 Ogre::RenderWindow *window = render_widget_->getRenderWindow();
00245 oculus_->setupOgre( scene_manager_, window, scene_node_ );
00246
00247 render_widget_->setVisible( oculus_->isOculusReady() );
00248
00249 onScreenCountChanged( QApplication::desktop()->numScreens() );
00250 onFullScreenChanged();
00251 onPredictionDtChanged();
00252 }
00253
00254 void OculusDisplay::onDisable()
00255 {
00256 clearStatuses();
00257 render_widget_->setVisible(false);
00258 if ( oculus_ )
00259 {
00260 oculus_.reset();
00261 }
00262 }
00263
00264 void OculusDisplay::update( float wall_dt, float ros_dt )
00265 {
00266 if ( !oculus_ )
00267 {
00268 return;
00269 }
00270
00271 updateCamera();
00272 Ogre::RenderWindow *window = render_widget_->getRenderWindow();
00273 window->update(false);
00274
00275 if ( oculus_->isMagCalibrated() )
00276 {
00277 setStatus( rviz::StatusProperty::Ok, "Magnetometer", "Magnetometer calibrated.");
00278 }
00279 else
00280 {
00281 setStatus( rviz::StatusProperty::Warn, "Magnetometer", "Magnetometer not calibrated. Look left/right/up/down to collect enough samples.");
00282 }
00283 }
00284
00285 void OculusDisplay::updateCamera()
00286 {
00287 if (!oculus_ || !oculus_->isOculusReady())
00288 {
00289 return;
00290 }
00291
00292 Ogre::Vector3 pos;
00293 Ogre::Quaternion ori;
00294
00295
00296 if ( follow_cam_property_->getBool() )
00297 {
00298 const Ogre::Camera *cam = context_->getViewManager()->getCurrent()->getCamera();
00299 pos = cam->getDerivedPosition();
00300 ori = cam->getDerivedOrientation();
00301 }
00302 else
00303 {
00304 context_->getFrameManager()->getTransform( tf_frame_property_->getStdString(),
00305 ros::Time(), pos, ori );
00306 Ogre::Quaternion r;
00307 r.FromAngleAxis( Ogre::Radian(M_PI*0.5), Ogre::Vector3::UNIT_X );
00308 ori = ori * r;
00309 r.FromAngleAxis( Ogre::Radian(-M_PI*0.5), Ogre::Vector3::UNIT_Y );
00310 ori = ori * r;
00311 }
00312
00313 pos += offset_property_->getVector();
00314
00315 scene_node_->setPosition( pos );
00316
00317
00318 if ( horizontal_property_->getBool() )
00319 {
00320 Ogre::Vector3 x_axis = ori * Ogre::Vector3(1,0,0);
00321 float yaw = atan2( x_axis.y, x_axis.x );
00322
00323
00324 ori.FromAngleAxis( Ogre::Radian(yaw), Ogre::Vector3::UNIT_Z );
00325
00326 Ogre::Quaternion r;
00327 r.FromAngleAxis( Ogre::Radian(M_PI*0.5), Ogre::Vector3::UNIT_X );
00328 ori = ori * r;
00329 }
00330
00331 scene_node_->setOrientation( ori );
00332
00333 Ogre::ColourValue bg_color = context_->getViewManager()->getRenderPanel()->getViewport()->getBackgroundColour();
00334
00335 for ( int i =0; i<2; i++ )
00336 {
00337 oculus_->getViewport(i)->setBackgroundColour( bg_color );
00338 oculus_->getCamera(i)->setNearClipDistance( near_clip_property_->getFloat() );
00339
00340
00341
00342 bg_color.g += 0.0001;
00343 }
00344
00345 oculus_->updateProjectionMatrices();
00346 oculus_->update();
00347
00348 if ( pub_tf_property_->getBool() )
00349 {
00350 tf::StampedTransform pose;
00351 pose.frame_id_ = context_->getFixedFrame().toStdString();
00352 pose.child_frame_id_ = pub_tf_frame_property_->getStdString();
00353 pose.stamp_ = ros::Time::now();
00354 ori = ori * oculus_->getOrientation();
00355 Ogre::Quaternion r;
00356 r.FromAngleAxis( Ogre::Radian(M_PI*0.5), Ogre::Vector3::UNIT_Y );
00357 ori = ori * r;
00358 r.FromAngleAxis( Ogre::Radian(-M_PI*0.5), Ogre::Vector3::UNIT_X );
00359 ori = ori * r;
00360
00361 pose.setRotation( tf::Quaternion( ori.x, ori.y, ori.z, ori.w ) );
00362 pose.setOrigin( tf::Vector3( pos.x, pos.y, pos.z ) );
00363 tf_pub_.sendTransform( pose );
00364 }
00365 }
00366
00367 void OculusDisplay::reset()
00368 {
00369 rviz::Display::reset();
00370 if ( oculus_ )
00371 {
00372 onDisable();
00373 onEnable();
00374 }
00375 }
00376
00377 }
00378
00379 #include <pluginlib/class_list_macros.h>
00380 PLUGINLIB_EXPORT_CLASS( oculus_rviz_plugins::OculusDisplay, rviz::Display )