From 85730dfb590576049400d43d7a5ec443b4538d08 Mon Sep 17 00:00:00 2001 From: DavidWyand-GG Date: Sat, 19 Oct 2013 00:46:39 -0400 Subject: [PATCH] Oculus Rift Improvements - Now requires OVR SDK 0.2.5 - New chromatic aberration correction shader. Can be disabled by setting $pref::OculusVR::UseChromaticAberrationCorrection to false prior to enabling Rift display (such as for screen shots). - FXAA on by default when using full screen on the Rift. - Can now manually override IPD from script. Otherwise value set in profile is used. - Raw sensor data now available through input events (set $OculusVR::GenerateSensorRawEvents to true) and console methods. The raw data is acceleration, angular velocity, and magnetometer reading. - Can determine if magnetometer calibration data is available using a console method in order to notify the user. --- .../oculusVR/barrelDistortionPostEffect.cpp | 29 +- .../oculusVR/barrelDistortionPostEffect.h | 1 + .../input/oculusVR/oculusVRDevice.cpp | 332 +++++++++++++++++- .../platform/input/oculusVR/oculusVRDevice.h | 17 + .../input/oculusVR/oculusVRHMDDevice.cpp | 28 +- .../input/oculusVR/oculusVRHMDDevice.h | 27 ++ .../input/oculusVR/oculusVRSensorData.cpp | 37 ++ .../input/oculusVR/oculusVRSensorData.h | 9 + .../input/oculusVR/oculusVRSensorDevice.cpp | 171 ++++++++- .../input/oculusVR/oculusVRSensorDevice.h | 46 ++- .../platform/input/oculusVR/oculusVRUtil.cpp | 17 +- .../platform/input/oculusVR/oculusVRUtil.h | 9 + .../game/core/scripts/client/oculusVR.cs | 12 +- .../client/postFx/ovrBarrelDistortion.cs | 34 ++ .../oculusvr/barrelDistortionChromaP.hlsl | 95 +++++ .../Full/game/core/scripts/client/oculusVR.cs | 12 +- .../client/postFx/ovrBarrelDistortion.cs | 34 ++ .../oculusvr/barrelDistortionChromaP.hlsl | 95 +++++ 18 files changed, 985 insertions(+), 20 deletions(-) create mode 100644 Templates/Empty/game/shaders/common/postFx/oculusvr/barrelDistortionChromaP.hlsl create mode 100644 Templates/Full/game/shaders/common/postFx/oculusvr/barrelDistortionChromaP.hlsl diff --git a/Engine/source/platform/input/oculusVR/barrelDistortionPostEffect.cpp b/Engine/source/platform/input/oculusVR/barrelDistortionPostEffect.cpp index 2ef74ac1e..bc5fa8b1c 100644 --- a/Engine/source/platform/input/oculusVR/barrelDistortionPostEffect.cpp +++ b/Engine/source/platform/input/oculusVR/barrelDistortionPostEffect.cpp @@ -42,6 +42,7 @@ IMPLEMENT_CONOBJECT(BarrelDistortionPostEffect); BarrelDistortionPostEffect::BarrelDistortionPostEffect() : PostEffect(), mHmdWarpParamSC(NULL), + mHmdChromaAbSC(NULL), mScaleSC(NULL), mScaleInSC(NULL), mLensCenterSC(NULL), @@ -85,23 +86,22 @@ void BarrelDistortionPostEffect::onRemove() void BarrelDistortionPostEffect::_setupConstants( const SceneRenderState *state ) { + // Test if setup is required before calling the parent method as the parent method + // will set up the shader constants buffer for us. + bool setupRequired = mShaderConsts.isNull(); + Parent::_setupConstants(state); // Define the shader constants - if(!mHmdWarpParamSC) + if(setupRequired) + { mHmdWarpParamSC = mShader->getShaderConstHandle( "$HmdWarpParam" ); - - if(!mScaleSC) + mHmdChromaAbSC = mShader->getShaderConstHandle( "$HmdChromaAbParam" ); 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; @@ -119,6 +119,12 @@ void BarrelDistortionPostEffect::_setupConstants( const SceneRenderState *state mShaderConsts->set( mHmdWarpParamSC, distortion ); } + if(mHmdChromaAbSC->isValid()) + { + const Point4F& correction = hmd->getChromaticAbCorrection(); + mShaderConsts->set( mHmdChromaAbSC, correction ); + } + if(mScaleSC->isValid()) { F32 scaleFactor = hmd->getDistortionScale(); @@ -149,6 +155,11 @@ void BarrelDistortionPostEffect::_setupConstants( const SceneRenderState *state mShaderConsts->set( mHmdWarpParamSC, Point4F(0.0f, 0.0f, 0.0f, 0.0f) ); } + if(mHmdChromaAbSC->isValid()) + { + mShaderConsts->set( mHmdChromaAbSC, Point4F(1.0f, 0.0f, 1.0f, 0.0f) ); + } + if(mScaleSC->isValid()) { mShaderConsts->set( mScaleSC, Point2F(1.0f, 1.0f) ); diff --git a/Engine/source/platform/input/oculusVR/barrelDistortionPostEffect.h b/Engine/source/platform/input/oculusVR/barrelDistortionPostEffect.h index 389bd96ff..986ff2a67 100644 --- a/Engine/source/platform/input/oculusVR/barrelDistortionPostEffect.h +++ b/Engine/source/platform/input/oculusVR/barrelDistortionPostEffect.h @@ -31,6 +31,7 @@ class BarrelDistortionPostEffect : public PostEffect protected: GFXShaderConstHandle *mHmdWarpParamSC; + GFXShaderConstHandle *mHmdChromaAbSC; GFXShaderConstHandle *mScaleSC; GFXShaderConstHandle *mScaleInSC; GFXShaderConstHandle *mLensCenterSC; diff --git a/Engine/source/platform/input/oculusVR/oculusVRDevice.cpp b/Engine/source/platform/input/oculusVR/oculusVRDevice.cpp index c6dd0513a..695880988 100644 --- a/Engine/source/platform/input/oculusVR/oculusVRDevice.cpp +++ b/Engine/source/platform/input/oculusVR/oculusVRDevice.cpp @@ -60,12 +60,16 @@ bool OculusVRDevice::smEnableDevice = true; bool OculusVRDevice::smSimulateHMD = true; +bool OculusVRDevice::smUseChromaticAberrationCorrection = true; + bool OculusVRDevice::smGenerateAngleAxisRotationEvents = true; bool OculusVRDevice::smGenerateEulerRotationEvents = false; bool OculusVRDevice::smGenerateRotationAsAxisEvents = false; F32 OculusVRDevice::smMaximumAxisAngle = 25.0f; +bool OculusVRDevice::smGenerateSensorRawEvents = false; + bool OculusVRDevice::smGenerateWholeFrameEvents = false; OculusVRDevice::OculusVRDevice() @@ -99,6 +103,10 @@ void OculusVRDevice::staticInit() "@brief If true, the Oculus VR device will be enabled, if present.\n\n" "@ingroup Game"); + Con::addVariable("pref::OculusVR::UseChromaticAberrationCorrection", TypeBool, &smUseChromaticAberrationCorrection, + "@brief If true, Use the chromatic aberration correction version of the Oculus VR barrel distortion shader.\n\n" + "@ingroup Game"); + Con::addVariable("OculusVR::GenerateAngleAxisRotationEvents", TypeBool, &smGenerateAngleAxisRotationEvents, "@brief If true, broadcast sensor rotation events as angled axis.\n\n" "@ingroup Game"); @@ -114,6 +122,10 @@ void OculusVRDevice::staticInit() "Should range from 0 to 90 degrees.\n\n" "@ingroup Game"); + Con::addVariable("OculusVR::GenerateSensorRawEvents", TypeBool, &smGenerateSensorRawEvents, + "@brief If ture, broadcast sensor raw data: acceleration, angular velocity, magnetometer reading.\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"); @@ -313,7 +325,7 @@ bool OculusVRDevice::process() // Process each sensor for(U32 i=0; iprocess(mDeviceType, smGenerateAngleAxisRotationEvents, smGenerateEulerRotationEvents, smGenerateRotationAsAxisEvents, maxAxisRadius); + mSensorDevices[i]->process(mDeviceType, smGenerateAngleAxisRotationEvents, smGenerateEulerRotationEvents, smGenerateRotationAsAxisEvents, maxAxisRadius, smGenerateSensorRawEvents); } return true; @@ -391,6 +403,22 @@ const OculusVRHMDDevice* OculusVRDevice::getHMDDevice(U32 index) const return mHMDDevices[index]; } +F32 OculusVRDevice::getHMDCurrentIPD(U32 index) +{ + if(index >= mHMDDevices.size()) + return -1.0f; + + return mHMDDevices[index]->getIPD(); +} + +void OculusVRDevice::setHMDCurrentIPD(U32 index, F32 ipd) +{ + if(index >= mHMDDevices.size()) + return; + + return mHMDDevices[index]->setIPD(ipd, mScaleInputTexture); +} + //----------------------------------------------------------------------------- const OculusVRSensorDevice* OculusVRDevice::getSensorDevice(U32 index) const @@ -409,6 +437,30 @@ EulerF OculusVRDevice::getSensorEulerRotation(U32 index) return mSensorDevices[index]->getEulerRotation(); } +VectorF OculusVRDevice::getSensorAcceleration(U32 index) +{ + if(index >= mSensorDevices.size()) + return Point3F::Zero; + + return mSensorDevices[index]->getAcceleration(); +} + +EulerF OculusVRDevice::getSensorAngularVelocity(U32 index) +{ + if(index >= mSensorDevices.size()) + return Point3F::Zero; + + return mSensorDevices[index]->getAngularVelocity(); +} + +VectorF OculusVRDevice::getSensorMagnetometer(U32 index) +{ + if(index >= mSensorDevices.size()) + return Point3F::Zero; + + return mSensorDevices[index]->getMagnetometer(); +} + F32 OculusVRDevice::getSensorPredictionTime(U32 index) { const OculusVRSensorDevice* sensor = getSensorDevice(index); @@ -438,6 +490,57 @@ void OculusVRDevice::setAllSensorPredictionTime(F32 dt) } } +bool OculusVRDevice::getSensorGravityCorrection(U32 index) +{ + const OculusVRSensorDevice* sensor = getSensorDevice(index); + if(!sensor || !sensor->isValid()) + return false; + + return sensor->getGravityCorrection(); +} + +void OculusVRDevice::setSensorGravityCorrection(U32 index, bool state) +{ + if(index >= mSensorDevices.size()) + return; + + OculusVRSensorDevice* sensor = mSensorDevices[index]; + if(!sensor->isValid()) + return; + + sensor->setGravityCorrection(state); +} + +bool OculusVRDevice::getSensorYawCorrection(U32 index) +{ + const OculusVRSensorDevice* sensor = getSensorDevice(index); + if(!sensor || !sensor->isValid()) + return false; + + return sensor->getYawCorrection(); +} + +void OculusVRDevice::setSensorYawCorrection(U32 index, bool state) +{ + if(index >= mSensorDevices.size()) + return; + + OculusVRSensorDevice* sensor = mSensorDevices[index]; + if(!sensor->isValid()) + return; + + sensor->setYawCorrection(state); +} + +bool OculusVRDevice::getSensorMagnetometerCalibrated(U32 index) +{ + const OculusVRSensorDevice* sensor = getSensorDevice(index); + if(!sensor || !sensor->isValid()) + return false; + + return sensor->getMagnetometerCalibrationAvailable(); +} + void OculusVRDevice::resetAllSensors() { // Reset each sensor @@ -628,6 +731,46 @@ DefineEngineFunction(getOVRHMDDisplayDeviceName, const char*, (S32 index),, return hmd->getDisplayDeviceName(); } +DefineEngineFunction(getOVRHMDDisplayDeviceId, S32, (S32 index),, + "@brief MacOS display ID.\n\n" + "@param index The HMD index.\n" + "@return The ID of the HMD display device, if any.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return -1; + } + + const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index); + if(!hmd) + { + return -1; + } + + return hmd->getDisplayDeviceId(); +} + +DefineEngineFunction(getOVRHMDDisplayDesktopPos, Point2I, (S32 index),, + "@brief Desktop coordinate position of the screen (can be negative; may not be present on all platforms).\n\n" + "@param index The HMD index.\n" + "@return Position of the screen.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return Point2I::Zero; + } + + const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index); + if(!hmd) + { + return Point2I::Zero; + } + + return hmd->getDesktopPosition(); +} + DefineEngineFunction(getOVRHMDResolution, Point2I, (S32 index),, "@brief Provides the OVR HMD screen resolution.\n\n" "@param index The HMD index.\n" @@ -672,6 +815,78 @@ DefineEngineFunction(getOVRHMDDistortionCoefficients, String, (S32 index),, return buf; } +DefineEngineFunction(getOVRHMDChromaticAbCorrection, String, (S32 index),, + "@brief Provides the OVR HMD chromatic aberration correction values.\n\n" + "@param index The HMD index.\n" + "@return A four component string with the chromatic aberration correction values.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return "1 0 1 0"; + } + + const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index); + if(!hmd) + { + return "1 0 1 0"; + } + + const Point4F& c = hmd->getChromaticAbCorrection(); + char buf[256]; + dSprintf(buf, 256, "%g %g %g %g", c.x, c.y, c.z, c.w); + + return buf; +} + +DefineEngineFunction(getOVRHMDProfileIPD, F32, (S32 index),, + "@brief Physical distance between the user's eye centers as defined by the current profile.\n\n" + "@param index The HMD index.\n" + "@return The profile IPD.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return -1.0f; + } + + const OculusVRHMDDevice* hmd = OCULUSVRDEV->getHMDDevice(index); + if(!hmd) + { + return -1.0f; + } + + return hmd->getProfileIPD(); +} + +DefineEngineFunction(getOVRHMDCurrentIPD, F32, (S32 index),, + "@brief Physical distance between the user's eye centers.\n\n" + "@param index The HMD index.\n" + "@return The current IPD.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return -1.0f; + } + + return OCULUSVRDEV->getHMDCurrentIPD(index); +} + +DefineEngineFunction(setOVRHMDCurrentIPD, void, (S32 index, F32 ipd),, + "@brief Set the physical distance between the user's eye centers.\n\n" + "@param index The HMD index.\n" + "@param ipd The IPD to use.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return; + } + + OCULUSVRDEV->setHMDCurrentIPD(index, ipd); +} + DefineEngineFunction(getOVRHMDEyeXOffsets, Point2F, (S32 index),, "@brief Provides the OVR HMD eye x offsets in uv coordinates.\n\n" "@param index The HMD index.\n" @@ -787,6 +1002,49 @@ DefineEngineFunction(getOVRSensorEulerRotation, Point3F, (S32 index),, return Point3F(mRadToDeg(rot.x), mRadToDeg(rot.y), mRadToDeg(rot.z)); } +DefineEngineFunction(getOVRSensorAcceleration, Point3F, (S32 index),, + "@brief Get the acceleration values for the given sensor index.\n\n" + "@param index The sensor index.\n" + "@return The acceleration values of the Oculus VR sensor, in m/s^2.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return Point3F::Zero; + } + + return OCULUSVRDEV->getSensorAcceleration(index); +} + +DefineEngineFunction(getOVRSensorAngVelocity, Point3F, (S32 index),, + "@brief Get the angular velocity values for the given sensor index.\n\n" + "@param index The sensor index.\n" + "@return The angular velocity values of the Oculus VR sensor, in degrees/s.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return Point3F::Zero; + } + + EulerF rot = OCULUSVRDEV->getSensorAngularVelocity(index); + return Point3F(mRadToDeg(rot.x), mRadToDeg(rot.y), mRadToDeg(rot.z)); +} + +DefineEngineFunction(getOVRSensorMagnetometer, Point3F, (S32 index),, + "@brief Get the magnetometer reading (direction and field strength) for the given sensor index.\n\n" + "@param index The sensor index.\n" + "@return The magnetometer reading (direction and field strength) of the Oculus VR sensor, in Gauss.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return Point3F::Zero; + } + + return OCULUSVRDEV->getSensorMagnetometer(index); +} + DefineEngineFunction(getOVRSensorPredictionTime, F32, (S32 index),, "@brief Get the prediction time set for the given sensor index.\n\n" "@param index The sensor index.\n" @@ -828,6 +1086,78 @@ DefineEngineFunction(setAllSensorPredictionTime, void, (F32 dt),, OCULUSVRDEV->setAllSensorPredictionTime(dt); } +DefineEngineFunction(getOVRSensorGravityCorrection, bool, (S32 index),, + "@brief Get the gravity correction state for the given sensor index.\n\n" + "@param index The sensor index.\n" + "@return True if gravity correction (for pitch and roll) is active.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return false; + } + + return OCULUSVRDEV->getSensorGravityCorrection(index); +} + +DefineEngineFunction(setOVRSensorGravityCorrection, void, (S32 index, bool state),, + "@brief Set the gravity correction state for the given sensor index.\n\n" + "@param index The sensor index.\n" + "@param state The gravity correction state to change to.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return; + } + + OCULUSVRDEV->setSensorGravityCorrection(index, state); +} + +DefineEngineFunction(getOVRSensorYawCorrection, bool, (S32 index),, + "@brief Get the yaw correction state for the given sensor index.\n\n" + "@param index The sensor index.\n" + "@return True if yaw correction (using magnetometer calibration data) is active.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return false; + } + + return OCULUSVRDEV->getSensorYawCorrection(index); +} + +DefineEngineFunction(setOVRSensorYawCorrection, void, (S32 index, bool state),, + "@brief Set the yaw correction state for the given sensor index.\n\n" + "@param index The sensor index.\n" + "@param state The yaw correction state to change to.\n" + "@note Yaw correction cannot be enabled if the user has disabled it through " + "the Oculus VR control panel.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return; + } + + OCULUSVRDEV->setSensorYawCorrection(index, state); +} + +DefineEngineFunction(getOVRSensorMagnetometerCalibrated, bool, (S32 index),, + "@brief Get the magnetometer calibrated data state for the given sensor index.\n\n" + "@param index The sensor index.\n" + "@return True if magnetometer calibration data is available.\n" + "@ingroup Game") +{ + if(!ManagedSingleton::instanceOrNull()) + { + return false; + } + + return OCULUSVRDEV->getSensorMagnetometerCalibrated(index); +} + DefineEngineFunction(ovrResetAllSensors, void, (),, "@brief Resets all Oculus VR sensors.\n\n" "This resets all sensor orientations such that their 'normal' rotation " diff --git a/Engine/source/platform/input/oculusVR/oculusVRDevice.h b/Engine/source/platform/input/oculusVR/oculusVRDevice.h index 4ca37a6cc..429702322 100644 --- a/Engine/source/platform/input/oculusVR/oculusVRDevice.h +++ b/Engine/source/platform/input/oculusVR/oculusVRDevice.h @@ -44,6 +44,10 @@ public: // If no HMD is present simulate it being available static bool smSimulateHMD; + // Use the chromatic aberration correction version of the barrel + // distortion shader. + static bool smUseChromaticAberrationCorrection; + // Type of rotation events to broadcast static bool smGenerateAngleAxisRotationEvents; static bool smGenerateEulerRotationEvents; @@ -55,6 +59,9 @@ public: // as measured from a vector pointing straight up (in degrees) static F32 smMaximumAxisAngle; + // Broadcast sensor raw data: acceleration, angular velocity, magnetometer reading + static bool smGenerateSensorRawEvents; + // Indicates that a whole frame event should be generated and frames // should be buffered. static bool smGenerateWholeFrameEvents; @@ -131,14 +138,24 @@ public: // HMDs U32 getHMDCount() const { return mHMDDevices.size(); } const OculusVRHMDDevice* getHMDDevice(U32 index) const; + F32 getHMDCurrentIPD(U32 index); + void setHMDCurrentIPD(U32 index, F32 ipd); // Sensors U32 getSensorCount() const { return mSensorDevices.size(); } const OculusVRSensorDevice* getSensorDevice(U32 index) const; EulerF getSensorEulerRotation(U32 index); + VectorF getSensorAcceleration(U32 index); + EulerF getSensorAngularVelocity(U32 index); + VectorF getSensorMagnetometer(U32 index); F32 getSensorPredictionTime(U32 index); void setSensorPredictionTime(U32 index, F32 dt); void setAllSensorPredictionTime(F32 dt); + bool getSensorGravityCorrection(U32 index); + void setSensorGravityCorrection(U32 index, bool state); + bool getSensorYawCorrection(U32 index); + void setSensorYawCorrection(U32 index, bool state); + bool getSensorMagnetometerCalibrated(U32 index); void resetAllSensors(); public: diff --git a/Engine/source/platform/input/oculusVR/oculusVRHMDDevice.cpp b/Engine/source/platform/input/oculusVR/oculusVRHMDDevice.cpp index 96919ff81..bb52e803b 100644 --- a/Engine/source/platform/input/oculusVR/oculusVRHMDDevice.cpp +++ b/Engine/source/platform/input/oculusVR/oculusVRHMDDevice.cpp @@ -58,6 +58,10 @@ void OculusVRHMDDevice::set(OVR::HMDDevice* hmd, OVR::HMDInfo& info, bool calcul mVersion = info.Version; mDisplayDeviceName = info.DisplayDeviceName; + mDisplayId = info.DisplayId; + + mDesktopPosition.x = info.DesktopX; + mDesktopPosition.y = info.DesktopY; mResolution.x = info.HResolution; mResolution.y = info.VResolution; @@ -68,13 +72,19 @@ void OculusVRHMDDevice::set(OVR::HMDDevice* hmd, OVR::HMDInfo& info, bool calcul mVerticalEyeCenter = info.VScreenCenter; mEyeToScreen = info.EyeToScreenDistance; mLensSeparation = info.LensSeparationDistance; - mInterpupillaryDistance = info.InterpupillaryDistance; + mProfileInterpupillaryDistance = info.InterpupillaryDistance; + mInterpupillaryDistance = mProfileInterpupillaryDistance; mKDistortion.x = info.DistortionK[0]; mKDistortion.y = info.DistortionK[1]; mKDistortion.z = info.DistortionK[2]; mKDistortion.w = info.DistortionK[3]; + mChromaticAbCorrection.x = info.ChromaAbCorrection[0]; + mChromaticAbCorrection.y = info.ChromaAbCorrection[1]; + mChromaticAbCorrection.z = info.ChromaAbCorrection[2]; + mChromaticAbCorrection.w = info.ChromaAbCorrection[3]; + // Calculated values calculateValues(calculateDistortionScale); @@ -109,13 +119,27 @@ void OculusVRHMDDevice::createSimulatedPreviewRift(bool calculateDistortionScale mVerticalEyeCenter = 0.046799999f; mEyeToScreen = 0.041000001f; mLensSeparation = 0.064000003f; - mInterpupillaryDistance = 0.064000003f; + mProfileInterpupillaryDistance = 0.064000003f; + mInterpupillaryDistance = mProfileInterpupillaryDistance; mKDistortion.x = 1.0000000f; mKDistortion.y = 0.22000000f; mKDistortion.z = 0.23999999f; mKDistortion.w = 0.00000000f; + mChromaticAbCorrection.x = 0.995999f; + mChromaticAbCorrection.y = -0.004f; + mChromaticAbCorrection.z = 1.014f; + mChromaticAbCorrection.z = 0.0f; + + calculateValues(calculateDistortionScale); +} + +void OculusVRHMDDevice::setIPD(F32 ipd, bool calculateDistortionScale) +{ + mInterpupillaryDistance = ipd; + + // Recalculate as some values rely on the IPD calculateValues(calculateDistortionScale); } diff --git a/Engine/source/platform/input/oculusVR/oculusVRHMDDevice.h b/Engine/source/platform/input/oculusVR/oculusVRHMDDevice.h index dce8234eb..ddea2a48e 100644 --- a/Engine/source/platform/input/oculusVR/oculusVRHMDDevice.h +++ b/Engine/source/platform/input/oculusVR/oculusVRHMDDevice.h @@ -54,6 +54,12 @@ protected: // Windows display device name used in EnumDisplaySettings/CreateDC String mDisplayDeviceName; + // MacOS display ID + S32 mDisplayId; + + // Desktop coordinate position of the screen (can be negative; may not be present on all platforms) + Point2I mDesktopPosition; + // Whole screen resolution Point2I mResolution; @@ -70,6 +76,9 @@ protected: // Physical distance between lens centers, in meters F32 mLensSeparation; + // Physical distance between the user's eye centers as defined in the current profile + F32 mProfileInterpupillaryDistance; + // Physical distance between the user's eye centers F32 mInterpupillaryDistance; @@ -79,6 +88,9 @@ protected: // Radial distortion correction coefficients used by the barrel distortion shader Point4F mKDistortion; + // Chromatic aberration correction coefficients + Point4F mChromaticAbCorrection; + // 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 @@ -137,6 +149,12 @@ public: // Windows display device name used in EnumDisplaySettings/CreateDC const char* getDisplayDeviceName() const { return mDisplayDeviceName.c_str(); } + // MacOS display ID + S32 getDisplayDeviceId() const { return mDisplayId; } + + // Desktop coordinate position of the screen (can be negative; may not be present on all platforms) + const Point2I& getDesktopPosition() const { return mDesktopPosition; } + // Whole screen resolution const Point2I& getResolution() const { return mResolution; } @@ -153,15 +171,24 @@ public: // Physical distance between lens centers, in meters F32 getLensSeparation() const { return mLensSeparation; } + // Physical distance between the user's eye centers as defined by the current profile + F32 getProfileIPD() const { return mProfileInterpupillaryDistance; } + // Physical distance between the user's eye centers F32 getIPD() const { return mInterpupillaryDistance; } + // Set a new physical distance between the user's eye centers + void setIPD(F32 ipd, bool calculateDistortionScale); + // 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; } + // Chromatic aberration correction coefficients used by the barrel distortion shader + const Point4F& getChromaticAbCorrection() const { return mChromaticAbCorrection; } + // Calculated values of eye x offset from center in normalized (uv) coordinates. const Point2F& getEyeUVOffset() const { return mEyeUVOffset; } diff --git a/Engine/source/platform/input/oculusVR/oculusVRSensorData.cpp b/Engine/source/platform/input/oculusVR/oculusVRSensorData.cpp index 1ffb6a1b1..219897577 100644 --- a/Engine/source/platform/input/oculusVR/oculusVRSensorData.cpp +++ b/Engine/source/platform/input/oculusVR/oculusVRSensorData.cpp @@ -56,6 +56,24 @@ void OculusVRSensorData::setData(OVR::SensorFusion& data, const F32& maxAxisRadi // Sensor rotation as axis OculusVRUtil::calculateAxisRotation(mRot, maxAxisRadius, mRotAxis); + // Sensor raw values + OVR::Vector3f accel = data.GetAcceleration(); + OculusVRUtil::convertAcceleration(accel, mAcceleration); + + OVR::Vector3f angVel = data.GetAngularVelocity(); + OculusVRUtil::convertAngularVelocity(angVel, mAngVelocity); + + OVR::Vector3f mag; + if(data.HasMagCalibration() && data.IsYawCorrectionEnabled()) + { + mag = data.GetCalibratedMagnetometer(); + } + else + { + mag = data.GetMagnetometer(); + } + OculusVRUtil::convertMagnetometer(mag, mMagnetometer); + mDataSet = true; } @@ -69,6 +87,11 @@ void OculusVRSensorData::simulateData(const F32& maxAxisRadius) // Sensor rotation as axis OculusVRUtil::calculateAxisRotation(mRot, maxAxisRadius, mRotAxis); + // Sensor raw values + mAcceleration.zero(); + mAngVelocity.zero(); + mMagnetometer.zero(); + mDataSet = true; } @@ -92,5 +115,19 @@ U32 OculusVRSensorData::compare(OculusVRSensorData* other) result |= DIFF_ROTAXISY; } + // Check raw values + if(mAcceleration.x != other->mAcceleration.x || mAcceleration.y != other->mAcceleration.y || mAcceleration.z != other->mAcceleration.z || !mDataSet) + { + result |= DIFF_ACCEL; + } + if(mAngVelocity.x != other->mAngVelocity.x || mAngVelocity.y != other->mAngVelocity.y || mAngVelocity.z != other->mAngVelocity.z || !mDataSet) + { + result |= DIFF_ANGVEL; + } + if(mMagnetometer.x != other->mMagnetometer.x || mMagnetometer.y != other->mMagnetometer.y || mMagnetometer.z != other->mMagnetometer.z || !mDataSet) + { + result |= DIFF_MAG; + } + return result; } diff --git a/Engine/source/platform/input/oculusVR/oculusVRSensorData.h b/Engine/source/platform/input/oculusVR/oculusVRSensorData.h index 41382900d..41256a2e1 100644 --- a/Engine/source/platform/input/oculusVR/oculusVRSensorData.h +++ b/Engine/source/platform/input/oculusVR/oculusVRSensorData.h @@ -36,8 +36,12 @@ struct OculusVRSensorData DIFF_ROT = (1<<0), DIFF_ROTAXISX = (1<<1), DIFF_ROTAXISY = (1<<2), + DIFF_ACCEL = (1<<3), + DIFF_ANGVEL = (1<<4), + DIFF_MAG = (1<<5), DIFF_ROTAXIS = (DIFF_ROTAXISX | DIFF_ROTAXISY), + DIFF_RAW = (DIFF_ACCEL | DIFF_ANGVEL | DIFF_MAG), }; bool mDataSet; @@ -50,6 +54,11 @@ struct OculusVRSensorData // Controller rotation as axis x, y Point2F mRotAxis; + // Raw values + VectorF mAcceleration; + EulerF mAngVelocity; + VectorF mMagnetometer; + OculusVRSensorData(); /// Reset the data diff --git a/Engine/source/platform/input/oculusVR/oculusVRSensorDevice.cpp b/Engine/source/platform/input/oculusVR/oculusVRSensorDevice.cpp index dad2bba20..460986889 100644 --- a/Engine/source/platform/input/oculusVR/oculusVRSensorDevice.cpp +++ b/Engine/source/platform/input/oculusVR/oculusVRSensorDevice.cpp @@ -29,6 +29,9 @@ 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}; +U32 OculusVRSensorDevice::OVR_SENSORACCELERATION[OculusVRConstants::MaxSensors] = {0}; +U32 OculusVRSensorDevice::OVR_SENSORANGVEL[OculusVRConstants::MaxSensors] = {0}; +U32 OculusVRSensorDevice::OVR_SENSORMAGNETOMETER[OculusVRConstants::MaxSensors] = {0}; OculusVRSensorDevice::OculusVRSensorDevice() { @@ -74,6 +77,7 @@ void OculusVRSensorDevice::set(OVR::SensorDevice* sensor, OVR::SensorInfo& info, mDevice = sensor; mSensorFusion.AttachToSensor(sensor); + mYawCorrectionDisabled = !mSensorFusion.IsYawCorrectionEnabled(); // DeviceInfo mProductName = info.ProductName; @@ -110,6 +114,7 @@ void OculusVRSensorDevice::createSimulatedPreviewRift(S32 actionCodeIndex) { mIsValid = false; mIsSimulation = true; + mYawCorrectionDisabled = true; // DeviceInfo mProductName = "Tracker DK"; @@ -145,6 +150,10 @@ void OculusVRSensorDevice::buildCodeTable() OVR_SENSORROTAXISX[i] = INPUTMGR->getNextDeviceCode(); OVR_SENSORROTAXISY[i] = INPUTMGR->getNextDeviceCode(); + + OVR_SENSORACCELERATION[i] = INPUTMGR->getNextDeviceCode(); + OVR_SENSORANGVEL[i] = INPUTMGR->getNextDeviceCode(); + OVR_SENSORMAGNETOMETER[i] = INPUTMGR->getNextDeviceCode(); } // Build out the virtual map @@ -155,16 +164,27 @@ void OculusVRSensorDevice::buildCodeTable() INPUTMGR->addVirtualMap( buffer, SI_ROT, OVR_SENSORROT[i] ); dSprintf(buffer, 64, "ovr_sensorrotang%d", i); - INPUTMGR->addVirtualMap( buffer, SI_ROT, OVR_SENSORROTANG[i] ); + INPUTMGR->addVirtualMap( buffer, SI_POS, 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] ); + + dSprintf(buffer, 64, "ovr_sensoracceleration%d", i); + INPUTMGR->addVirtualMap( buffer, SI_POS, OVR_SENSORACCELERATION[i] ); + + dSprintf(buffer, 64, "ovr_sensorangvel%d", i); + INPUTMGR->addVirtualMap( buffer, SI_POS, OVR_SENSORANGVEL[i] ); + + dSprintf(buffer, 64, "ovr_sensormagnetometer%d", i); + INPUTMGR->addVirtualMap( buffer, SI_POS, OVR_SENSORMAGNETOMETER[i] ); } } -bool OculusVRSensorDevice::process(U32 deviceType, bool generateRotAsAngAxis, bool generateRotAsEuler, bool generateRotationAsAxisEvents, F32 maxAxisRadius) +//----------------------------------------------------------------------------- + +bool OculusVRSensorDevice::process(U32 deviceType, bool generateRotAsAngAxis, bool generateRotAsEuler, bool generateRotationAsAxisEvents, F32 maxAxisRadius, bool generateRawSensor) { if(!mIsValid) return false; @@ -215,9 +235,32 @@ bool OculusVRSensorDevice::process(U32 deviceType, bool generateRotAsAngAxis, bo INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_AXIS, OVR_SENSORROTAXISY[mActionCodeIndex], SI_MOVE, currentBuffer->mRotAxis.y); } + // Raw sensor event + if(generateRawSensor && diff & OculusVRSensorData::DIFF_RAW) + { + if(diff & OculusVRSensorData::DIFF_ACCEL) + INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_POS, OVR_SENSORACCELERATION[mActionCodeIndex], SI_MOVE, currentBuffer->mAcceleration); + + if(diff & OculusVRSensorData::DIFF_ANGVEL) + { + // Convert angles to degrees + VectorF angles; + for(U32 i=0; i<3; ++i) + { + angles[i] = mRadToDeg(currentBuffer->mAngVelocity[i]); + } + INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_POS, OVR_SENSORANGVEL[mActionCodeIndex], SI_MOVE, angles); + } + + if(diff & OculusVRSensorData::DIFF_MAG) + INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_POS, OVR_SENSORMAGNETOMETER[mActionCodeIndex], SI_MOVE, currentBuffer->mMagnetometer); + } + return true; } +//----------------------------------------------------------------------------- + void OculusVRSensorDevice::reset() { if(!mIsValid) @@ -242,6 +285,51 @@ void OculusVRSensorDevice::setPredictionTime(F32 dt) mSensorFusion.SetPrediction(dt); } +bool OculusVRSensorDevice::getGravityCorrection() const +{ + if(!mIsValid) + return false; + + return mSensorFusion.IsGravityEnabled(); +} + +void OculusVRSensorDevice::setGravityCorrection(bool state) +{ + if(!mIsValid) + return; + + mSensorFusion.SetGravityEnabled(state); +} + +bool OculusVRSensorDevice::getYawCorrection() const +{ + if(!mIsValid) + return false; + + return mSensorFusion.IsYawCorrectionEnabled(); +} + +void OculusVRSensorDevice::setYawCorrection(bool state) +{ + if(!mIsValid) + return; + + if(mYawCorrectionDisabled || !mSensorFusion.HasMagCalibration()) + return; + + mSensorFusion.SetYawCorrectionEnabled(state); +} + +bool OculusVRSensorDevice::getMagnetometerCalibrationAvailable() const +{ + if(!mIsValid) + return false; + + return mSensorFusion.HasMagCalibration(); +} + +//----------------------------------------------------------------------------- + EulerF OculusVRSensorDevice::getEulerRotation() { if(!mIsValid) @@ -263,3 +351,82 @@ EulerF OculusVRSensorDevice::getEulerRotation() return rot; } + +EulerF OculusVRSensorDevice::getRawEulerRotation() +{ + if(!mIsValid) + return Point3F::Zero; + + OVR::Quatf orientation; + orientation = mSensorFusion.GetOrientation(); + + // Sensor rotation in Euler format + EulerF rot; + OculusVRUtil::convertRotation(orientation, rot); + + return rot; +} + +VectorF OculusVRSensorDevice::getAcceleration() +{ + if(!mIsValid) + return VectorF::Zero; + + OVR::Vector3f a = mSensorFusion.GetAcceleration(); + + // Sensor acceleration in VectorF format + VectorF acceleration; + OculusVRUtil::convertAcceleration(a, acceleration); + + return acceleration; +} + +EulerF OculusVRSensorDevice::getAngularVelocity() +{ + if(!mIsValid) + return EulerF::Zero; + + OVR::Vector3f v = mSensorFusion.GetAngularVelocity(); + + // Sensor angular velocity in EulerF format + EulerF vel; + OculusVRUtil::convertAngularVelocity(v, vel); + + return vel; +} + +VectorF OculusVRSensorDevice::getMagnetometer() +{ + if(!mIsValid) + return VectorF::Zero; + + OVR::Vector3f m; + if(mSensorFusion.HasMagCalibration() && mSensorFusion.IsYawCorrectionEnabled()) + { + m = mSensorFusion.GetCalibratedMagnetometer(); + } + else + { + m = mSensorFusion.GetMagnetometer(); + } + + // Sensor magnetometer reading in VectorF format + VectorF mag; + OculusVRUtil::convertMagnetometer(m, mag); + + return mag; +} + +VectorF OculusVRSensorDevice::getRawMagnetometer() +{ + if(!mIsValid) + return VectorF::Zero; + + OVR::Vector3f m = mSensorFusion.GetMagnetometer(); + + // Sensor magnetometer reading in VectorF format + VectorF mag; + OculusVRUtil::convertMagnetometer(m, mag); + + return mag; +} diff --git a/Engine/source/platform/input/oculusVR/oculusVRSensorDevice.h b/Engine/source/platform/input/oculusVR/oculusVRSensorDevice.h index c5ed30322..fcaca44d5 100644 --- a/Engine/source/platform/input/oculusVR/oculusVRSensorDevice.h +++ b/Engine/source/platform/input/oculusVR/oculusVRSensorDevice.h @@ -50,6 +50,10 @@ public: static U32 OVR_SENSORROTAXISX[OculusVRConstants::MaxSensors]; // SI_AXIS static U32 OVR_SENSORROTAXISY[OculusVRConstants::MaxSensors]; + static U32 OVR_SENSORACCELERATION[OculusVRConstants::MaxSensors]; // SI_POS + static U32 OVR_SENSORANGVEL[OculusVRConstants::MaxSensors]; // SI_POS but is EulerF + static U32 OVR_SENSORMAGNETOMETER[OculusVRConstants::MaxSensors]; // SI_POS + protected: bool mIsValid; @@ -69,6 +73,9 @@ protected: U16 mProductId; String mSerialNumber; + // Has yaw correction been disabled by the control panel + bool mYawCorrectionDisabled; + // Assigned by the OculusVRDevice S32 mActionCodeIndex; @@ -99,7 +106,7 @@ public: bool isValid() const {return mIsValid;} bool isSimulated() {return mIsSimulation;} - bool process(U32 deviceType, bool generateRotAsAngAxis, bool generateRotAsEuler, bool generateRotationAsAxisEvents, F32 maxAxisRadius); + bool process(U32 deviceType, bool generateRotAsAngAxis, bool generateRotAsEuler, bool generateRotationAsAxisEvents, F32 maxAxisRadius, bool generateRawSensor); void reset(); @@ -109,6 +116,26 @@ public: // Set the prediction time for the sensor fusion. The time is in seconds. void setPredictionTime(F32 dt); + // Is gravity correction enabled for pitch and roll + bool getGravityCorrection() const; + + // Set the pitch and roll gravity correction + void setGravityCorrection(bool state); + + // Has yaw correction been disabled using the control panel + bool getYawCorrectionUserDisabled() const { return mYawCorrectionDisabled; } + + // Is yaw correction enabled + bool getYawCorrection() const; + + // Set the yaw correction. Note: if magnetometer calibration data is not present, + // or user has disabled yaw correction in the control panel, this method will + // not enable it. + void setYawCorrection(bool state); + + // Is magnetometer calibration data available for this sensor + bool getMagnetometerCalibrationAvailable() const; + const char* getProductName() { return mProductName.c_str(); } const char* getManufacturer() { return mManufacturer.c_str(); } U32 getVersion() { return mVersion; } @@ -116,7 +143,24 @@ public: U16 getProductId() { return mProductId; } const char* getSerialNumber() { return mSerialNumber; } + // Get the current rotation of the sensor. Uses prediction if set. EulerF getEulerRotation(); + + // Get the current rotation of the sensor. + EulerF getRawEulerRotation(); + + // Get the current absolute acceleration reading, in m/s^2 + VectorF getAcceleration(); + + // Get the current angular velocity reading, in rad/s + EulerF getAngularVelocity(); + + // Get the current magnetometer reading (direction and field strength), in Gauss. + // Uses magnetometer calibration if set. + VectorF getMagnetometer(); + + // Get the current raw magnetometer reading (direction and field strength), in Gauss + VectorF getRawMagnetometer(); }; #endif // _OCULUSVRSENSORDEVICE_H_ diff --git a/Engine/source/platform/input/oculusVR/oculusVRUtil.cpp b/Engine/source/platform/input/oculusVR/oculusVRUtil.cpp index 46b4c7a34..69ddbc380 100644 --- a/Engine/source/platform/input/oculusVR/oculusVRUtil.cpp +++ b/Engine/source/platform/input/oculusVR/oculusVRUtil.cpp @@ -73,4 +73,19 @@ void calculateAxisRotation(const MatrixF& inRotation, const F32& maxAxisRadius, outRotation.y = axis.y; } -} \ No newline at end of file +void convertAcceleration(OVR::Vector3f& inAcceleration, VectorF& outAcceleration) +{ + outAcceleration.set(inAcceleration.x, -inAcceleration.z, inAcceleration.y); +} + +void convertAngularVelocity(OVR::Vector3f& inAngVel, EulerF& outAngVel) +{ + outAngVel.set(-inAngVel.x, inAngVel.z, -inAngVel.y); +} + +void convertMagnetometer(OVR::Vector3f& inMagnetometer, VectorF& outMagnetometer) +{ + outMagnetometer.set(inMagnetometer.x, -inMagnetometer.z, inMagnetometer.y); +} + +} diff --git a/Engine/source/platform/input/oculusVR/oculusVRUtil.h b/Engine/source/platform/input/oculusVR/oculusVRUtil.h index f4088f3c1..ccf6018e9 100644 --- a/Engine/source/platform/input/oculusVR/oculusVRUtil.h +++ b/Engine/source/platform/input/oculusVR/oculusVRUtil.h @@ -37,6 +37,15 @@ namespace OculusVRUtil /// Calcualte a sensor's rotation as if it were a thumb stick axis void calculateAxisRotation(const MatrixF& inRotation, const F32& maxAxisRadius, Point2F& outRotation); + + /// Convert an OVR sensor's acceleration to Torque 3D vector (in m/s^2) + void convertAcceleration(OVR::Vector3f& inAcceleration, VectorF& outAcceleration); + + /// Convert OVR sensor's angular velocity to Torque 3D Euler angles (in radians/s) + void convertAngularVelocity(OVR::Vector3f& inAngVel, EulerF& outAngVel); + + /// Convert an OVR sensor's magnetometer reading (direction and field strength) to Torque 3D vector (in Gauss) + void convertMagnetometer(OVR::Vector3f& inMagnetometer, VectorF& outMagnetometer); } #endif // _OCULUSVRUTIL_H_ diff --git a/Templates/Empty/game/core/scripts/client/oculusVR.cs b/Templates/Empty/game/core/scripts/client/oculusVR.cs index 81015b40f..f0035999c 100644 --- a/Templates/Empty/game/core/scripts/client/oculusVR.cs +++ b/Templates/Empty/game/core/scripts/client/oculusVR.cs @@ -63,7 +63,14 @@ function enableOculusVRDisplay(%gameConnection, %trueStereoRendering) if(%trueStereoRendering) { - OVRBarrelDistortionPostFX.isEnabled = true; + if($pref::OculusVR::UseChromaticAberrationCorrection) + { + OVRBarrelDistortionChromaPostFX.isEnabled = true; + } + else + { + OVRBarrelDistortionPostFX.isEnabled = true; + } } else { @@ -81,6 +88,7 @@ function disableOculusVRDisplay(%gameConnection) %gameConnection.clearDisplayDevice(); PlayGui.renderStyle = "standard"; OVRBarrelDistortionPostFX.isEnabled = false; + OVRBarrelDistortionChromaPostFX.isEnabled = false; OVRBarrelDistortionMonoPostFX.isEnabled = false; } @@ -112,7 +120,7 @@ function setStandardOculusVRControlScheme(%gameConnection) function setVideoModeForOculusVRDisplay(%fullscreen) { %res = getOVRHMDResolution(0); - Canvas.setVideoMode(%res.x, %res.y, %fullscreen, 32, 0); + Canvas.setVideoMode(%res.x, %res.y, %fullscreen, 32, 4); } //----------------------------------------------------------------------------- diff --git a/Templates/Empty/game/core/scripts/client/postFx/ovrBarrelDistortion.cs b/Templates/Empty/game/core/scripts/client/postFx/ovrBarrelDistortion.cs index 7978a6bc8..cbd72ec84 100644 --- a/Templates/Empty/game/core/scripts/client/postFx/ovrBarrelDistortion.cs +++ b/Templates/Empty/game/core/scripts/client/postFx/ovrBarrelDistortion.cs @@ -44,6 +44,14 @@ singleton ShaderData( OVRBarrelDistortionShader ) pixVersion = 2.0; }; +singleton ShaderData( OVRBarrelDistortionChromaShader ) +{ + DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl"; + DXPixelShaderFile = "shaders/common/postFx/oculusvr/barrelDistortionChromaP.hlsl"; + + pixVersion = 2.0; +}; + //----------------------------------------------------------------------------- // GFX state blocks //----------------------------------------------------------------------------- @@ -78,6 +86,32 @@ singleton BarrelDistortionPostEffect( OVRBarrelDistortionPostFX ) scaleOutput = 1.25; }; +//----------------------------------------------------------------------------- +// Barrel Distortion with Chromatic Aberration Correction 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. +// This version applies a chromatic aberration correction during the +// barrel distortion. +//----------------------------------------------------------------------------- +singleton BarrelDistortionPostEffect( OVRBarrelDistortionChromaPostFX ) +{ + isEnabled = false; + allowReflectPass = false; + + renderTime = "PFXAfterDiffuse"; + renderPriority = 100; + + // The barrel distortion + shader = OVRBarrelDistortionChromaShader; + stateBlock = OVRBarrelDistortionStateBlock; + + texture[0] = "$backBuffer"; + + scaleOutput = 1.25; +}; + //----------------------------------------------------------------------------- // Barrel Distortion Mono PostFx // diff --git a/Templates/Empty/game/shaders/common/postFx/oculusvr/barrelDistortionChromaP.hlsl b/Templates/Empty/game/shaders/common/postFx/oculusvr/barrelDistortionChromaP.hlsl new file mode 100644 index 000000000..726fb0afc --- /dev/null +++ b/Templates/Empty/game/shaders/common/postFx/oculusvr/barrelDistortionChromaP.hlsl @@ -0,0 +1,95 @@ +//----------------------------------------------------------------------------- +// 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; +uniform float4 HmdChromaAbParam; // Chromatic aberration correction + +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; + } + + // 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 theta = (texCoord - 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); + + // Detect whether blue texture coordinates are out of range + // since these will scaled out the furthest. + float2 thetaBlue = theta1 * (HmdChromaAbParam.z + HmdChromaAbParam.w * rSq); + float2 tcBlue = lensCenter + Scale * thetaBlue; + + float4 color; + if (any(clamp(tcBlue, ScreenCenter-float2(0.25,0.5), ScreenCenter+float2(0.25, 0.5)) - tcBlue)) + { + color = float4(0,0,0,0); + } + else + { + // Now do blue texture lookup. + tcBlue.x += xOffset; + float blue = tex2D(backBuffer, tcBlue).b; + + // Do green lookup (no scaling). + float2 tcGreen = lensCenter + Scale * theta1; + tcGreen.x += xOffset; + float green = tex2D(backBuffer, tcGreen).g; + + // Do red scale and lookup. + float2 thetaRed = theta1 * (HmdChromaAbParam.x + HmdChromaAbParam.y * rSq); + float2 tcRed = lensCenter + Scale * thetaRed; + tcRed.x += xOffset; + float red = tex2D(backBuffer, tcRed).r; + + color = float4(red, green, blue, 1); + } + + return color; +} diff --git a/Templates/Full/game/core/scripts/client/oculusVR.cs b/Templates/Full/game/core/scripts/client/oculusVR.cs index 81015b40f..f0035999c 100644 --- a/Templates/Full/game/core/scripts/client/oculusVR.cs +++ b/Templates/Full/game/core/scripts/client/oculusVR.cs @@ -63,7 +63,14 @@ function enableOculusVRDisplay(%gameConnection, %trueStereoRendering) if(%trueStereoRendering) { - OVRBarrelDistortionPostFX.isEnabled = true; + if($pref::OculusVR::UseChromaticAberrationCorrection) + { + OVRBarrelDistortionChromaPostFX.isEnabled = true; + } + else + { + OVRBarrelDistortionPostFX.isEnabled = true; + } } else { @@ -81,6 +88,7 @@ function disableOculusVRDisplay(%gameConnection) %gameConnection.clearDisplayDevice(); PlayGui.renderStyle = "standard"; OVRBarrelDistortionPostFX.isEnabled = false; + OVRBarrelDistortionChromaPostFX.isEnabled = false; OVRBarrelDistortionMonoPostFX.isEnabled = false; } @@ -112,7 +120,7 @@ function setStandardOculusVRControlScheme(%gameConnection) function setVideoModeForOculusVRDisplay(%fullscreen) { %res = getOVRHMDResolution(0); - Canvas.setVideoMode(%res.x, %res.y, %fullscreen, 32, 0); + Canvas.setVideoMode(%res.x, %res.y, %fullscreen, 32, 4); } //----------------------------------------------------------------------------- diff --git a/Templates/Full/game/core/scripts/client/postFx/ovrBarrelDistortion.cs b/Templates/Full/game/core/scripts/client/postFx/ovrBarrelDistortion.cs index 7978a6bc8..cbd72ec84 100644 --- a/Templates/Full/game/core/scripts/client/postFx/ovrBarrelDistortion.cs +++ b/Templates/Full/game/core/scripts/client/postFx/ovrBarrelDistortion.cs @@ -44,6 +44,14 @@ singleton ShaderData( OVRBarrelDistortionShader ) pixVersion = 2.0; }; +singleton ShaderData( OVRBarrelDistortionChromaShader ) +{ + DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl"; + DXPixelShaderFile = "shaders/common/postFx/oculusvr/barrelDistortionChromaP.hlsl"; + + pixVersion = 2.0; +}; + //----------------------------------------------------------------------------- // GFX state blocks //----------------------------------------------------------------------------- @@ -78,6 +86,32 @@ singleton BarrelDistortionPostEffect( OVRBarrelDistortionPostFX ) scaleOutput = 1.25; }; +//----------------------------------------------------------------------------- +// Barrel Distortion with Chromatic Aberration Correction 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. +// This version applies a chromatic aberration correction during the +// barrel distortion. +//----------------------------------------------------------------------------- +singleton BarrelDistortionPostEffect( OVRBarrelDistortionChromaPostFX ) +{ + isEnabled = false; + allowReflectPass = false; + + renderTime = "PFXAfterDiffuse"; + renderPriority = 100; + + // The barrel distortion + shader = OVRBarrelDistortionChromaShader; + stateBlock = OVRBarrelDistortionStateBlock; + + texture[0] = "$backBuffer"; + + scaleOutput = 1.25; +}; + //----------------------------------------------------------------------------- // Barrel Distortion Mono PostFx // diff --git a/Templates/Full/game/shaders/common/postFx/oculusvr/barrelDistortionChromaP.hlsl b/Templates/Full/game/shaders/common/postFx/oculusvr/barrelDistortionChromaP.hlsl new file mode 100644 index 000000000..726fb0afc --- /dev/null +++ b/Templates/Full/game/shaders/common/postFx/oculusvr/barrelDistortionChromaP.hlsl @@ -0,0 +1,95 @@ +//----------------------------------------------------------------------------- +// 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; +uniform float4 HmdChromaAbParam; // Chromatic aberration correction + +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; + } + + // 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 theta = (texCoord - 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); + + // Detect whether blue texture coordinates are out of range + // since these will scaled out the furthest. + float2 thetaBlue = theta1 * (HmdChromaAbParam.z + HmdChromaAbParam.w * rSq); + float2 tcBlue = lensCenter + Scale * thetaBlue; + + float4 color; + if (any(clamp(tcBlue, ScreenCenter-float2(0.25,0.5), ScreenCenter+float2(0.25, 0.5)) - tcBlue)) + { + color = float4(0,0,0,0); + } + else + { + // Now do blue texture lookup. + tcBlue.x += xOffset; + float blue = tex2D(backBuffer, tcBlue).b; + + // Do green lookup (no scaling). + float2 tcGreen = lensCenter + Scale * theta1; + tcGreen.x += xOffset; + float green = tex2D(backBuffer, tcGreen).g; + + // Do red scale and lookup. + float2 thetaRed = theta1 * (HmdChromaAbParam.x + HmdChromaAbParam.y * rSq); + float2 tcRed = lensCenter + Scale * thetaRed; + tcRed.x += xOffset; + float red = tex2D(backBuffer, tcRed).r; + + color = float4(red, green, blue, 1); + } + + return color; +}