pxmlw6n2f/Gazebo_Distributed_MPI/gazebo/rendering/OculusCamera.cc

772 lines
25 KiB
C++

/*
* Copyright (C) 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 <sstream>
#include <string>
#include "gazebo/rendering/ogre_gazebo.h"
#include "gazebo/common/Assert.hh"
#include "gazebo/common/Console.hh"
#include "gazebo/common/Exception.hh"
#include "gazebo/common/Events.hh"
#include "gazebo/rendering/skyx/include/SkyX.h"
#include "gazebo/rendering/selection_buffer/SelectionBuffer.hh"
#include "gazebo/rendering/RenderEngine.hh"
#include "gazebo/rendering/Conversions.hh"
#include "gazebo/rendering/RenderTypes.hh"
#include "gazebo/rendering/Scene.hh"
#include "gazebo/rendering/RTShaderSystem.hh"
#include "gazebo/rendering/Camera.hh"
#include "gazebo/rendering/Visual.hh"
#include "gazebo/rendering/OculusCameraPrivate.hh"
#include "gazebo/rendering/OculusCamera.hh"
using namespace gazebo;
using namespace rendering;
const float g_defaultNearClip = 0.01f;
const float g_defaultFarClip = 500.0f;
//////////////////////////////////////////////////
OculusCamera::OculusCamera(const std::string &_name, ScenePtr _scene)
: Camera(_name, _scene), dataPtr(new OculusCameraPrivate)
{
ovr_Initialize();
this->dataPtr->hmd = ovrHmd_Create(0);
if (!this->dataPtr->hmd)
{
gzerr << "Oculus Rift not detected. "
<< "Oculus error["
<< ovrHmd_GetLastError(NULL) << "]. "
<< "Is the oculusd service running?\n"
<< "Did you copy the udev rules from the oculussdk repo?\n"
<< "See: http://gazebosim.org/tutorials?tut=oculus"
<< std::endl;
return;
}
if (this->dataPtr->hmd->ProductName[0] == '\0')
{
gzerr << "Oculus Rift detected, display not enabled. "
<< "Oculus error["
<< ovrHmd_GetLastError(NULL) << "]. "
<< std::endl;
return;
}
// These are the suggested refresh rates for dk1 and dk2
// dk1: 60Hz
// dk2: 75Hz
switch (this->dataPtr->hmd->Type)
{
case ovrHmd_DK1:
// A little bit extra for safety
this->SetRenderRate(70.0);
break;
case ovrHmd_DK2:
// A little bit extra for safety
this->SetRenderRate(80.0);
break;
case ovrHmd_None:
gzerr << "Unable to handle Oculus with type 'None'\n";
return;
case ovrHmd_DKHD:
gzerr << "Unable to handle Oculus with type 'DKHD'\n";
return;
case ovrHmd_Other:
gzerr << "Unable to handle Oculus with type 'Other'\n";
return;
default:
gzerr << "Unknown Oculus type '" << this->dataPtr->hmd->Type << "'\n";
return;
};
// Log some useful information
gzmsg << "Oculus Rift found." << std::endl;
gzmsg << "\tType: " << this->dataPtr->hmd->Type << std::endl;
gzmsg << "\tProduct Name: " << this->dataPtr->hmd->ProductName << std::endl;
gzmsg << "\tProduct ID: " << this->dataPtr->hmd->ProductId << std::endl;
gzmsg << "\tFirmware: " << this->dataPtr->hmd->FirmwareMajor << "."
<< this->dataPtr->hmd->FirmwareMinor << std::endl;
gzmsg << "\tResolution: " << this->dataPtr->hmd->Resolution.w << "x"
<< this->dataPtr->hmd->Resolution.h << std::endl;
gzmsg << "\tPosition tracking: "
<< (this->dataPtr->hmd->TrackingCaps & ovrTrackingCap_Position)
<< std::endl;
// Start the sensor which informs of the Rift's pose and motion
if (!ovrHmd_ConfigureTracking(this->dataPtr->hmd, ovrTrackingCap_Orientation
| ovrTrackingCap_MagYawCorrection | ovrTrackingCap_Position, 0))
{
gzerr << "Tracking capability not found. "
<< "The Oculus viewpoint will not move.\n";
}
this->dataPtr->node = transport::NodePtr(new transport::Node());
this->dataPtr->node->Init();
this->dataPtr->controlSub = this->dataPtr->node->Subscribe("~/world_control",
&OculusCamera::OnControl, this);
// Oculus is now ready.
this->dataPtr->ready = true;
}
//////////////////////////////////////////////////
OculusCamera::~OculusCamera()
{
if (this->dataPtr->externalSceneManager)
{
RenderEngine::Instance()->Root()->destroySceneManager(
this->dataPtr->externalSceneManager);
}
ovrHmd_Destroy(this->dataPtr->hmd);
ovr_Shutdown();
this->connections.clear();
delete this->dataPtr;
this->dataPtr = NULL;
}
//////////////////////////////////////////////////
void OculusCamera::Load(sdf::ElementPtr _sdf)
{
if (this->Ready())
Camera::Load(_sdf);
}
//////////////////////////////////////////////////
void OculusCamera::OnControl(ConstWorldControlPtr &_data)
{
if (_data->has_reset() && _data->reset().has_all() && _data->reset().all())
{
this->ResetSensor();
}
}
//////////////////////////////////////////////////
void OculusCamera::Load()
{
if (this->Ready())
Camera::Load();
}
//////////////////////////////////////////////////
void OculusCamera::Init()
{
if (!this->Ready())
return;
Camera::Init();
// Oculus
{
this->dataPtr->rightCamera = this->scene->OgreSceneManager()->createCamera(
"OculusUserRight");
this->dataPtr->rightCamera->pitch(Ogre::Degree(90));
// Don't yaw along variable axis, causes leaning
this->dataPtr->rightCamera->setFixedYawAxis(true, Ogre::Vector3::UNIT_Z);
this->dataPtr->rightCamera->setDirection(1, 0, 0);
this->sceneNode->attachObject(this->dataPtr->rightCamera);
this->dataPtr->rightCamera->setAutoAspectRatio(false);
this->camera->setAutoAspectRatio(false);
this->dataPtr->rightCamera->setNearClipDistance(g_defaultNearClip);
this->dataPtr->rightCamera->setFarClipDistance(g_defaultFarClip);
this->camera->setNearClipDistance(g_defaultNearClip);
this->camera->setFarClipDistance(g_defaultFarClip);
}
// Careful when setting this value.
// A far clip that is too close will have bad side effects on the
// lighting. When using deferred shading, the light's use geometry that
// trigger shaders. If the far clip is too close, the light's geometry is
// clipped and wholes appear in the lighting.
switch (RenderEngine::Instance()->GetRenderPathType())
{
case RenderEngine::VERTEX:
this->SetClipDist(g_defaultNearClip, g_defaultFarClip);
break;
case RenderEngine::DEFERRED:
case RenderEngine::FORWARD:
this->SetClipDist(g_defaultNearClip, g_defaultFarClip);
break;
default:
this->SetClipDist(g_defaultNearClip, g_defaultFarClip);
break;
}
}
//////////////////////////////////////////////////
void OculusCamera::RenderImpl()
{
ovrHmd_BeginFrameTiming(this->dataPtr->hmd, this->dataPtr->frameIndex);
this->dataPtr->renderTextureLeft->getBuffer()->getRenderTarget()->update();
this->dataPtr->renderTextureRight->getBuffer()->getRenderTarget()->update();
this->renderTarget->update();
ovrHmd_EndFrameTiming(this->dataPtr->hmd);
this->dataPtr->frameIndex++;
}
//////////////////////////////////////////////////
void OculusCamera::Update()
{
if (!this->Ready())
return;
Camera::Update();
ovrFrameTiming frameTiming = ovrHmd_GetFrameTiming(this->dataPtr->hmd,
this->dataPtr->frameIndex);
ovrTrackingState ts = ovrHmd_GetTrackingState(
this->dataPtr->hmd, frameTiming.ScanoutMidpointSeconds);
// Only doing orientation tracking for now. Position tracking is an option
// for dk2
if (ts.StatusFlags & ovrStatus_OrientationTracked)
{
if (this->dataPtr->oculusTrackingWarned)
{
gzmsg << "Oculus: Head tracking enabled.\n";
this->dataPtr->oculusTrackingWarned = false;
}
ovrPosef ovrpose = ts.HeadPose.ThePose;
this->sceneNode->setOrientation(Ogre::Quaternion(
ovrpose.Orientation.w,
-ovrpose.Orientation.z,
-ovrpose.Orientation.x,
ovrpose.Orientation.y));
}
else if (!this->dataPtr->oculusTrackingWarned)
{
gzwarn << "Oculus: No head tracking.\n\t"
<< "If you do not see a following message about 'Head tracking enabled'"
<< ", then try rebooting while leaving the Oculus turned on."
<< std::endl;
this->dataPtr->oculusTrackingWarned = true;
}
this->sceneNode->needUpdate();
}
//////////////////////////////////////////////////
void OculusCamera::ResetSensor()
{
}
//////////////////////////////////////////////////
bool OculusCamera::Ready()
{
return this->dataPtr->ready;
}
//////////////////////////////////////////////////
void OculusCamera::PostRender()
{
Camera::PostRender();
}
//////////////////////////////////////////////////
void OculusCamera::Fini()
{
Camera::Fini();
}
/////////////////////////////////////////////////
bool OculusCamera::AttachToVisualImpl(VisualPtr _visual,
bool _inheritOrientation,
double /*_minDist*/, double /*_maxDist*/)
{
Camera::AttachToVisualImpl(_visual, _inheritOrientation);
if (_visual)
{
math::Pose origPose = this->WorldPose();
double yaw = _visual->GetWorldPose().rot.GetAsEuler().z;
double zDiff = origPose.pos.z - _visual->GetWorldPose().pos.z;
double pitch = 0;
if (fabs(zDiff) > 1e-3)
{
double dist = _visual->GetWorldPose().pos.Distance(
this->WorldPose().Pos());
pitch = acos(zDiff/dist);
}
this->Yaw(ignition::math::Angle(yaw));
this->Pitch(ignition::math::Angle(pitch));
math::Box bb = _visual->GetBoundingBox();
math::Vector3 pos = bb.GetCenter();
pos.z = bb.max.z;
}
return true;
}
//////////////////////////////////////////////////
bool OculusCamera::TrackVisualImpl(VisualPtr _visual)
{
Camera::TrackVisualImpl(_visual);
return true;
}
//////////////////////////////////////////////////
unsigned int OculusCamera::GetImageWidth() const
{
return this->viewport->getActualWidth();
}
//////////////////////////////////////////////////
unsigned int OculusCamera::GetImageHeight() const
{
return this->viewport->getActualHeight();
}
//////////////////////////////////////////////////
void OculusCamera::Resize(unsigned int /*_w*/, unsigned int /*_h*/)
{
if (this->viewport)
{
this->viewport->setDimensions(0, 0, 0.5, 1);
this->dataPtr->rightViewport->setDimensions(0.5, 0, 0.5, 1);
delete [] this->saveFrameBuffer;
this->saveFrameBuffer = NULL;
}
}
//////////////////////////////////////////////////
bool OculusCamera::MoveToPosition(const math::Pose &_pose, double _time)
{
return Camera::MoveToPosition(_pose.Ign(), _time);
}
//////////////////////////////////////////////////
void OculusCamera::MoveToVisual(const std::string &_name)
{
VisualPtr visualPtr = this->scene->GetVisual(_name);
if (visualPtr)
this->MoveToVisual(visualPtr);
else
gzerr << "MoveTo Unknown visual[" << _name << "]\n";
}
//////////////////////////////////////////////////
void OculusCamera::MoveToVisual(VisualPtr _visual)
{
if (!_visual)
return;
if (this->scene->OgreSceneManager()->hasAnimation("cameratrack"))
{
this->scene->OgreSceneManager()->destroyAnimation("cameratrack");
}
math::Box box = _visual->GetBoundingBox();
math::Vector3 size = box.GetSize();
double maxSize = std::max(std::max(size.x, size.y), size.z);
math::Vector3 start = this->WorldPose().Pos();
start.Correct();
math::Vector3 end = box.GetCenter() + _visual->GetWorldPose().pos;
end.Correct();
math::Vector3 dir = end - start;
dir.Correct();
dir.Normalize();
double dist = start.Distance(end) - maxSize;
math::Vector3 mid = start + dir*(dist*.5);
mid.z = box.GetCenter().z + box.GetSize().z + 2.0;
dir = end - mid;
dir.Correct();
dist = mid.Distance(end) - maxSize;
double yawAngle = atan2(dir.y, dir.x);
double pitchAngle = atan2(-dir.z, sqrt(dir.x*dir.x + dir.y*dir.y));
Ogre::Quaternion yawFinal(Ogre::Radian(yawAngle), Ogre::Vector3(0, 0, 1));
Ogre::Quaternion pitchFinal(Ogre::Radian(pitchAngle), Ogre::Vector3(0, 1, 0));
dir.Normalize();
double scale = maxSize / tan((this->HFOV()/2.0).Radian());
end = mid + dir*(dist - scale);
// dist = start.Distance(end);
// double vel = 5.0;
double time = 0.5; // dist / vel;
Ogre::Animation *anim =
this->scene->OgreSceneManager()->createAnimation("cameratrack", time);
anim->setInterpolationMode(Ogre::Animation::IM_SPLINE);
Ogre::NodeAnimationTrack *strack = anim->createNodeTrack(0, this->sceneNode);
Ogre::TransformKeyFrame *key;
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(end.x, end.y, end.z));
key->setRotation(yawFinal);
this->animState =
this->scene->OgreSceneManager()->createAnimationState("cameratrack");
this->animState->setTimePosition(0);
this->animState->setEnabled(true);
this->animState->setLoop(false);
this->prevAnimTime = common::Time::GetWallTime();
}
//////////////////////////////////////////////////
void OculusCamera::SetRenderTarget(Ogre::RenderTarget *_target)
{
this->renderTarget = _target;
this->Oculus();
Ogre::RenderTexture *rt =
this->dataPtr->renderTextureLeft->getBuffer()->getRenderTarget();
rt->addViewport(this->camera);
rt->getViewport(0)->setClearEveryFrame(true);
rt->getViewport(0)->setOverlaysEnabled(false);
rt->getViewport(0)->setShadowsEnabled(true);
rt->getViewport(0)->setBackgroundColour(
Conversions::Convert(this->scene->BackgroundColor()));
rt->getViewport(0)->setVisibilityMask(GZ_VISIBILITY_ALL &
~(GZ_VISIBILITY_GUI | GZ_VISIBILITY_SELECTABLE));
RTShaderSystem::AttachViewport(rt->getViewport(0), this->GetScene());
if (this->GetScene()->GetSkyX() != NULL)
rt->addListener(this->GetScene()->GetSkyX());
rt = this->dataPtr->renderTextureRight->getBuffer()->getRenderTarget();
rt->addViewport(this->dataPtr->rightCamera);
rt->getViewport(0)->setClearEveryFrame(true);
rt->getViewport(0)->setShadowsEnabled(true);
rt->getViewport(0)->setOverlaysEnabled(false);
rt->getViewport(0)->setBackgroundColour(
Conversions::Convert(this->scene->BackgroundColor()));
rt->getViewport(0)->setVisibilityMask(GZ_VISIBILITY_ALL &
~(GZ_VISIBILITY_GUI | GZ_VISIBILITY_SELECTABLE));
RTShaderSystem::AttachViewport(rt->getViewport(0), this->GetScene());
if (this->GetScene()->GetSkyX() != NULL)
rt->addListener(this->GetScene()->GetSkyX());
ovrFovPort fovLeft = this->dataPtr->hmd->DefaultEyeFov[ovrEye_Left];
ovrFovPort fovRight = this->dataPtr->hmd->DefaultEyeFov[ovrEye_Right];
float combinedTanHalfFovHorizontal =
std::max(fovLeft.LeftTan, fovLeft.RightTan);
float combinedTanHalfFovVertical = std::max(fovLeft.UpTan, fovLeft.DownTan);
float aspectRatio = combinedTanHalfFovHorizontal / combinedTanHalfFovVertical;
double vfov = 2.0 * atan(combinedTanHalfFovVertical);
this->camera->setAspectRatio(aspectRatio);
this->camera->setFOVy(Ogre::Radian(vfov));
this->dataPtr->rightCamera->setAspectRatio(aspectRatio);
this->dataPtr->rightCamera->setFOVy(Ogre::Radian(vfov));
ovrMatrix4f projL = ovrMatrix4f_Projection(fovLeft, 0.001,
g_defaultFarClip, true);
ovrMatrix4f projR = ovrMatrix4f_Projection(fovRight, 0.001,
g_defaultFarClip, true);
this->camera->setCustomProjectionMatrix(true,
Ogre::Matrix4(
projL.M[0][0], projL.M[0][1], projL.M[0][2], projL.M[0][3],
projL.M[1][0], projL.M[1][1], projL.M[1][2], projL.M[1][3],
projL.M[2][0], projL.M[2][1], projL.M[2][2], projL.M[2][3],
projL.M[3][0], projL.M[3][1], projL.M[3][2], projL.M[3][3]));
this->dataPtr->rightCamera->setCustomProjectionMatrix(true,
Ogre::Matrix4(
projR.M[0][0], projR.M[0][1], projR.M[0][2], projR.M[0][3],
projR.M[1][0], projR.M[1][1], projR.M[1][2], projR.M[1][3],
projR.M[2][0], projR.M[2][1], projR.M[2][2], projR.M[2][3],
projR.M[3][0], projR.M[3][1], projR.M[3][2], projR.M[3][3]));
// This seems like a mistake, but it's here on purpose.
// Problem: Shadows get rendered incorrectly with
// setCustomProjectionMatrix.
// Solution (HACK): Pass false to setCustomProjectionMatrix. Found this
// solution here: http://www.ogre3d.org/forums/viewtopic.php?f=2&t=60904
// and here: http://www.ogre3d.org/forums/viewtopic.php?f=2&t=78461
this->camera->setCustomProjectionMatrix(false,
Ogre::Matrix4(
projL.M[0][0], projL.M[0][1], projL.M[0][2], projL.M[0][3],
projL.M[1][0], projL.M[1][1], projL.M[1][2], projL.M[1][3],
projL.M[2][0], projL.M[2][1], projL.M[2][2], projL.M[2][3],
projL.M[3][0], projL.M[3][1], projL.M[3][2], projL.M[3][3]));
this->dataPtr->rightCamera->setCustomProjectionMatrix(false,
Ogre::Matrix4(
projR.M[0][0], projR.M[0][1], projR.M[0][2], projR.M[0][3],
projR.M[1][0], projR.M[1][1], projR.M[1][2], projR.M[1][3],
projR.M[2][0], projR.M[2][1], projR.M[2][2], projR.M[2][3],
projR.M[3][0], projR.M[3][1], projR.M[3][2], projR.M[3][3]));
this->initialized = true;
}
//////////////////////////////////////////////////
void OculusCamera::Oculus()
{
if (!this->Ready())
return;
// Create a separate scene manager to holds a distorted mesh and a camera.
// The distorted mesh receives the left and right camera images, and the
// camera in the externalSceneManager renders the distorted meshes.
this->dataPtr->externalSceneManager =
RenderEngine::Instance()->Root()->createSceneManager(Ogre::ST_GENERIC);
this->dataPtr->externalSceneManager->setAmbientLight(
Ogre::ColourValue(0.5, 0.5, 0.5));
ovrFovPort fovLeft = this->dataPtr->hmd->DefaultEyeFov[ovrEye_Left];
ovrFovPort fovRight = this->dataPtr->hmd->DefaultEyeFov[ovrEye_Right];
// Get the texture sizes
ovrSizei textureSizeLeft = ovrHmd_GetFovTextureSize(this->dataPtr->hmd,
ovrEye_Left, fovLeft, 1.0f);
ovrSizei textureSizeRight = ovrHmd_GetFovTextureSize(this->dataPtr->hmd,
ovrEye_Right, fovRight, 1.0f);
// Create the left and right render textures.
this->dataPtr->renderTextureLeft =
Ogre::TextureManager::getSingleton().createManual(
"OculusRiftRenderTextureLeft",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::TEX_TYPE_2D,
textureSizeLeft.w,
textureSizeLeft.h,
0,
Ogre::PF_R8G8B8,
Ogre::TU_RENDERTARGET);
this->dataPtr->renderTextureRight =
Ogre::TextureManager::getSingleton().createManual(
"OculusRiftRenderTextureRight",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::TEX_TYPE_2D,
textureSizeRight.w,
textureSizeRight.h,
0,
Ogre::PF_R8G8B8,
Ogre::TU_RENDERTARGET);
// Create the left and right materials.
Ogre::MaterialPtr matLeft =
Ogre::MaterialManager::getSingleton().getByName("Oculus/LeftEye");
Ogre::MaterialPtr matRight =
Ogre::MaterialManager::getSingleton().getByName("Oculus/RightEye");
// Attach materials to the render textures.
matLeft->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTexture(
this->dataPtr->renderTextureLeft);
matRight->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTexture(
this->dataPtr->renderTextureRight);
// Get eye description information
ovrEyeRenderDesc eyeRenderDesc[2];
eyeRenderDesc[0] = ovrHmd_GetRenderDesc(
this->dataPtr->hmd, ovrEye_Left, fovLeft);
eyeRenderDesc[1] = ovrHmd_GetRenderDesc(
this->dataPtr->hmd, ovrEye_Right, fovRight);
double combinedTanHalfFovHorizontal = std::max(
std::max(fovLeft.LeftTan, fovLeft.RightTan),
std::max(fovRight.LeftTan, fovRight.RightTan));
double combinedTanHalfFovVertical = std::max(
std::max(fovLeft.UpTan, fovLeft.DownTan),
std::max(fovRight.UpTan, fovRight.DownTan));
// Hold some values that are needed when creating the distortion meshes.
ovrVector2f uvScaleOffset[2];
ovrRecti viewports[2];
viewports[0].Pos.x = 0;
viewports[0].Pos.y = 0;
viewports[0].Size.w = textureSizeLeft.w;
viewports[0].Size.h = textureSizeLeft.h;
viewports[1].Pos.x = textureSizeLeft.w;
viewports[1].Pos.y = 0;
viewports[1].Size.w = textureSizeRight.w;
viewports[1].Size.h = textureSizeRight.h;
// Create a scene node in the external scene to hold the distortion
// meshes.
Ogre::SceneNode *meshNode =
this->dataPtr->externalSceneManager->getRootSceneNode()
->createChildSceneNode();
// Create the Distortion Meshes:
for (int eyeIndex = 0; eyeIndex < 2; ++eyeIndex)
{
ovrDistortionMesh meshData;
// Make the FOV symmetrical. Refer to Section 8.5.2 of the oculus SDF
// developers manual.
eyeRenderDesc[eyeIndex].Fov.RightTan = combinedTanHalfFovHorizontal;
eyeRenderDesc[eyeIndex].Fov.LeftTan = combinedTanHalfFovHorizontal;
eyeRenderDesc[eyeIndex].Fov.UpTan = combinedTanHalfFovVertical;
eyeRenderDesc[eyeIndex].Fov.DownTan = combinedTanHalfFovVertical;
ovrHmd_CreateDistortionMesh(
this->dataPtr->hmd,
eyeRenderDesc[eyeIndex].Eye,
eyeRenderDesc[eyeIndex].Fov,
0,
&meshData);
Ogre::GpuProgramParametersSharedPtr params;
if (eyeIndex == 0)
{
ovrHmd_GetRenderScaleAndOffset(eyeRenderDesc[eyeIndex].Fov,
textureSizeLeft, viewports[eyeIndex], uvScaleOffset);
params =
matLeft->getTechnique(0)->getPass(0)->getVertexProgramParameters();
}
else
{
ovrHmd_GetRenderScaleAndOffset(eyeRenderDesc[eyeIndex].Fov,
textureSizeRight, viewports[eyeIndex], uvScaleOffset);
params =
matRight->getTechnique(0)->getPass(0)->getVertexProgramParameters();
}
#if OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR >= 9
params->setNamedConstant("eyeToSourceUVScale",
Ogre::Vector2(uvScaleOffset[0].x, uvScaleOffset[0].y));
params->setNamedConstant("eyeToSourceUVOffset",
Ogre::Vector2(uvScaleOffset[1].x, uvScaleOffset[1].y));
#else
params->setNamedConstant("eyeToSourceUVScale",
Ogre::Vector4(uvScaleOffset[0].x, uvScaleOffset[0].y, 0, 0));
params->setNamedConstant("eyeToSourceUVOffset",
Ogre::Vector4(uvScaleOffset[1].x, uvScaleOffset[1].y, 0, 0));
#endif
Ogre::ManualObject *externalObj;
// create ManualObject
if (eyeIndex == 0)
{
externalObj =
this->dataPtr->externalSceneManager->createManualObject(
"OculusRiftRenderObjectLeft");
externalObj->begin("Oculus/LeftEye",
Ogre::RenderOperation::OT_TRIANGLE_LIST);
}
else
{
externalObj =
this->dataPtr->externalSceneManager->createManualObject(
"OculusRiftRenderObjectRight");
externalObj->begin("Oculus/RightEye",
Ogre::RenderOperation::OT_TRIANGLE_LIST);
}
for (unsigned int i = 0; i < meshData.VertexCount; ++i)
{
ovrDistortionVertex v = meshData.pVertexData[i];
externalObj->position(v.ScreenPosNDC.x, v.ScreenPosNDC.y, 0);
externalObj->textureCoord(v.TanEyeAnglesR.x, v.TanEyeAnglesR.y);
externalObj->textureCoord(v.TanEyeAnglesG.x, v.TanEyeAnglesG.y);
externalObj->textureCoord(v.TanEyeAnglesB.x, v.TanEyeAnglesB.y);
float vig = std::max(v.VignetteFactor, 0.0f);
externalObj->colour(vig, vig, vig, vig);
}
for (unsigned int i = 0; i < meshData.IndexCount; ++i)
{
externalObj->index(meshData.pIndexData[i]);
}
// Manual render object complete
externalObj->end();
// Attach externalObj object to the node
meshNode->attachObject(externalObj);
// Free up memory
ovrHmd_DestroyDistortionMesh(&meshData);
}
// Position the node in the scene
meshNode->setPosition(0, 0, -1);
meshNode->setScale(1, 1, -1);
// Create the external camera
this->dataPtr->externalCamera =
this->dataPtr->externalSceneManager->createCamera(
"_OculusRiftExternalCamera_INTERNAL_");
this->dataPtr->externalCamera->setFarClipDistance(50);
this->dataPtr->externalCamera->setNearClipDistance(0.001);
this->dataPtr->externalCamera->setProjectionType(Ogre::PT_ORTHOGRAPHIC);
this->dataPtr->externalCamera->setOrthoWindow(2, 2);
this->dataPtr->externalSceneManager->getRootSceneNode()->attachObject(
this->dataPtr->externalCamera);
// Create the external viewport
this->dataPtr->externalViewport = this->renderTarget->addViewport(
this->dataPtr->externalCamera);
this->dataPtr->externalViewport->setBackgroundColour(
Ogre::ColourValue::Black);
this->dataPtr->externalViewport->setOverlaysEnabled(true);
// Set up IPD in meters:
float ipd = ovrHmd_GetFloat(this->dataPtr->hmd, OVR_KEY_IPD, 0.064f);
this->camera->setPosition(-ipd * 0.5, 0, 0);
this->dataPtr->rightCamera->setPosition(ipd * 0.5, 0, 0);
}
/////////////////////////////////////////////////
void OculusCamera::AdjustAspect(double _v)
{
if (!this->Ready())
return;
for (int i = 0; i < 2; ++i)
{
Ogre::Camera *cam = i == 0 ? this->camera : this->dataPtr->rightCamera;
cam->setAspectRatio(cam->getAspectRatio() + _v);
}
}