Oculus VR (Rift) support

Input device and shaders for supporting the Oculus Rift.
This commit is contained in:
DavidWyand-GG 2013-04-10 01:05:26 -04:00
parent 2123365d4d
commit de7a72d82a
24 changed files with 3214 additions and 0 deletions

View file

@ -0,0 +1,188 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/oculusVR/barrelDistortionPostEffect.h"
#include "console/consoleTypes.h"
#include "console/engineAPI.h"
#include "gfx/gfxDevice.h"
#include "platform/input/oculusVR/oculusVRDevice.h"
extern bool gEditingMission;
ConsoleDocClass( BarrelDistortionPostEffect,
"@brief A fullscreen shader effect used with the Oculus Rift.\n\n"
"@section PFXTextureIdentifiers\n\n"
"@ingroup Rendering\n"
);
IMPLEMENT_CONOBJECT(BarrelDistortionPostEffect);
BarrelDistortionPostEffect::BarrelDistortionPostEffect()
: PostEffect(),
mHmdWarpParamSC(NULL),
mScaleSC(NULL),
mScaleInSC(NULL),
mLensCenterSC(NULL),
mScreenCenterSC(NULL)
{
mHMDIndex = 0;
mSensorIndex = 0;
mScaleOutput = 1.0f;
}
BarrelDistortionPostEffect::~BarrelDistortionPostEffect()
{
}
void BarrelDistortionPostEffect::initPersistFields()
{
addField( "hmdIndex", TypeS32, Offset( mHMDIndex, BarrelDistortionPostEffect ),
"Oculus VR HMD index to reference." );
addField( "sensorIndex", TypeS32, Offset( mSensorIndex, BarrelDistortionPostEffect ),
"Oculus VR sensor index to reference." );
addField( "scaleOutput", TypeF32, Offset( mScaleOutput, BarrelDistortionPostEffect ),
"Used to increase the size of the window into the world at the expense of apparent resolution." );
Parent::initPersistFields();
}
bool BarrelDistortionPostEffect::onAdd()
{
if( !Parent::onAdd() )
return false;
return true;
}
void BarrelDistortionPostEffect::onRemove()
{
Parent::onRemove();
}
void BarrelDistortionPostEffect::_setupConstants( const SceneRenderState *state )
{
Parent::_setupConstants(state);
// Define the shader constants
if(!mHmdWarpParamSC)
mHmdWarpParamSC = mShader->getShaderConstHandle( "$HmdWarpParam" );
if(!mScaleSC)
mScaleSC = mShader->getShaderConstHandle( "$Scale" );
if(!mScaleInSC)
mScaleInSC = mShader->getShaderConstHandle( "$ScaleIn" );
if(!mLensCenterSC)
mLensCenterSC = mShader->getShaderConstHandle( "$LensCenter" );
if(!mScreenCenterSC)
mScreenCenterSC = mShader->getShaderConstHandle( "$ScreenCenter" );
const Point2I &resolution = GFX->getActiveRenderTarget()->getSize();
F32 widthScale = 0.5f;
F32 heightScale = 1.0f;
F32 aspectRatio = (resolution.x * 0.5f) / resolution.y;
// Set up the HMD dependant shader constants
if(ManagedSingleton<OculusVRDevice>::instanceOrNull() && OCULUSVRDEV->getHMDDevice(mHMDIndex))
{
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(mHMDIndex);
if(mHmdWarpParamSC->isValid())
{
const Point4F& distortion = hmd->getKDistortion();
mShaderConsts->set( mHmdWarpParamSC, distortion );
}
if(mScaleSC->isValid())
{
F32 scaleFactor = hmd->getDistortionScale();
if(!mIsZero(mScaleOutput))
{
scaleFactor /= mScaleOutput;
}
Point2F scale;
scale.x = widthScale * 0.5f * scaleFactor;
scale.y = heightScale * 0.5f * scaleFactor * aspectRatio;
mShaderConsts->set( mScaleSC, scale );
}
if(mLensCenterSC->isValid())
{
F32 xCenterOffset = hmd->getCenterOffset();
Point3F lensCenter;
lensCenter.x = (widthScale + xCenterOffset * 0.5f) * 0.5f;
lensCenter.y = (widthScale - xCenterOffset * 0.5f) * 0.5f;
lensCenter.z = heightScale * 0.5f;
mShaderConsts->set( mLensCenterSC, lensCenter );
}
}
else
{
if(mHmdWarpParamSC->isValid())
{
mShaderConsts->set( mHmdWarpParamSC, Point4F(0.0f, 0.0f, 0.0f, 0.0f) );
}
if(mScaleSC->isValid())
{
mShaderConsts->set( mScaleSC, Point2F(1.0f, 1.0f) );
}
if(mLensCenterSC->isValid())
{
Point3F lensCenter;
lensCenter.x = widthScale * 0.5f;
lensCenter.y = widthScale * 0.5f;
lensCenter.z = heightScale * 0.5f;
mShaderConsts->set( mLensCenterSC, lensCenter );
}
}
if(mScaleInSC->isValid())
{
Point2F scaleIn;
scaleIn.x = 2.0f / widthScale;
scaleIn.y = 2.0f / heightScale / aspectRatio;
mShaderConsts->set( mScaleInSC, scaleIn );
}
if(mScreenCenterSC->isValid())
{
mShaderConsts->set( mScreenCenterSC, Point2F(widthScale * 0.5f, heightScale * 0.5f) );
}
}
void BarrelDistortionPostEffect::process(const SceneRenderState *state, GFXTexHandle &inOutTex, const RectI *inTexViewport)
{
// Don't draw the post effect if the editor is active
if(gEditingMission)
return;
Parent::process(state, inOutTex, inTexViewport);
}

View file

@ -0,0 +1,68 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _BARRELDISTORTIONPOSTEFFECT_H_
#define _BARRELDISTORTIONPOSTEFFECT_H_
#include "postFx/postEffect.h"
class BarrelDistortionPostEffect : public PostEffect
{
typedef PostEffect Parent;
protected:
GFXShaderConstHandle *mHmdWarpParamSC;
GFXShaderConstHandle *mScaleSC;
GFXShaderConstHandle *mScaleInSC;
GFXShaderConstHandle *mLensCenterSC;
GFXShaderConstHandle *mScreenCenterSC;
// Oculus VR HMD index to reference
S32 mHMDIndex;
// Oculus VR sensor index to reference
S32 mSensorIndex;
// Used to increase the size of the window into the world at the
// expense of apparent resolution.
F32 mScaleOutput;
protected:
virtual void _setupConstants( const SceneRenderState *state );
public:
BarrelDistortionPostEffect();
virtual ~BarrelDistortionPostEffect();
DECLARE_CONOBJECT(BarrelDistortionPostEffect);
// SimObject
virtual bool onAdd();
virtual void onRemove();
static void initPersistFields();
virtual void process( const SceneRenderState *state,
GFXTexHandle &inOutTex,
const RectI *inTexViewport = NULL );
};
#endif // _BARRELDISTORTIONPOSTEFFECT_H_

View file

@ -0,0 +1,34 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _OCULUSVRCONSTANTS_H_
#define _OCULUSVRCONSTANTS_H_
namespace OculusVRConstants
{
enum Constants {
DefaultOVRBase = 0,
MaxSensors = 1,
};
}
#endif // _OCULUSVRCONSTANTS_H_

View file

@ -0,0 +1,844 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/oculusVR/oculusVRDevice.h"
#include "platform/platformInput.h"
#include "core/module.h"
#include "console/engineAPI.h"
#include "T3D/gameBase/gameConnection.h"
MODULE_BEGIN( OculusVRDevice )
MODULE_INIT_AFTER( InputEventManager )
MODULE_SHUTDOWN_BEFORE( InputEventManager )
MODULE_INIT
{
OculusVRDevice::staticInit();
ManagedSingleton< OculusVRDevice >::createSingleton();
if(OculusVRDevice::smEnableDevice)
{
OCULUSVRDEV->enable();
}
// Register the device with the Input Event Manager
INPUTMGR->registerDevice(OCULUSVRDEV);
}
MODULE_SHUTDOWN
{
INPUTMGR->unregisterDevice(OCULUSVRDEV);
ManagedSingleton< OculusVRDevice >::deleteSingleton();
}
MODULE_END;
//-----------------------------------------------------------------------------
// OculusVRDevice
//-----------------------------------------------------------------------------
bool OculusVRDevice::smEnableDevice = true;
bool OculusVRDevice::smSimulateHMD = true;
bool OculusVRDevice::smGenerateAngleAxisRotationEvents = true;
bool OculusVRDevice::smGenerateEulerRotationEvents = false;
bool OculusVRDevice::smGenerateRotationAsAxisEvents = false;
F32 OculusVRDevice::smMaximumAxisAngle = 25.0f;
bool OculusVRDevice::smGenerateWholeFrameEvents = false;
OculusVRDevice::OculusVRDevice()
{
// From IInputDevice
dStrcpy(mName, "oculusvr");
mDeviceType = INPUTMGR->getNextDeviceType();
//
mEnabled = false;
mActive = false;
// We don't current support scaling of the input texture. The graphics pipeline will
// need to be modified for this.
mScaleInputTexture = false;
mDeviceManager = NULL;
mListener = NULL;
buildCodeTable();
}
OculusVRDevice::~OculusVRDevice()
{
cleanUp();
}
void OculusVRDevice::staticInit()
{
Con::addVariable("pref::OculusVR::EnableDevice", TypeBool, &smEnableDevice,
"@brief If true, the Oculus VR device will be enabled, if present.\n\n"
"@ingroup Game");
Con::addVariable("OculusVR::GenerateAngleAxisRotationEvents", TypeBool, &smGenerateAngleAxisRotationEvents,
"@brief If true, broadcast sensor rotation events as angled axis.\n\n"
"@ingroup Game");
Con::addVariable("OculusVR::GenerateEulerRotationEvents", TypeBool, &smGenerateEulerRotationEvents,
"@brief If true, broadcast sensor rotation events as Euler angles about the X, Y and Z axis.\n\n"
"@ingroup Game");
Con::addVariable("OculusVR::GenerateRotationAsAxisEvents", TypeBool, &smGenerateRotationAsAxisEvents,
"@brief If true, broadcast sensor rotation as axis events.\n\n"
"@ingroup Game");
Con::addVariable("OculusVR::MaximumAxisAngle", TypeF32, &smMaximumAxisAngle,
"@brief The maximum sensor angle when used as an axis event as measured from a vector pointing straight up (in degrees).\n\n"
"Should range from 0 to 90 degrees.\n\n"
"@ingroup Game");
Con::addVariable("OculusVR::GenerateWholeFrameEvents", TypeBool, &smGenerateWholeFrameEvents,
"@brief Indicates that a whole frame event should be generated and frames should be buffered.\n\n"
"@ingroup Game");
}
void OculusVRDevice::cleanUp()
{
disable();
}
void OculusVRDevice::buildCodeTable()
{
// Build the sensor device code table
OculusVRSensorDevice::buildCodeTable();
}
void OculusVRDevice::addHMDDevice(OVR::HMDDevice* hmd)
{
if(!hmd)
return;
OVR::HMDInfo hmdInfo;
if(!hmd->GetDeviceInfo(&hmdInfo))
return;
OculusVRHMDDevice* hmdd = new OculusVRHMDDevice();
hmdd->set(hmd, hmdInfo, mScaleInputTexture);
mHMDDevices.push_back(hmdd);
Con::printf(" HMD found: %s by %s [v%d]", hmdInfo.ProductName, hmdInfo.Manufacturer, hmdInfo.Version);
}
void OculusVRDevice::createSimulatedHMD()
{
OculusVRHMDDevice* hmdd = new OculusVRHMDDevice();
hmdd->createSimulation(OculusVRHMDDevice::ST_RIFT_PREVIEW, mScaleInputTexture);
mHMDDevices.push_back(hmdd);
Con::printf(" HMD simulated: %s by %s [v%d]", hmdd->getProductName(), hmdd->getManufacturer(), hmdd->getVersion());
}
void OculusVRDevice::addSensorDevice(OVR::SensorDevice* sensor)
{
if(!sensor)
return;
OVR::SensorInfo sensorInfo;
if(!sensor->GetDeviceInfo(&sensorInfo))
return;
OculusVRSensorDevice* sensord = new OculusVRSensorDevice();
sensord->set(sensor, sensorInfo, mSensorDevices.size());
mSensorDevices.push_back(sensord);
Con::printf(" Sensor found: %s by %s [v%d] %s", sensorInfo.ProductName, sensorInfo.Manufacturer, sensorInfo.Version, sensorInfo.SerialNumber);
}
void OculusVRDevice::createSimulatedSensor()
{
OculusVRSensorDevice* sensord = new OculusVRSensorDevice();
sensord->createSimulation(OculusVRSensorDevice::ST_RIFT_PREVIEW, mSensorDevices.size());
mSensorDevices.push_back(sensord);
Con::printf(" Sensor simulated: %s by %s [v%d] %s", sensord->getProductName(), sensord->getManufacturer(), sensord->getVersion(), sensord->getSerialNumber());
}
bool OculusVRDevice::enable()
{
// Start off with disabling the device if it is already enabled
disable();
Con::printf("Oculus VR Device Init:");
OVR::System::Init(OVR::Log::ConfigureDefaultLog(OVR::LogMask_All));
if(OVR::System::IsInitialized())
{
mEnabled = true;
// Create the OVR device manager
mDeviceManager = OVR::DeviceManager::Create();
if(!mDeviceManager)
{
if(smSimulateHMD)
{
Con::printf(" Could not create a HMD device manager. Simulating a HMD.");
Con::printf(" ");
createSimulatedHMD();
createSimulatedSensor();
setActive(true);
return true;
}
else
{
Con::printf(" Could not create a HMD device manager.");
Con::printf(" ");
mEnabled = false;
OVR::System::Destroy();
return false;
}
}
// Provide a message listener
// NOTE: Commented out as non-functional in 0.1.2
//mListener = new DeviceListener(this);
//mDeviceManager->SetMessageHandler(mListener);
// Enumerate HMDs and pick the first one
OVR::HMDDevice* hmd = mDeviceManager->EnumerateDevices<OVR::HMDDevice>().CreateDevice();
if(hmd)
{
// Add the HMD to our list
addHMDDevice(hmd);
// Detect and add any sensor on the HMD
OVR::SensorDevice* sensor = hmd->GetSensor();
if(sensor)
{
addSensorDevice(sensor);
}
else
{
Con::printf(" No sensor device on HMD.");
}
setActive(true);
}
else
{
if(smSimulateHMD)
{
Con::printf(" Could not enumerate a HMD device. Simulating a HMD.");
createSimulatedHMD();
createSimulatedSensor();
setActive(true);
}
else
{
Con::printf(" Could not enumerate a HMD device.");
}
}
}
Con::printf(" ");
return false;
}
void OculusVRDevice::disable()
{
for(U32 i=0; i<mSensorDevices.size(); ++i)
{
delete mSensorDevices[i];
}
mSensorDevices.clear();
for(U32 i=0; i<mHMDDevices.size(); ++i)
{
delete mHMDDevices[i];
}
mHMDDevices.clear();
if(mDeviceManager)
{
mDeviceManager->Release();
mDeviceManager = NULL;
}
if(mEnabled)
{
OVR::System::Destroy();
}
if(mListener)
{
delete mListener;
mListener = NULL;
}
setActive(false);
mEnabled = false;
}
bool OculusVRDevice::process()
{
if(!mEnabled)
return false;
if(!getActive())
return false;
//Build the maximum axis angle to be passed into the sensor process()
F32 maxAxisRadius = mSin(mDegToRad(smMaximumAxisAngle));
// Process each sensor
for(U32 i=0; i<mSensorDevices.size(); ++i)
{
mSensorDevices[i]->process(mDeviceType, smGenerateAngleAxisRotationEvents, smGenerateEulerRotationEvents, smGenerateRotationAsAxisEvents, maxAxisRadius);
}
return true;
}
//-----------------------------------------------------------------------------
bool OculusVRDevice::providesYFOV() const
{
if(!mHMDDevices.size())
return false;
return true;
}
F32 OculusVRDevice::getYFOV() const
{
if(!mHMDDevices.size())
return 0.0f;
const OculusVRHMDDevice* hmd = getHMDDevice(0);
if(!hmd)
return 0.0f;
return hmd->getYFOV();
}
bool OculusVRDevice::providesEyeOffset() const
{
if(!mHMDDevices.size())
return false;
return true;
}
const Point3F& OculusVRDevice::getEyeOffset() const
{
if(!mHMDDevices.size())
return Point3F::Zero;
const OculusVRHMDDevice* hmd = getHMDDevice(0);
if(!hmd)
return Point3F::Zero;
return hmd->getEyeWorldOffset();
}
bool OculusVRDevice::providesProjectionOffset() const
{
if(!mHMDDevices.size())
return false;
return true;
}
const Point2F& OculusVRDevice::getProjectionOffset() const
{
if(!mHMDDevices.size())
return Point2F::Zero;
const OculusVRHMDDevice* hmd = getHMDDevice(0);
if(!hmd)
return Point2F::Zero;
return hmd->getProjectionCenterOffset();
}
//-----------------------------------------------------------------------------
const OculusVRHMDDevice* OculusVRDevice::getHMDDevice(U32 index) const
{
if(index >= mHMDDevices.size())
return NULL;
return mHMDDevices[index];
}
//-----------------------------------------------------------------------------
const OculusVRSensorDevice* OculusVRDevice::getSensorDevice(U32 index) const
{
if(index >= mSensorDevices.size())
return NULL;
return mSensorDevices[index];
}
EulerF OculusVRDevice::getSensorEulerRotation(U32 index)
{
if(index >= mSensorDevices.size())
return Point3F::Zero;
return mSensorDevices[index]->getEulerRotation();
}
F32 OculusVRDevice::getSensorPredictionTime(U32 index)
{
const OculusVRSensorDevice* sensor = getSensorDevice(index);
if(!sensor || !sensor->isValid())
return 0.0f;
return sensor->getPredictionTime();
}
void OculusVRDevice::setSensorPredictionTime(U32 index, F32 dt)
{
if(index >= mSensorDevices.size())
return;
OculusVRSensorDevice* sensor = mSensorDevices[index];
if(!sensor->isValid())
return;
sensor->setPredictionTime(dt);
}
void OculusVRDevice::setAllSensorPredictionTime(F32 dt)
{
for(U32 i=0; i<mSensorDevices.size(); ++i)
{
mSensorDevices[i]->setPredictionTime(dt);
}
}
void OculusVRDevice::resetAllSensors()
{
// Reset each sensor
for(U32 i=0; i<mSensorDevices.size(); ++i)
{
mSensorDevices[i]->reset();
}
}
//-----------------------------------------------------------------------------
void OculusVRDevice::DeviceListener::OnMessage(const OVR::Message& msg)
{
switch(msg.Type)
{
case OVR::Message_DeviceAdded:
{
const OVR::MessageDeviceStatus* status = static_cast<const OVR::MessageDeviceStatus*>(&msg);
Con::printf("OVR: Device added of type: %d", status->Handle.GetType());
}
break;
case OVR::Message_DeviceRemoved:
Con::printf("OVR: Device removed of type: %d", msg.pDevice->GetType());
break;
default:
break;
}
}
//-----------------------------------------------------------------------------
DefineEngineFunction(isOculusVRDeviceActive, bool, (),,
"@brief Used to determine if the Oculus VR input device is active\n\n"
"The Oculus VR device is considered active when the library has been "
"initialized and either a real of simulated HMD is present.\n\n"
"@return True if the Oculus VR input device is active.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return false;
}
return OCULUSVRDEV->getActive();
}
//-----------------------------------------------------------------------------
DefineEngineFunction(setOVRHMDAsGameConnectionDisplayDevice, bool, (GameConnection* conn),,
"@brief Sets the first HMD to be a GameConnection's display device\n\n"
"@param conn The GameConnection to set.\n"
"@return True if the GameConnection display device was set.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
Con::errorf("setOVRHMDAsGameConnectionDisplayDevice(): No Oculus VR Device present.");
return false;
}
if(!conn)
{
Con::errorf("setOVRHMDAsGameConnectionDisplayDevice(): Invalid GameConnection.");
return false;
}
conn->setDisplayDevice(OCULUSVRDEV);
return true;
}
//-----------------------------------------------------------------------------
DefineEngineFunction(getOVRHMDCount, S32, (),,
"@brief Get the number of HMD devices that are currently connected.\n\n"
"@return The number of Oculus VR HMD devices that are currently connected.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return 0;
}
return OCULUSVRDEV->getHMDCount();
}
DefineEngineFunction(isOVRHMDSimulated, bool, (S32 index),,
"@brief Determines if the requested OVR HMD is simulated or real.\n\n"
"@param index The HMD index.\n"
"@return True if the HMD is simulated.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return true;
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return true;
}
return hmd->isSimulated();
}
DefineEngineFunction(getOVRHMDProductName, const char*, (S32 index),,
"@brief Retrieves the HMD product name.\n\n"
"@param index The HMD index.\n"
"@return The name of the HMD product.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return "";
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return "";
}
return hmd->getProductName();
}
DefineEngineFunction(getOVRHMDManufacturer, const char*, (S32 index),,
"@brief Retrieves the HMD manufacturer name.\n\n"
"@param index The HMD index.\n"
"@return The manufacturer of the HMD product.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return "";
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return "";
}
return hmd->getManufacturer();
}
DefineEngineFunction(getOVRHMDVersion, S32, (S32 index),,
"@brief Retrieves the HMD version number.\n\n"
"@param index The HMD index.\n"
"@return The version number of the HMD product.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return -1;
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return -1;
}
return hmd->getVersion();
}
DefineEngineFunction(getOVRHMDDisplayDeviceName, const char*, (S32 index),,
"@brief Windows display device name used in EnumDisplaySettings/CreateDC.\n\n"
"@param index The HMD index.\n"
"@return The name of the HMD display device, if any.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return "";
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return "";
}
return hmd->getDisplayDeviceName();
}
DefineEngineFunction(getOVRHMDResolution, Point2I, (S32 index),,
"@brief Provides the OVR HMD screen resolution.\n\n"
"@param index The HMD index.\n"
"@return A two component string with the screen's resolution.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return Point2I(1280, 800);
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return Point2I(1280, 800);
}
return hmd->getResolution();
}
DefineEngineFunction(getOVRHMDDistortionCoefficients, String, (S32 index),,
"@brief Provides the OVR HMD distortion coefficients.\n\n"
"@param index The HMD index.\n"
"@return A four component string with the distortion coefficients.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return "0 0 0 0";
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return "0 0 0 0";
}
const Point4F& k = hmd->getKDistortion();
char buf[256];
dSprintf(buf, 256, "%g %g %g %g", k.x, k.y, k.z, k.w);
return buf;
}
DefineEngineFunction(getOVRHMDEyeXOffsets, Point2F, (S32 index),,
"@brief Provides the OVR HMD eye x offsets in uv coordinates.\n\n"
"@param index The HMD index.\n"
"@return A two component string with the left and right eye x offsets.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return Point2F(0.5, 0.5);
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return Point2F(0.5, 0.5);
}
// X component is left, Y component is right
const Point2F& offset = hmd->getEyeUVOffset();
return offset;
}
DefineEngineFunction(getOVRHMDXCenterOffset, F32, (S32 index),,
"@brief Provides the OVR HMD calculated XCenterOffset.\n\n"
"@param index The HMD index.\n"
"@return The calculated XCenterOffset.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return 0.0f;
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return 0.0f;
}
F32 offset = hmd->getCenterOffset();
return offset;
}
DefineEngineFunction(getOVRHMDDistortionScale, F32, (S32 index),,
"@brief Provides the OVR HMD calculated distortion scale.\n\n"
"@param index The HMD index.\n"
"@return The calculated distortion scale.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return 1.0f;
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return 1.0f;
}
F32 scale = hmd->getDistortionScale();
return scale;
}
DefineEngineFunction(getOVRHMDYFOV, F32, (S32 index),,
"@brief Provides the OVR HMD calculated Y FOV.\n\n"
"@param index The HMD index.\n"
"@return The calculated Y FOV.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return 1.0f;
}
const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index);
if(!hmd)
{
return 1.0f;
}
F32 fov = hmd->getYFOV();
return mRadToDeg(fov);
}
//-----------------------------------------------------------------------------
DefineEngineFunction(getOVRSensorCount, S32, (),,
"@brief Get the number of sensor devices that are currently connected.\n\n"
"@return The number of Oculus VR sensor devices that are currently connected.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return 0;
}
return OCULUSVRDEV->getSensorCount();
}
DefineEngineFunction(getOVRSensorEulerRotation, Point3F, (S32 index),,
"@brief Get the Euler rotation values for the given sensor index.\n\n"
"@param index The sensor index.\n"
"@return The Euler rotation values of the Oculus VR sensor, in degrees.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return Point3F::Zero;
}
EulerF rot = OCULUSVRDEV->getSensorEulerRotation(index);
return Point3F(mRadToDeg(rot.x), mRadToDeg(rot.y), mRadToDeg(rot.z));
}
DefineEngineFunction(getOVRSensorPredictionTime, F32, (S32 index),,
"@brief Get the prediction time set for the given sensor index.\n\n"
"@param index The sensor index.\n"
"@return The prediction time of the Oculus VR sensor, given in seconds.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return 0;
}
return OCULUSVRDEV->getSensorPredictionTime(index);
}
DefineEngineFunction(setSensorPredictionTime, void, (S32 index, F32 dt),,
"@brief Set the prediction time set for the given sensor index.\n\n"
"@param index The sensor index.\n"
"@param dt The prediction time to set given in seconds. Setting to 0 disables prediction.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return;
}
OCULUSVRDEV->setSensorPredictionTime(index, dt);
}
DefineEngineFunction(setAllSensorPredictionTime, void, (F32 dt),,
"@brief Set the prediction time set for all sensors.\n\n"
"@param dt The prediction time to set given in seconds. Setting to 0 disables prediction.\n"
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return;
}
OCULUSVRDEV->setAllSensorPredictionTime(dt);
}
DefineEngineFunction(ovrResetAllSensors, void, (),,
"@brief Resets all Oculus VR sensors.\n\n"
"This resets all sensor orientations such that their 'normal' rotation "
"is defined when this function is called. This defines an HMD's forwards "
"and up direction, for example."
"@ingroup Game")
{
if(!ManagedSingleton<OculusVRDevice>::instanceOrNull())
{
return;
}
OCULUSVRDEV->resetAllSensors();
}

View file

@ -0,0 +1,152 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _OCULUSVRDEVICE_H_
#define _OCULUSVRDEVICE_H_
#include "platform/input/oculusVR/oculusVRConstants.h"
#include "platform/input/oculusVR/oculusVRHMDDevice.h"
#include "platform/input/oculusVR/oculusVRSensorDevice.h"
#include "platform/input/IInputDevice.h"
#include "platform/input/event.h"
#include "platform/output/IDisplayDevice.h"
#include "core/util/tSingleton.h"
#include "math/mQuat.h"
#include "math/mPoint4.h"
#include "OVR.h"
#define DEFAULT_RIFT_UNIT 0
class OculusVRDevice : public IInputDevice, public IDisplayDevice
{
public:
static bool smEnableDevice;
// If no HMD is present simulate it being available
static bool smSimulateHMD;
// Type of rotation events to broadcast
static bool smGenerateAngleAxisRotationEvents;
static bool smGenerateEulerRotationEvents;
// Broadcast sensor rotation as axis
static bool smGenerateRotationAsAxisEvents;
// The maximum sensor angle when used as an axis event
// as measured from a vector pointing straight up (in degrees)
static F32 smMaximumAxisAngle;
// Indicates that a whole frame event should be generated and frames
// should be buffered.
static bool smGenerateWholeFrameEvents;
protected:
class DeviceListener : public OVR::MessageHandler
{
protected:
OculusVRDevice* mOwner;
public:
DeviceListener(OculusVRDevice* owner) { mOwner = owner; }
virtual ~DeviceListener() { mOwner = NULL; }
virtual void OnMessage(const OVR::Message&);
};
// Our OVR SDK device listener class
DeviceListener* mListener;
// The OVR SDK device manager
OVR::DeviceManager* mDeviceManager;
// Discovered HMD devices
Vector<OculusVRHMDDevice*> mHMDDevices;
// Discovered sensor devices
Vector<OculusVRSensorDevice*> mSensorDevices;
/// Is the device active
bool mActive;
// Should the input texture into the HMD (the render target that the scene has been
// rendered to) be scaled according to the HMD's distortion calculation?
bool mScaleInputTexture;
protected:
void cleanUp();
/// Build out the codes used for controller actions with the
/// Input Event Manager
void buildCodeTable();
void addHMDDevice(OVR::HMDDevice* hmd);
void createSimulatedHMD();
void addSensorDevice(OVR::SensorDevice* sensor);
void createSimulatedSensor();
public:
OculusVRDevice();
~OculusVRDevice();
static void staticInit();
bool enable();
void disable();
bool getActive() { return mActive; }
void setActive(bool state) { mActive = state; }
bool process();
// IDisplayDevice
virtual bool providesYFOV() const;
virtual F32 getYFOV() const;
virtual bool providesEyeOffset() const;
virtual const Point3F& getEyeOffset() const;
virtual bool providesProjectionOffset() const;
virtual const Point2F& getProjectionOffset() const;
// HMDs
U32 getHMDCount() const { return mHMDDevices.size(); }
const OculusVRHMDDevice* getHMDDevice(U32 index) const;
// Sensors
U32 getSensorCount() const { return mSensorDevices.size(); }
const OculusVRSensorDevice* getSensorDevice(U32 index) const;
EulerF getSensorEulerRotation(U32 index);
F32 getSensorPredictionTime(U32 index);
void setSensorPredictionTime(U32 index, F32 dt);
void setAllSensorPredictionTime(F32 dt);
void resetAllSensors();
public:
// For ManagedSingleton.
static const char* getSingletonName() { return "OculusVRDevice"; }
};
/// Returns the OculusVRDevice singleton.
#define OCULUSVRDEV ManagedSingleton<OculusVRDevice>::instance()
#endif // _OCULUSVRDEVICE_H_

View file

@ -0,0 +1,208 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/oculusVR/oculusVRHMDDevice.h"
OculusVRHMDDevice::OculusVRHMDDevice()
{
mIsValid = false;
mIsSimulation = false;
mDevice = NULL;
}
OculusVRHMDDevice::~OculusVRHMDDevice()
{
cleanUp();
}
void OculusVRHMDDevice::cleanUp()
{
if(mDevice)
{
mDevice->Release();
mDevice = NULL;
}
mIsValid = false;
}
void OculusVRHMDDevice::set(OVR::HMDDevice* hmd, OVR::HMDInfo& info, bool calculateDistortionScale)
{
mIsValid = false;
mIsSimulation = false;
mDevice = hmd;
// DeviceInfo
mProductName = info.ProductName;
mManufacturer = info.Manufacturer;
mVersion = info.Version;
mDisplayDeviceName = info.DisplayDeviceName;
mResolution.x = info.HResolution;
mResolution.y = info.VResolution;
mScreenSize.x = info.HScreenSize;
mScreenSize.y = info.VScreenSize;
mVerticalEyeCenter = info.VScreenCenter;
mEyeToScreen = info.EyeToScreenDistance;
mLensSeparation = info.LensSeparationDistance;
mInterpupillaryDistance = info.InterpupillaryDistance;
mKDistortion.x = info.DistortionK[0];
mKDistortion.y = info.DistortionK[1];
mKDistortion.z = info.DistortionK[2];
mKDistortion.w = info.DistortionK[3];
// Calculated values
calculateValues(calculateDistortionScale);
mIsValid = true;
}
void OculusVRHMDDevice::createSimulation(SimulationTypes simulationType, bool calculateDistortionScale)
{
if(simulationType == ST_RIFT_PREVIEW)
{
createSimulatedPreviewRift(calculateDistortionScale);
}
}
void OculusVRHMDDevice::createSimulatedPreviewRift(bool calculateDistortionScale)
{
mIsValid = true;
mIsSimulation = true;
mProductName = "Oculus Rift DK1-SLA1";
mManufacturer = "Oculus VR";
mVersion = 0;
mDisplayDeviceName = "";
mResolution.x = 1280;
mResolution.y = 800;
mScreenSize.x = 0.14975999f;
mScreenSize.y = 0.093599997f;
mVerticalEyeCenter = 0.046799999f;
mEyeToScreen = 0.041000001f;
mLensSeparation = 0.064000003f;
mInterpupillaryDistance = 0.064000003f;
mKDistortion.x = 1.0000000f;
mKDistortion.y = 0.22000000f;
mKDistortion.z = 0.23999999f;
mKDistortion.w = 0.00000000f;
calculateValues(calculateDistortionScale);
}
// Computes scale that should be applied to the input render texture
// before distortion to fit the result in the same screen size.
// The 'fitRadius' parameter specifies the distance away from distortion center at
// which the input and output coordinates will match, assuming [-1,1] range.
F32 OculusVRHMDDevice::calcScale(F32 fitRadius)
{
F32 s = fitRadius;
// This should match distortion equation used in shader.
F32 ssq = s * s;
F32 scale = s * (mKDistortion.x + mKDistortion.y * ssq + mKDistortion.z * ssq * ssq + mKDistortion.w * ssq * ssq * ssq);
return scale;
}
void OculusVRHMDDevice::calculateValues(bool calculateDistortionScale)
{
F32 halfScreenX = mScreenSize.x * 0.5f;
if(halfScreenX > 0)
{
F32 halfLensSeparation = mLensSeparation * 0.5;
F32 offset = halfLensSeparation / halfScreenX;
mEyeUVOffset.x = offset - 0.5;
mEyeUVOffset.y = 1.0f - offset - 0.5;
}
else
{
mEyeUVOffset.x = 0.5f;
mEyeUVOffset.y = 0.5f;
}
F32 lensOffset = mLensSeparation * 0.5f;
F32 lensShift = mScreenSize.x * 0.25f - lensOffset;
F32 lensViewportShift = 4.0f * lensShift / mScreenSize.x;
mXCenterOffset= lensViewportShift;
// Determine how the input texture should be scaled relative to the back buffer
// so that we fit the distorted view to the backbuffer after calculating the
// distortion. In reference to section 5.6.3 Distortion Scale and FOV in the
// SDK docs.
if(!calculateDistortionScale)
{
// Do not calculate a distortion scale for the input texture. This means that the input
// texture and the backbuffer will be the same resolution.
mDistortionFit.x = 0.0f;
mDistortionFit.y = 0.0f;
}
else if (mScreenSize.x > 0.140f) // 7"
{
mDistortionFit.x = -1.0f;
mDistortionFit.y = 0.0f;
}
else // 5"
{
mDistortionFit.x = 0.0f;
mDistortionFit.y = 1.0f;
}
// Compute distortion scale from DistortionFitX & DistortionFitY.
// Fit value of 0.0 means "no fit".
if (mIsZero(mDistortionFit.x) && mIsZero(mDistortionFit.y))
{
mDistortionScale = 1.0f;
}
else
{
// Convert fit value to distortion-centered coordinates before fit radius
// calculation.
// NOTE: For now just assume a full view the same size as the HMD supports. It is
// possible that this full view is smaller or larger.
F32 stereoAspect = 0.5f * mResolution.x / mResolution.y;
F32 dx = mDistortionFit.x - mXCenterOffset;
F32 dy = mDistortionFit.y / stereoAspect;
F32 fitRadius = sqrt(dx * dx + dy * dy);
mDistortionScale = calcScale(fitRadius)/fitRadius;
}
// Calculate the vertical FOV for a single eye
mAspectRatio = F32(mResolution.x * 0.5f) / F32(mResolution.y);
F32 halfScreenDistance = mScreenSize.y * 0.5f * mDistortionScale;
mYFOV = 2.0f * mAtan(halfScreenDistance / mEyeToScreen);
F32 viewCenter = mScreenSize.x * 0.25f;
F32 eyeProjectionShift = viewCenter - (mInterpupillaryDistance * 0.5f);
mProjectionCenterOffset.set(4.0f * eyeProjectionShift / mScreenSize.x, 0.0f);
mEyeWorldOffset.set(mInterpupillaryDistance * 0.5f, 0.0f, 0.0f);
}

View file

@ -0,0 +1,187 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _OCULUSVRHMDDEVICE_H_
#define _OCULUSVRHMDDEVICE_H_
#include "core/util/str.h"
#include "math/mQuat.h"
#include "math/mPoint2.h"
#include "math/mPoint3.h"
#include "math/mPoint4.h"
#include "platform/input/oculusVR/oculusVRConstants.h"
#include "platform/types.h"
#include "OVR.h"
class OculusVRHMDDevice
{
public:
enum SimulationTypes {
ST_RIFT_PREVIEW,
};
protected:
bool mIsValid;
bool mIsSimulation;
OVR::HMDDevice* mDevice;
// From OVR::DeviceInfo
String mProductName;
String mManufacturer;
U32 mVersion;
// Windows display device name used in EnumDisplaySettings/CreateDC
String mDisplayDeviceName;
// Whole screen resolution
Point2I mResolution;
// Physical screen size in meters
Point2F mScreenSize;
// Physical offset from the top of the screen to the center of the
// eye, in meters. Usually half of the vertical physical screen size
F32 mVerticalEyeCenter;
// Physical distance from the eye to the screen
F32 mEyeToScreen;
// Physical distance between lens centers, in meters
F32 mLensSeparation;
// Physical distance between the user's eye centers
F32 mInterpupillaryDistance;
// The eye IPD as a Point3F
Point3F mEyeWorldOffset;
// Radial distortion correction coefficients used by the barrel distortion shader
Point4F mKDistortion;
// Calculated values of eye x offset from center in normalized (uv) coordinates
// where each eye is 0..1. Used for the mono to stereo postFX to simulate an
// eye offset of the camera. The x component is the left eye, the y component
// is the right eye.
Point2F mEyeUVOffset;
// Used to adjust where an eye's view is rendered to account for the lenses not
// being in the center of the physical screen half.
F32 mXCenterOffset;
// When calculating the distortion scale to use to increase the size of the input texture
// this determines how we should attempt to fit the distorted view into the backbuffer.
Point2F mDistortionFit;
// Is the factor by which the input texture size is increased to make post-distortion
// result distortion fit the viewport. If the input texture is the same size as the
// backbuffer, then this should be 1.0.
F32 mDistortionScale;
// Aspect ratio for a single eye
F32 mAspectRatio;
// Vertical field of view
F32 mYFOV;
// The amount to offset the projection matrix to account for the eye not being in the
// center of the screen.
Point2F mProjectionCenterOffset;
protected:
F32 calcScale(F32 fitRadius);
void calculateValues(bool calculateDistortionScale);
void createSimulatedPreviewRift(bool calculateDistortionScale);
public:
OculusVRHMDDevice();
~OculusVRHMDDevice();
void cleanUp();
// Set the HMD properties based on information from the OVR device
void set(OVR::HMDDevice* hmd, OVR::HMDInfo& info, bool calculateDistortionScale);
// Set the HMD properties based on a simulation of the given type
void createSimulation(SimulationTypes simulationType, bool calculateDistortionScale);
bool isValid() const {return mIsValid;}
bool isSimulated() const {return mIsSimulation;}
const char* getProductName() const { return mProductName.c_str(); }
const char* getManufacturer() const { return mManufacturer.c_str(); }
U32 getVersion() const { return mVersion; }
// Windows display device name used in EnumDisplaySettings/CreateDC
const char* getDisplayDeviceName() const { return mDisplayDeviceName.c_str(); }
// Whole screen resolution
const Point2I& getResolution() const { return mResolution; }
// Physical screen size in meters
const Point2F& getScreenSize() const { return mScreenSize; }
// Physical offset from the top of the screen to the center of the
// eye, in meters. Usually half of the vertical physical screen size
F32 getVerticalEyeCenter() const { return mVerticalEyeCenter; }
// Physical distance from the eye to the screen
F32 getEyeToScreen() const { return mEyeToScreen; }
// Physical distance between lens centers, in meters
F32 getLensSeparation() const { return mLensSeparation; }
// Physical distance between the user's eye centers
F32 getIPD() const { return mInterpupillaryDistance; }
// Provides the IPD of one eye as a Point3F
const Point3F& getEyeWorldOffset() const { return mEyeWorldOffset; }
// Radial distortion correction coefficients used by the barrel distortion shader
const Point4F& getKDistortion() const { return mKDistortion; }
// Calculated values of eye x offset from center in normalized (uv) coordinates.
const Point2F& getEyeUVOffset() const { return mEyeUVOffset; }
// Used to adjust where an eye's view is rendered to account for the lenses not
// being in the center of the physical screen half.
F32 getCenterOffset() const { return mXCenterOffset; }
// Is the factor by which the input texture size is increased to make post-distortion
// result distortion fit the viewport.
F32 getDistortionScale() const { return mDistortionScale; }
// Aspect ration for a single eye
F32 getAspectRation() const { return mAspectRatio; }
// Vertical field of view
F32 getYFOV() const { return mYFOV; }
// The amount to offset the projection matrix to account for the eye not being in the
// center of the screen.
const Point2F& getProjectionCenterOffset() const { return mProjectionCenterOffset; }
};
#endif // _OCULUSVRHMDDEVICE_H_

View file

@ -0,0 +1,96 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/oculusVR/oculusVRSensorData.h"
#include "platform/input/oculusVR/oculusVRUtil.h"
#include "console/console.h"
OculusVRSensorData::OculusVRSensorData()
{
reset();
}
void OculusVRSensorData::reset()
{
mDataSet = false;
}
void OculusVRSensorData::setData(const OVR::SensorFusion& data, const F32& maxAxisRadius)
{
// Sensor rotation
OVR::Quatf orientation;
if(data.GetPredictionDelta() > 0)
{
orientation = data.GetPredictedOrientation();
}
else
{
orientation = data.GetOrientation();
}
OVR::Matrix4f orientMat(orientation);
OculusVRUtil::convertRotation(orientMat.M, mRot);
mRotQuat.set(mRot);
// Sensor rotation in Euler format
OculusVRUtil::convertRotation(orientation, mRotEuler);
// Sensor rotation as axis
OculusVRUtil::calculateAxisRotation(mRot, maxAxisRadius, mRotAxis);
mDataSet = true;
}
void OculusVRSensorData::simulateData(const F32& maxAxisRadius)
{
// Sensor rotation
mRot.identity();
mRotQuat.identity();
mRotEuler.zero();
// Sensor rotation as axis
OculusVRUtil::calculateAxisRotation(mRot, maxAxisRadius, mRotAxis);
mDataSet = true;
}
U32 OculusVRSensorData::compare(OculusVRSensorData* other)
{
S32 result = DIFF_NONE;
// Check rotation
if(mRotEuler.x != other->mRotEuler.x || mRotEuler.y != other->mRotEuler.y || mRotEuler.z != other->mRotEuler.z || !mDataSet)
{
result |= DIFF_ROT;
}
// Check rotation as axis
if(mRotAxis.x != other->mRotAxis.x || !mDataSet)
{
result |= DIFF_ROTAXISX;
}
if(mRotAxis.y != other->mRotAxis.y || !mDataSet)
{
result |= DIFF_ROTAXISY;
}
return result;
}

View file

@ -0,0 +1,68 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _OCULUSVRSENSORDATA_H_
#define _OCULUSVRSENSORDATA_H_
#include "platform/types.h"
#include "math/mMatrix.h"
#include "math/mQuat.h"
#include "math/mPoint2.h"
#include "OVR.h"
struct OculusVRSensorData
{
enum DataDifferences {
DIFF_NONE = 0,
DIFF_ROT = (1<<0),
DIFF_ROTAXISX = (1<<1),
DIFF_ROTAXISY = (1<<2),
DIFF_ROTAXIS = (DIFF_ROTAXISX | DIFF_ROTAXISY),
};
bool mDataSet;
// Rotation
MatrixF mRot;
QuatF mRotQuat;
EulerF mRotEuler;
// Controller rotation as axis x, y
Point2F mRotAxis;
OculusVRSensorData();
/// Reset the data
void reset();
/// Set data based on given sensor fusion
void setData(const OVR::SensorFusion& data, const F32& maxAxisRadius);
/// Simulate valid data
void simulateData(const F32& maxAxisRadius);
/// Compare this data and given and return differences
U32 compare(OculusVRSensorData* other);
};
#endif // _OCULUSVRSENSORDATA_H_

View file

@ -0,0 +1,265 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/oculusVR/oculusVRSensorDevice.h"
#include "platform/input/oculusVR/oculusVRSensorData.h"
#include "platform/input/oculusVR/oculusVRUtil.h"
#include "platform/platformInput.h"
U32 OculusVRSensorDevice::OVR_SENSORROT[OculusVRConstants::MaxSensors] = {0};
U32 OculusVRSensorDevice::OVR_SENSORROTANG[OculusVRConstants::MaxSensors] = {0};
U32 OculusVRSensorDevice::OVR_SENSORROTAXISX[OculusVRConstants::MaxSensors] = {0};
U32 OculusVRSensorDevice::OVR_SENSORROTAXISY[OculusVRConstants::MaxSensors] = {0};
OculusVRSensorDevice::OculusVRSensorDevice()
{
mIsValid = false;
mIsSimulation = false;
mDevice = NULL;
for(U32 i=0; i<2; ++i)
{
mDataBuffer[i] = new OculusVRSensorData();
}
mPrevData = mDataBuffer[0];
}
OculusVRSensorDevice::~OculusVRSensorDevice()
{
cleanUp();
for(U32 i=0; i<2; ++i)
{
delete mDataBuffer[i];
mDataBuffer[i] = NULL;
}
mPrevData = NULL;
}
void OculusVRSensorDevice::cleanUp()
{
mSensorFusion.AttachToSensor(NULL);
if(mDevice)
{
mDevice->Release();
mDevice = NULL;
}
mIsValid = false;
}
void OculusVRSensorDevice::set(OVR::SensorDevice* sensor, OVR::SensorInfo& info, S32 actionCodeIndex)
{
mIsValid = false;
mDevice = sensor;
mSensorFusion.AttachToSensor(sensor);
// DeviceInfo
mProductName = info.ProductName;
mManufacturer = info.Manufacturer;
mVersion = info.Version;
// SensorInfo
mVendorId = info.VendorId;
mProductId = info.ProductId;
mSerialNumber = info.SerialNumber;
mActionCodeIndex = actionCodeIndex;
if(mActionCodeIndex >= OculusVRConstants::MaxSensors)
{
// Cannot declare more sensors than we are able to handle
mIsValid = false;
}
else
{
mIsValid = true;
}
}
void OculusVRSensorDevice::createSimulation(SimulationTypes simulationType, S32 actionCodeIndex)
{
if(simulationType == ST_RIFT_PREVIEW)
{
createSimulatedPreviewRift(actionCodeIndex);
}
}
void OculusVRSensorDevice::createSimulatedPreviewRift(S32 actionCodeIndex)
{
mIsValid = false;
mIsSimulation = true;
// DeviceInfo
mProductName = "Tracker DK";
mManufacturer = "Oculus VR, Inc.";
mVersion = 0;
// SensorInfo
mVendorId = 10291;
mProductId = 1;
mSerialNumber = "000000000000";
mActionCodeIndex = actionCodeIndex;
if(mActionCodeIndex >= OculusVRConstants::MaxSensors)
{
// Cannot declare more sensors than we are able to handle
mIsValid = false;
}
else
{
mIsValid = true;
}
}
void OculusVRSensorDevice::buildCodeTable()
{
// Obtain all of the device codes
for(U32 i=0; i<OculusVRConstants::MaxSensors; ++i)
{
OVR_SENSORROT[i] = INPUTMGR->getNextDeviceCode();
OVR_SENSORROTANG[i] = INPUTMGR->getNextDeviceCode();
OVR_SENSORROTAXISX[i] = INPUTMGR->getNextDeviceCode();
OVR_SENSORROTAXISY[i] = INPUTMGR->getNextDeviceCode();
}
// Build out the virtual map
char buffer[64];
for(U32 i=0; i<OculusVRConstants::MaxSensors; ++i)
{
dSprintf(buffer, 64, "ovr_sensorrot%d", i);
INPUTMGR->addVirtualMap( buffer, SI_ROT, OVR_SENSORROT[i] );
dSprintf(buffer, 64, "ovr_sensorrotang%d", i);
INPUTMGR->addVirtualMap( buffer, SI_ROT, OVR_SENSORROTANG[i] );
dSprintf(buffer, 64, "ovr_sensorrotaxisx%d", i);
INPUTMGR->addVirtualMap( buffer, SI_AXIS, OVR_SENSORROTAXISX[i] );
dSprintf(buffer, 64, "ovr_sensorrotaxisy%d", i);
INPUTMGR->addVirtualMap( buffer, SI_AXIS, OVR_SENSORROTAXISY[i] );
}
}
bool OculusVRSensorDevice::process(U32 deviceType, bool generateRotAsAngAxis, bool generateRotAsEuler, bool generateRotationAsAxisEvents, F32 maxAxisRadius)
{
if(!mIsValid)
return false;
// Store the current data from the sensor and compare with previous data
U32 diff;
OculusVRSensorData* currentBuffer = (mPrevData == mDataBuffer[0]) ? mDataBuffer[1] : mDataBuffer[0];
if(!mIsSimulation)
{
currentBuffer->setData(mSensorFusion, maxAxisRadius);
}
else
{
currentBuffer->simulateData(maxAxisRadius);
}
diff = mPrevData->compare(currentBuffer);
// Update the previous data pointer. We do this here in case someone calls our
// console functions during one of the input events below.
mPrevData = currentBuffer;
// Rotation event
if(diff & OculusVRSensorData::DIFF_ROT)
{
if(generateRotAsAngAxis)
{
INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_ROT, OVR_SENSORROT[mActionCodeIndex], SI_MOVE, currentBuffer->mRotQuat);
}
if(generateRotAsEuler)
{
// Convert angles to degrees
VectorF angles;
for(U32 i=0; i<3; ++i)
{
angles[i] = mRadToDeg(currentBuffer->mRotEuler[i]);
}
INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_POS, OVR_SENSORROTANG[mActionCodeIndex], SI_MOVE, angles);
}
}
// Rotation as axis event
if(generateRotationAsAxisEvents && diff & OculusVRSensorData::DIFF_ROTAXIS)
{
if(diff & OculusVRSensorData::DIFF_ROTAXISX)
INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_AXIS, OVR_SENSORROTAXISX[mActionCodeIndex], SI_MOVE, currentBuffer->mRotAxis.x);
if(diff & OculusVRSensorData::DIFF_ROTAXISY)
INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_AXIS, OVR_SENSORROTAXISY[mActionCodeIndex], SI_MOVE, currentBuffer->mRotAxis.y);
}
return true;
}
void OculusVRSensorDevice::reset()
{
if(!mIsValid)
return;
mSensorFusion.Reset();
}
F32 OculusVRSensorDevice::getPredictionTime() const
{
if(!mIsValid)
return 0.0f;
return mSensorFusion.GetPredictionDelta();
}
void OculusVRSensorDevice::setPredictionTime(F32 dt)
{
if(!mIsValid)
return;
mSensorFusion.SetPrediction(dt);
}
EulerF OculusVRSensorDevice::getEulerRotation()
{
if(!mIsValid)
return Point3F::Zero;
OVR::Quatf orientation;
if(mSensorFusion.GetPredictionDelta() > 0)
{
orientation = mSensorFusion.GetPredictedOrientation();
}
else
{
orientation = mSensorFusion.GetOrientation();
}
// Sensor rotation in Euler format
EulerF rot;
OculusVRUtil::convertRotation(orientation, rot);
return rot;
}

View file

@ -0,0 +1,122 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _OCULUSVRSENSORDEVICE_H_
#define _OCULUSVRSENSORDEVICE_H_
#include "core/util/str.h"
#include "math/mQuat.h"
#include "math/mPoint2.h"
#include "math/mPoint3.h"
#include "math/mPoint4.h"
#include "platform/input/oculusVR/oculusVRConstants.h"
#include "platform/types.h"
#include "OVR.h"
struct OculusVRSensorData;
class OculusVRSensorDevice
{
public:
enum SimulationTypes {
ST_RIFT_PREVIEW,
};
public:
// Action codes
static U32 OVR_SENSORROT[OculusVRConstants::MaxSensors]; // SI_ROT
static U32 OVR_SENSORROTANG[OculusVRConstants::MaxSensors]; // SI_POS but is EulerF
static U32 OVR_SENSORROTAXISX[OculusVRConstants::MaxSensors]; // SI_AXIS
static U32 OVR_SENSORROTAXISY[OculusVRConstants::MaxSensors];
protected:
bool mIsValid;
bool mIsSimulation;
OVR::SensorDevice* mDevice;
OVR::SensorFusion mSensorFusion;
// From OVR::DeviceInfo
String mProductName;
String mManufacturer;
U32 mVersion;
// From OVR::SensorInfo
U16 mVendorId;
U16 mProductId;
String mSerialNumber;
// Assigned by the OculusVRDevice
S32 mActionCodeIndex;
// Buffers to store data for sensor
OculusVRSensorData* mDataBuffer[2];
// Points to the buffer that holds the previously collected data
// for the sensor
OculusVRSensorData* mPrevData;
protected:
void createSimulatedPreviewRift(S32 actionCodeIndex);
public:
OculusVRSensorDevice();
virtual ~OculusVRSensorDevice();
static void buildCodeTable();
void cleanUp();
// Set the sensor properties based on information from the OVR device
void set(OVR::SensorDevice* sensor, OVR::SensorInfo& info, S32 actionCodeIndex);
// Set the sensor properties based on a simulation of the given type
void createSimulation(SimulationTypes simulationType, S32 actionCodeIndex);
bool isValid() const {return mIsValid;}
bool isSimulated() {return mIsSimulation;}
bool process(U32 deviceType, bool generateRotAsAngAxis, bool generateRotAsEuler, bool generateRotationAsAxisEvents, F32 maxAxisRadius);
void reset();
// Get the prediction time for the sensor fusion. The time is in seconds.
F32 getPredictionTime() const;
// Set the prediction time for the sensor fusion. The time is in seconds.
void setPredictionTime(F32 dt);
const char* getProductName() { return mProductName.c_str(); }
const char* getManufacturer() { return mManufacturer.c_str(); }
U32 getVersion() { return mVersion; }
U16 getVendorId() { return mVendorId; }
U16 getProductId() { return mProductId; }
const char* getSerialNumber() { return mSerialNumber; }
EulerF getEulerRotation();
};
#endif // _OCULUSVRSENSORDEVICE_H_

View file

@ -0,0 +1,76 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/input/oculusVR/oculusVRUtil.h"
namespace OculusVRUtil
{
void convertRotation(const F32 inRotMat[4][4], MatrixF& outRotation)
{
// Set rotation. We need to convert from sensor coordinates to
// Torque coordinates. The sensor matrix is stored row-major.
// The conversion is:
//
// Sensor Torque
// a b c a b c a -c b
// d e f --> -g -h -i --> -g i -h
// g h i d e f d -f e
outRotation.setColumn(0, Point4F( inRotMat[0][0], -inRotMat[2][0], inRotMat[1][0], 0.0f));
outRotation.setColumn(1, Point4F(-inRotMat[0][2], inRotMat[2][2], -inRotMat[1][2], 0.0f));
outRotation.setColumn(2, Point4F( inRotMat[0][1], -inRotMat[2][1], inRotMat[1][1], 0.0f));
outRotation.setPosition(Point3F::Zero);
}
void convertRotation(OVR::Quatf& inRotation, EulerF& outRotation)
{
F32 yaw, pitch, roll;
inRotation.GetEulerAngles<OVR::Axis_Y, OVR::Axis_X, OVR::Axis_Z>(&yaw, &pitch, &roll);
outRotation.x = -pitch;
outRotation.y = roll;
outRotation.z = -yaw;
}
void calculateAxisRotation(const MatrixF& inRotation, const F32& maxAxisRadius, Point2F& outRotation)
{
const VectorF& controllerUp = inRotation.getUpVector();
Point2F axis(0,0);
axis.x = controllerUp.x;
axis.y = controllerUp.y;
// Limit the axis angle to that given to us
if(axis.len() > maxAxisRadius)
{
axis.normalize(maxAxisRadius);
}
// Renormalize to the range of 0..1
if(maxAxisRadius != 0.0f)
{
axis /= maxAxisRadius;
}
outRotation.x = axis.x;
outRotation.y = axis.y;
}
}

View file

@ -0,0 +1,42 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _OCULUSVRUTIL_H_
#define _OCULUSVRUTIL_H_
#include "math/mPoint2.h"
#include "math/mMatrix.h"
#include "OVR.h"
namespace OculusVRUtil
{
/// Convert an OVR sensor's rotation to a Torque 3D matrix
void convertRotation(const F32 inRotMat[4][4], MatrixF& outRotation);
/// Convert an OVR sensor's rotation to Torque 3D Euler angles (in radians)
void convertRotation(OVR::Quatf& inRotation, EulerF& outRotation);
/// Calcualte a sensor's rotation as if it were a thumb stick axis
void calculateAxisRotation(const MatrixF& inRotation, const F32& maxAxisRadius, Point2F& outRotation);
}
#endif // _OCULUSVRUTIL_H_

View file

@ -54,6 +54,9 @@ function initializeCore()
exec( "./audioStates.cs" );
exec( "./audioAmbiences.cs" );
// Input devices
exec("~/scripts/client/oculusVR.cs");
// Seed the random number generator.
setRandomSeed();

View file

@ -0,0 +1,125 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
// Only load these functions if an Oculus VR device is present
if(!isFunction(isOculusVRDeviceActive))
return;
//-----------------------------------------------------------------------------
function oculusSensorMetricsCallback()
{
return " | OVR Sensor 0 |" @
" rot: " @ getOVRSensorEulerRotation(0);
}
//-----------------------------------------------------------------------------
// Call this function from createCanvas() to have the Canvas attach itself
// to the Rift's display. The Canvas' window will still open on the primary
// display if that is different from the Rift, but it will move to the Rift
// when it goes full screen. If the Rift is not connected then nothing
// will happen.
function pointCanvasToOculusVRDisplay()
{
$pref::Video::displayOutputDevice = getOVRHMDDisplayDeviceName(0);
}
//-----------------------------------------------------------------------------
// Call this function from GameConnection::initialControlSet() just before
// your "Canvas.setContent(PlayGui);" call, or at any time you wish to switch
// to a side-by-side rendering and the appropriate barrel distortion. This
// will turn on side-by-side rendering and tell the GameConnection to use the
// Rift as its display device.
// Parameters:
// %gameConnection - The client GameConnection instance
// %trueStereoRendering - If true will enable stereo rendering with an eye
// offset for each viewport. This will render each frame twice. If false
// then a pseudo stereo rendering is done with only a single render per frame.
function enableOculusVRDisplay(%gameConnection, %trueStereoRendering)
{
setOVRHMDAsGameConnectionDisplayDevice(%gameConnection);
PlayGui.renderStyle = "stereo side by side";
if(%trueStereoRendering)
{
OVRBarrelDistortionPostFX.isEnabled = true;
}
else
{
OVRBarrelDistortionMonoPostFX.isEnabled = true;
}
// Reset all sensors
ovrResetAllSensors();
}
// Call this function when ever you wish to turn off the stereo rendering
// and barrel distortion for the Rift.
function disableOculusVRDisplay(%gameConnection)
{
%gameConnection.clearDisplayDevice();
PlayGui.renderStyle = "standard";
OVRBarrelDistortionPostFX.isEnabled = false;
OVRBarrelDistortionMonoPostFX.isEnabled = false;
}
// Helper function to set the standard Rift control scheme. You could place
// this function in GameConnection::initialControlSet() at the same time
// you call enableOculusVRDisplay().
function setStandardOculusVRControlScheme(%gameConnection)
{
if(isOVRHMDSimulated(0))
{
// We are simulating a HMD so allow the mouse and gamepad to control
// both yaw and pitch.
%gameConnection.setControlSchemeParameters(true, true, true);
}
else
{
// A HMD is connected so have the mouse and gamepad only add to yaw
%gameConnection.setControlSchemeParameters(true, true, false);
}
}
//-----------------------------------------------------------------------------
// Helper function to set the resolution for the Rift.
// Parameters:
// %fullscreen - If true then the display will be forced to full screen. If
// pointCanvasToOculusVRDisplay() was called before the Canvas was created, then
// the full screen display will appear on the Rift.
function setVideoModeForOculusVRDisplay(%fullscreen)
{
%res = getOVRHMDResolution(0);
Canvas.setVideoMode(%res.x, %res.y, %fullscreen, 32, 0);
}
//-----------------------------------------------------------------------------
// Reset all Oculus Rift sensors. This will make the Rift's current heading
// be considered the origin.
function resetOculusVRSensors()
{
ovrResetAllSensors();
}

View file

@ -0,0 +1,123 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
// Only load these shaders if an Oculus VR device is present
if(!isFunction(isOculusVRDeviceActive))
return;
//-----------------------------------------------------------------------------
// Shader data
//-----------------------------------------------------------------------------
singleton ShaderData( OVRMonoToStereoShader )
{
DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl";
DXPixelShaderFile = "shaders/common/postFx/oculusvr/monoToStereoP.hlsl";
pixVersion = 2.0;
};
singleton ShaderData( OVRBarrelDistortionShader )
{
DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl";
DXPixelShaderFile = "shaders/common/postFx/oculusvr/barrelDistortionP.hlsl";
pixVersion = 2.0;
};
//-----------------------------------------------------------------------------
// GFX state blocks
//-----------------------------------------------------------------------------
singleton GFXStateBlockData( OVRBarrelDistortionStateBlock : PFX_DefaultStateBlock )
{
samplersDefined = true;
samplerStates[0] = SamplerClampLinear;
};
//-----------------------------------------------------------------------------
// Barrel Distortion PostFx
//
// To be used with the Oculus Rift.
// Expects a stereo pair to exist on the back buffer and then applies the
// appropriate barrel distortion.
//-----------------------------------------------------------------------------
singleton BarrelDistortionPostEffect( OVRBarrelDistortionPostFX )
{
isEnabled = false;
allowReflectPass = false;
renderTime = "PFXAfterDiffuse";
renderPriority = 100;
// The barrel distortion
shader = OVRBarrelDistortionShader;
stateBlock = OVRBarrelDistortionStateBlock;
texture[0] = "$backBuffer";
scaleOutput = 1.25;
};
//-----------------------------------------------------------------------------
// Barrel Distortion Mono PostFx
//
// To be used with the Oculus Rift.
// Takes a non-stereo image and turns it into a stereo pair with barrel
// distortion applied. Only a vertical slice around the center of the back
// buffer is used to generate the pseudo stereo pair.
//-----------------------------------------------------------------------------
singleton PostEffect( OVRBarrelDistortionMonoPostFX )
{
isEnabled = false;
allowReflectPass = false;
renderTime = "PFXAfterDiffuse";
renderPriority = 100;
// Converts the mono display to a stereo one
shader = OVRMonoToStereoShader;
stateBlock = OVRBarrelDistortionStateBlock;
texture[0] = "$backBuffer";
target = "$outTex";
// The actual barrel distortion
new BarrelDistortionPostEffect(OVRBarrelDistortionMonoStage2PostFX)
{
shader = OVRBarrelDistortionShader;
stateBlock = OVRBarrelDistortionStateBlock;
texture[0] = "$inTex";
target = "$backBuffer";
scaleOutput = 1.25;
};
};
function OVRBarrelDistortionMonoPostFX::setShaderConsts( %this )
{
%HMDIndex = 0;
%xOffsets = getOVRHMDEyeXOffsets(%HMDIndex);
%this.setShaderConst( "$LensXOffsets", %xOffsets );
}

View file

@ -0,0 +1,81 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "shadergen:/autogenConditioners.h"
#include "../postFx.hlsl"
#include "../../torque.hlsl"
uniform sampler2D backBuffer : register(S0);
uniform float3 LensCenter; // x=Left X, y=Right X, z=Y
uniform float2 ScreenCenter;
uniform float2 Scale;
uniform float2 ScaleIn;
uniform float4 HmdWarpParam;
// Scales input texture coordinates for distortion.
// ScaleIn maps texture coordinates to Scales to ([-1, 1]), although top/bottom will be
// larger due to aspect ratio.
float2 HmdWarp(float2 in01, float2 lensCenter)
{
float2 theta = (in01 - lensCenter) * ScaleIn; // Scales to [-1, 1]
float rSq = theta.x * theta.x + theta.y * theta.y;
float2 theta1 = theta * (HmdWarpParam.x + HmdWarpParam.y * rSq + HmdWarpParam.z * rSq * rSq + HmdWarpParam.w * rSq * rSq * rSq);
return lensCenter + Scale * theta1;
}
float4 main( PFXVertToPix IN ) : COLOR0
{
float2 texCoord;
float xOffset;
float2 lensCenter;
lensCenter.y = LensCenter.z;
if(IN.uv0.x < 0.5)
{
texCoord.x = IN.uv0.x;
texCoord.y = IN.uv0.y;
xOffset = 0.0;
lensCenter.x = LensCenter.x;
}
else
{
texCoord.x = IN.uv0.x - 0.5;
texCoord.y = IN.uv0.y;
xOffset = 0.5;
lensCenter.x = LensCenter.y;
}
float2 tc = HmdWarp(texCoord, lensCenter);
float4 color;
if (any(clamp(tc, ScreenCenter-float2(0.25,0.5), ScreenCenter+float2(0.25, 0.5)) - tc))
{
color = float4(0,0,0,0);
}
else
{
tc.x += xOffset;
color = tex2D(backBuffer, tc);
}
return color;
}

View file

@ -0,0 +1,60 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "shadergen:/autogenConditioners.h"
#include "../postFx.hlsl"
#include "../../torque.hlsl"
uniform sampler2D backBuffer : register(S0);
uniform float2 LensXOffsets;
float4 main( PFXVertToPix IN ) : COLOR0
{
float2 texCoord;
float xOffset;
float2 lensCenter;
lensCenter.y = 0.5;
if(IN.uv0.x < 0.5)
{
texCoord.x = IN.uv0.x;
texCoord.y = IN.uv0.y;
xOffset = 0.0;
lensCenter.x = LensXOffsets.x;
}
else
{
texCoord.x = IN.uv0.x - 0.5;
texCoord.y = IN.uv0.y;
xOffset = 0.5;
lensCenter.x = LensXOffsets.y;
}
texCoord.x *= 2.0;
texCoord.x += lensCenter.x;
texCoord.x *= 0.5;
texCoord.x += 0.25;
float4 color = tex2D(backBuffer, texCoord);
return color;
}

View file

@ -54,6 +54,9 @@ function initializeCore()
exec( "./audioStates.cs" );
exec( "./audioAmbiences.cs" );
// Input devices
exec("~/scripts/client/oculusVR.cs");
// Seed the random number generator.
setRandomSeed();

View file

@ -0,0 +1,125 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
// Only load these functions if an Oculus VR device is present
if(!isFunction(isOculusVRDeviceActive))
return;
//-----------------------------------------------------------------------------
function oculusSensorMetricsCallback()
{
return " | OVR Sensor 0 |" @
" rot: " @ getOVRSensorEulerRotation(0);
}
//-----------------------------------------------------------------------------
// Call this function from createCanvas() to have the Canvas attach itself
// to the Rift's display. The Canvas' window will still open on the primary
// display if that is different from the Rift, but it will move to the Rift
// when it goes full screen. If the Rift is not connected then nothing
// will happen.
function pointCanvasToOculusVRDisplay()
{
$pref::Video::displayOutputDevice = getOVRHMDDisplayDeviceName(0);
}
//-----------------------------------------------------------------------------
// Call this function from GameConnection::initialControlSet() just before
// your "Canvas.setContent(PlayGui);" call, or at any time you wish to switch
// to a side-by-side rendering and the appropriate barrel distortion. This
// will turn on side-by-side rendering and tell the GameConnection to use the
// Rift as its display device.
// Parameters:
// %gameConnection - The client GameConnection instance
// %trueStereoRendering - If true will enable stereo rendering with an eye
// offset for each viewport. This will render each frame twice. If false
// then a pseudo stereo rendering is done with only a single render per frame.
function enableOculusVRDisplay(%gameConnection, %trueStereoRendering)
{
setOVRHMDAsGameConnectionDisplayDevice(%gameConnection);
PlayGui.renderStyle = "stereo side by side";
if(%trueStereoRendering)
{
OVRBarrelDistortionPostFX.isEnabled = true;
}
else
{
OVRBarrelDistortionMonoPostFX.isEnabled = true;
}
// Reset all sensors
ovrResetAllSensors();
}
// Call this function when ever you wish to turn off the stereo rendering
// and barrel distortion for the Rift.
function disableOculusVRDisplay(%gameConnection)
{
%gameConnection.clearDisplayDevice();
PlayGui.renderStyle = "standard";
OVRBarrelDistortionPostFX.isEnabled = false;
OVRBarrelDistortionMonoPostFX.isEnabled = false;
}
// Helper function to set the standard Rift control scheme. You could place
// this function in GameConnection::initialControlSet() at the same time
// you call enableOculusVRDisplay().
function setStandardOculusVRControlScheme(%gameConnection)
{
if(isOVRHMDSimulated(0))
{
// We are simulating a HMD so allow the mouse and gamepad to control
// both yaw and pitch.
%gameConnection.setControlSchemeParameters(true, true, true);
}
else
{
// A HMD is connected so have the mouse and gamepad only add to yaw
%gameConnection.setControlSchemeParameters(true, true, false);
}
}
//-----------------------------------------------------------------------------
// Helper function to set the resolution for the Rift.
// Parameters:
// %fullscreen - If true then the display will be forced to full screen. If
// pointCanvasToOculusVRDisplay() was called before the Canvas was created, then
// the full screen display will appear on the Rift.
function setVideoModeForOculusVRDisplay(%fullscreen)
{
%res = getOVRHMDResolution(0);
Canvas.setVideoMode(%res.x, %res.y, %fullscreen, 32, 0);
}
//-----------------------------------------------------------------------------
// Reset all Oculus Rift sensors. This will make the Rift's current heading
// be considered the origin.
function resetOculusVRSensors()
{
ovrResetAllSensors();
}

View file

@ -0,0 +1,123 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
// Only load these shaders if an Oculus VR device is present
if(!isFunction(isOculusVRDeviceActive))
return;
//-----------------------------------------------------------------------------
// Shader data
//-----------------------------------------------------------------------------
singleton ShaderData( OVRMonoToStereoShader )
{
DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl";
DXPixelShaderFile = "shaders/common/postFx/oculusvr/monoToStereoP.hlsl";
pixVersion = 2.0;
};
singleton ShaderData( OVRBarrelDistortionShader )
{
DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl";
DXPixelShaderFile = "shaders/common/postFx/oculusvr/barrelDistortionP.hlsl";
pixVersion = 2.0;
};
//-----------------------------------------------------------------------------
// GFX state blocks
//-----------------------------------------------------------------------------
singleton GFXStateBlockData( OVRBarrelDistortionStateBlock : PFX_DefaultStateBlock )
{
samplersDefined = true;
samplerStates[0] = SamplerClampLinear;
};
//-----------------------------------------------------------------------------
// Barrel Distortion PostFx
//
// To be used with the Oculus Rift.
// Expects a stereo pair to exist on the back buffer and then applies the
// appropriate barrel distortion.
//-----------------------------------------------------------------------------
singleton BarrelDistortionPostEffect( OVRBarrelDistortionPostFX )
{
isEnabled = false;
allowReflectPass = false;
renderTime = "PFXAfterDiffuse";
renderPriority = 100;
// The barrel distortion
shader = OVRBarrelDistortionShader;
stateBlock = OVRBarrelDistortionStateBlock;
texture[0] = "$backBuffer";
scaleOutput = 1.25;
};
//-----------------------------------------------------------------------------
// Barrel Distortion Mono PostFx
//
// To be used with the Oculus Rift.
// Takes a non-stereo image and turns it into a stereo pair with barrel
// distortion applied. Only a vertical slice around the center of the back
// buffer is used to generate the pseudo stereo pair.
//-----------------------------------------------------------------------------
singleton PostEffect( OVRBarrelDistortionMonoPostFX )
{
isEnabled = false;
allowReflectPass = false;
renderTime = "PFXAfterDiffuse";
renderPriority = 100;
// Converts the mono display to a stereo one
shader = OVRMonoToStereoShader;
stateBlock = OVRBarrelDistortionStateBlock;
texture[0] = "$backBuffer";
target = "$outTex";
// The actual barrel distortion
new BarrelDistortionPostEffect(OVRBarrelDistortionMonoStage2PostFX)
{
shader = OVRBarrelDistortionShader;
stateBlock = OVRBarrelDistortionStateBlock;
texture[0] = "$inTex";
target = "$backBuffer";
scaleOutput = 1.25;
};
};
function OVRBarrelDistortionMonoPostFX::setShaderConsts( %this )
{
%HMDIndex = 0;
%xOffsets = getOVRHMDEyeXOffsets(%HMDIndex);
%this.setShaderConst( "$LensXOffsets", %xOffsets );
}

View file

@ -0,0 +1,81 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "shadergen:/autogenConditioners.h"
#include "../postFx.hlsl"
#include "../../torque.hlsl"
uniform sampler2D backBuffer : register(S0);
uniform float3 LensCenter; // x=Left X, y=Right X, z=Y
uniform float2 ScreenCenter;
uniform float2 Scale;
uniform float2 ScaleIn;
uniform float4 HmdWarpParam;
// Scales input texture coordinates for distortion.
// ScaleIn maps texture coordinates to Scales to ([-1, 1]), although top/bottom will be
// larger due to aspect ratio.
float2 HmdWarp(float2 in01, float2 lensCenter)
{
float2 theta = (in01 - lensCenter) * ScaleIn; // Scales to [-1, 1]
float rSq = theta.x * theta.x + theta.y * theta.y;
float2 theta1 = theta * (HmdWarpParam.x + HmdWarpParam.y * rSq + HmdWarpParam.z * rSq * rSq + HmdWarpParam.w * rSq * rSq * rSq);
return lensCenter + Scale * theta1;
}
float4 main( PFXVertToPix IN ) : COLOR0
{
float2 texCoord;
float xOffset;
float2 lensCenter;
lensCenter.y = LensCenter.z;
if(IN.uv0.x < 0.5)
{
texCoord.x = IN.uv0.x;
texCoord.y = IN.uv0.y;
xOffset = 0.0;
lensCenter.x = LensCenter.x;
}
else
{
texCoord.x = IN.uv0.x - 0.5;
texCoord.y = IN.uv0.y;
xOffset = 0.5;
lensCenter.x = LensCenter.y;
}
float2 tc = HmdWarp(texCoord, lensCenter);
float4 color;
if (any(clamp(tc, ScreenCenter-float2(0.25,0.5), ScreenCenter+float2(0.25, 0.5)) - tc))
{
color = float4(0,0,0,0);
}
else
{
tc.x += xOffset;
color = tex2D(backBuffer, tc);
}
return color;
}

View file

@ -0,0 +1,60 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "shadergen:/autogenConditioners.h"
#include "../postFx.hlsl"
#include "../../torque.hlsl"
uniform sampler2D backBuffer : register(S0);
uniform float2 LensXOffsets;
float4 main( PFXVertToPix IN ) : COLOR0
{
float2 texCoord;
float xOffset;
float2 lensCenter;
lensCenter.y = 0.5;
if(IN.uv0.x < 0.5)
{
texCoord.x = IN.uv0.x;
texCoord.y = IN.uv0.y;
xOffset = 0.0;
lensCenter.x = LensXOffsets.x;
}
else
{
texCoord.x = IN.uv0.x - 0.5;
texCoord.y = IN.uv0.y;
xOffset = 0.5;
lensCenter.x = LensXOffsets.y;
}
texCoord.x *= 2.0;
texCoord.x += lensCenter.x;
texCoord.x *= 0.5;
texCoord.x += 0.25;
float4 color = tex2D(backBuffer, texCoord);
return color;
}

View file

@ -0,0 +1,80 @@
<?php
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
beginModule( 'oculusVR' );
// Look for the optional global from the project.conf.
global $OCULUSVR_SDK_PATH;
if (!$OCULUSVR_SDK_PATH)
{
// First look for an environment var.
$OCULUSVR_SDK_PATH = getenv( "TORQUE_OCULUSVR_PATH" );
if (strlen($OCULUSVR_SDK_PATH) == 0 || !file_exists($OCULUSVR_SDK_PATH))
{
// Sometimes users get confused and use this var.
$OCULUSVR_SDK_PATH = getenv( "OCULUSVR_SDK_PATH" );
}
// We need forward slashes for paths.
$OCULUSVR_SDK_PATH = str_replace( "\\", "/", $OCULUSVR_SDK_PATH);
// Remove trailing slashes.
$OCULUSVR_SDK_PATH = rtrim($OCULUSVR_SDK_PATH, " /");
}
// If we still don't have the SDK path then let the user know.
if (!file_exists($OCULUSVR_SDK_PATH))
{
trigger_error(
"\n*******************************************************************".
"\n".
"\n We were not able to find a valid path to the Oculus Rift SDK!".
"\n".
"\n You must install the latest Oculus VR SDK and set the path via a".
"\n \$OCULUSVR_SDK_PATH variable in your buildFiles/project.conf file".
"\n or by setting the TORQUE_OCULUSVR_PATH system environment variable".
"\n (may require a reboot).".
"\n".
"\n*******************************************************************".
"\n", E_USER_ERROR );
}
// Only Windows is supported at this time
if ( Generator::$platform == "win32" )
{
// Source
addEngineSrcDir( "platform/input/oculusVR" );
// Includes
addIncludePath( $OCULUSVR_SDK_PATH . "/LibOVR/Include" );
addIncludePath( $OCULUSVR_SDK_PATH . "/LibOVR/Src" );
// Libs
addProjectLibDir( $OCULUSVR_SDK_PATH . "/LibOVR/Lib/Win32" );
addProjectLibInput( "libovr.lib", "libovrd.lib" );
}
endModule();
?>