void MainLoop() { Layer[0] = new VRLayer(Session); // Create a trivial model to represent the left controller TriangleSet cube; cube.AddSolidColorBox(0.05f, -0.05f, 0.05f, -0.05f, 0.05f, -0.05f, 0xff404040); Model * controller = new Model(&cube, XMFLOAT3(0, 0, 0), XMFLOAT4(0, 0, 0, 1), new Material(new Texture(false, 256, 256, Texture::AUTO_CEILING))); // Main loop while (HandleMessages()) { // We don't allow yaw change for now, as this sample is too simple to cater for it. ActionFromInput(1.0f,false); ovrTrackingState hmdState = Layer[0]->GetEyePoses(); //Write position and orientation into controller model. controller->Pos = XMFLOAT3(XMVectorGetX(MainCam->Pos) + hmdState.HandPoses[ovrHand_Left].ThePose.Position.x, XMVectorGetY(MainCam->Pos) + hmdState.HandPoses[ovrHand_Left].ThePose.Position.y, XMVectorGetZ(MainCam->Pos) + hmdState.HandPoses[ovrHand_Left].ThePose.Position.z); controller->Rot = XMFLOAT4(hmdState.HandPoses[ovrHand_Left].ThePose.Orientation.x, hmdState.HandPoses[ovrHand_Left].ThePose.Orientation.y, hmdState.HandPoses[ovrHand_Left].ThePose.Orientation.z, hmdState.HandPoses[ovrHand_Left].ThePose.Orientation.w); //Button presses are modifying the colour of the controller model below ovrInputState inputState; ovr_GetInputState(Session, ovrControllerType_Touch, &inputState); for (int eye = 0; eye < 2; ++eye) { XMMATRIX viewProj = Layer[0]->RenderSceneToEyeBuffer(MainCam, RoomScene, eye); // Render the controller model controller->Render(&viewProj, 1, inputState.Buttons & ovrTouch_X ? 1.0f : 0.0f, inputState.Buttons & ovrTouch_Y ? 1.0f : 0.0f, 1, true); } Layer[0]->PrepareLayerHeader(); DistortAndPresent(1); } delete controller; }
int main() { // Register a callback to clean up when the process exits. atexit(Shutdown); while (true) { // Retry initialization each frame until it succeeds. It will early-out thereafter. Initialize(); // Each frame is 10ms to save CPU. Sleep(10); // Handle button input from LibOVR. ovrInputState inputState; memset(&inputState, 0, sizeof(ovrInputState)); if (OVR_SUCCESS(ovr_GetInputState(g_session, g_controllerType, &inputState))) SendKeysForInputState(inputState); } }
void MainLoop() { Layer[0] = new VRLayer(Session); while (HandleMessages()) { ActionFromInput(); Layer[0]->GetEyePoses(); // Read the remote state ovrInputState inputState; ovr_GetInputState(Session, ovrControllerType_Remote, &inputState); unsigned int result = ovr_GetConnectedControllerTypes(Session); bool isRemoteConnected = (result & ovrControllerType_Remote) ? true : false; // Some auxiliary controls we're going to read from the remote. XMVECTOR forward = XMVector3Rotate(XMVectorSet(0, 0, -0.05f, 0), MainCam->Rot); XMVECTOR right = XMVector3Rotate(XMVectorSet(0.05f, 0, 0, 0), MainCam->Rot); if (inputState.Buttons & ovrButton_Up) MainCam->Pos = XMVectorAdd(MainCam->Pos, forward); if (inputState.Buttons & ovrButton_Down) MainCam->Pos = XMVectorSubtract(MainCam->Pos, forward); if (inputState.Buttons & ovrButton_Left) MainCam->Pos = XMVectorSubtract(MainCam->Pos, right); if (inputState.Buttons & ovrButton_Right) MainCam->Pos = XMVectorAdd(MainCam->Pos, right); for (int eye = 0; eye < 2; ++eye) { //Tint the world, green for it the controller is attached, otherwise red if (isRemoteConnected) Layer[0]->RenderSceneToEyeBuffer(MainCam, RoomScene, eye, 0, 0, 1,/**/ 1, 0.5f, 1, 0.5f /*green*/); else Layer[0]->RenderSceneToEyeBuffer(MainCam, RoomScene, eye, 0, 0, 1,/**/ 1, 1, 0, 0 /*red*/); } Layer[0]->PrepareLayerHeader(); DistortAndPresent(1); } }
DLL_EXPORT_API void xnOvrGetInputProperties(xnOvrSession* session, xnOvrInputProperties* properties) { ovrInputState state; auto res = ovr_GetInputState(session->Session, ovrControllerType_Touch, &state); if(OVR_SUCCESS(res)) { properties->Valid = true; properties->Buttons = state.Buttons; properties->Touches = state.Touches; properties->HandTriggerLeft = state.HandTrigger[0]; properties->HandTriggerRight = state.HandTrigger[1]; properties->IndexTriggerLeft = state.IndexTrigger[0]; properties->IndexTriggerRight = state.IndexTrigger[1]; properties->ThumbstickLeft[0] = state.Thumbstick[0].x; properties->ThumbstickLeft[1] = state.Thumbstick[0].y; properties->ThumbstickRight[0] = state.Thumbstick[1].x; properties->ThumbstickRight[1] = state.Thumbstick[1].y; } else { properties->Valid = false; } }
/** * Render the Virtual Cinema Theatre. ***/ void* OculusTracker::Provoke(void* pThis, int eD3D, int eD3DInterface, int eD3DMethod, DWORD dwNumberConnected, int& nProvokerIndex) { // update game timer m_cGameTimer.Tick(); static UINT unFrameSkip = 200; if (unFrameSkip > 0) { unFrameSkip--; return nullptr; } // #define _DEBUG_OTR #ifdef _DEBUG_OTR { wchar_t buf[128]; wsprintf(buf, L"[OTR] ifc %u mtd %u", eD3DInterface, eD3DMethod); OutputDebugString(buf); } #endif // save ini file ? if (m_nIniFrameCount) { if (m_nIniFrameCount == 1) SaveIniSettings(); m_nIniFrameCount--; } // main menu update ? if (m_sMenu.bOnChanged) { // set back event bool, set ini file frame count m_sMenu.bOnChanged = false; m_nIniFrameCount = 300; // loop through entries for (size_t nIx = 0; nIx < m_sMenu.asEntries.size(); nIx++) { // entry index changed ? if (m_sMenu.asEntries[nIx].bOnChanged) { m_sMenu.asEntries[nIx].bOnChanged = false; // touch entries ? if (nIx < 25) { // set new vk code by string m_aaunKeys[1][nIx] = GetVkCodeByString(m_sMenu.asEntries[nIx].astrValueEnumeration[m_sMenu.asEntries[nIx].unValue]); } } } } if (m_hSession) { #pragma region controller // controller indices static const uint32_t s_unIndexRemote = 0; static const uint32_t s_unIndexTouch = 1; static const uint32_t s_unIndexXBox = 2; // get all connected input states ovrInputState sInputState[3] = {}; unsigned int unControllersConnected = ovr_GetConnectedControllerTypes(m_hSession); #pragma region Remote if (unControllersConnected & ovrControllerType_Remote) { ovr_GetInputState(m_hSession, ovrControllerType_Remote, &sInputState[s_unIndexRemote]); // handle all remote buttons except Oculus private ones if (sInputState[s_unIndexRemote].Buttons & ovrButton_Up) m_sMenu.bOnUp = true; if (sInputState[s_unIndexRemote].Buttons & ovrButton_Down) m_sMenu.bOnDown = true; if (sInputState[s_unIndexRemote].Buttons & ovrButton_Left) m_sMenu.bOnLeft = true; if (sInputState[s_unIndexRemote].Buttons & ovrButton_Right) m_sMenu.bOnRight = true; if (sInputState[s_unIndexRemote].Buttons & ovrButton_Enter) m_sMenu.bOnAccept = true; if (sInputState[s_unIndexRemote].Buttons & ovrButton_Back) m_sMenu.bOnBack = true; } #pragma endregion #pragma region touch if (unControllersConnected & ovrControllerType_Touch) { // get input state ovr_GetInputState(m_hSession, ovrControllerType_Touch, &sInputState[s_unIndexTouch]); // loop through controller buttons for (UINT unButtonIx = 0; unButtonIx < unButtonNo; unButtonIx++) { // cast keyboard event if (sInputState[s_unIndexTouch].Buttons & aunButtonIds[unButtonIx]) { if (!m_aabKeys[s_unIndexTouch][unButtonIx]) MapButtonDown(s_unIndexTouch, unButtonIx); } else if (m_aabKeys[s_unIndexTouch][unButtonIx]) MapButtonUp(s_unIndexTouch, unButtonIx); } } #pragma endregion if (unControllersConnected & ovrControllerType_XBox) ovr_GetInputState(m_hSession, ovrControllerType_XBox, &sInputState[s_unIndexXBox]); #pragma endregion #pragma region hmd /*// Start the sensor which informs of the Rift's pose and motion .... obsolete for SDK 1.3.x ?? ovr_ConfigureTracking(m_hSession, ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection | ovrTrackingCap_Position, 0);*/ // get the current tracking state ovrTrackingState sTrackingState = ovr_GetTrackingState(m_hSession, ovr_GetTimeInSeconds(), false); if (TRUE)//(sTrackingState.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { // get pose ovrPoseStatef sPoseState = sTrackingState.HeadPose; m_sPose = sPoseState.ThePose; m_sOrientation.x = m_sPose.Orientation.x; m_sOrientation.y = m_sPose.Orientation.y; m_sOrientation.z = m_sPose.Orientation.z; m_sOrientation.w = m_sPose.Orientation.w; // backup old euler angles and velocity float fEulerOld[3]; float fEulerVelocityOld[3]; memcpy(&fEulerOld[0], &m_fEuler[0], sizeof(float)* 3); memcpy(&fEulerVelocityOld[0], &m_fEulerVelocity[0], sizeof(float)* 3); // predicted euler angles ? for Oculus, due to ATW, we do not predict the euler angles if (FALSE) { // get angles m_sOrientation.GetEulerAngles<Axis::Axis_Y, Axis::Axis_X, Axis::Axis_Z, RotateDirection::Rotate_CW, HandedSystem::Handed_R >(&m_fEuler[1], &m_fEuler[0], &m_fEuler[2]); // quick fix here... m_fEuler[1] *= -1.0f; m_fEuler[0] *= -1.0f; m_fEuler[2] *= -1.0f; // get euler velocity + acceleration float fEulerAcceleration[3]; for (UINT unI = 0; unI < 3; unI++) { // get the velocity m_fEulerVelocity[unI] = (m_fEuler[unI] - fEulerOld[unI]) / (float)m_cGameTimer.DeltaTime(); // get the acceleration fEulerAcceleration[unI] = (m_fEulerVelocity[unI] - fEulerVelocityOld[unI]) / (float)m_cGameTimer.DeltaTime(); } // get predicted euler for (UINT unI = 0; unI < 3; unI++) { // compute predicted euler m_fEulerPredicted[unI] = (0.5f * fEulerAcceleration[unI] * ((float)m_cGameTimer.DeltaTime() * (float)m_cGameTimer.DeltaTime())) + (m_fEulerVelocity[unI] * (float)m_cGameTimer.DeltaTime()) + m_fEuler[unI]; } } else { // get angles m_sOrientation.GetEulerAngles<Axis::Axis_Y, Axis::Axis_X, Axis::Axis_Z, RotateDirection::Rotate_CW, HandedSystem::Handed_R >(&m_fEulerPredicted[1], &m_fEulerPredicted[0], &m_fEulerPredicted[2]); // quick fix here... m_fEulerPredicted[1] *= -1.0f; m_fEulerPredicted[0] *= -1.0f; m_fEulerPredicted[2] *= -1.0f; } // set the drawing update to true m_bControlUpdate = true; // set position m_afPosition[0] = (float)-m_sPose.Position.x - m_afPositionOrigin[0]; m_afPosition[1] = (float)-m_sPose.Position.y - m_afPositionOrigin[1]; m_afPosition[2] = (float)m_sPose.Position.z + m_afPositionOrigin[2]; // get eye render pose and other fields ovrEyeRenderDesc asEyeRenderDesc[2]; asEyeRenderDesc[0] = ovr_GetRenderDesc(m_hSession, ovrEye_Left, m_sHMDDesc.DefaultEyeFov[0]); asEyeRenderDesc[1] = ovr_GetRenderDesc(m_hSession, ovrEye_Right, m_sHMDDesc.DefaultEyeFov[1]); ovrPosef asHmdToEyePose[2] = { asEyeRenderDesc[0].HmdToEyePose,asEyeRenderDesc[1].HmdToEyePose }; //ovrVector3f asHmdToEyeViewOffset[2] = { asEyeRenderDesc[0].HmdToEyePose, asEyeRenderDesc[1].HmdToEyePose }; ovrPosef asEyeRenderPose[2]; static long long s_frameIndex = 0; static double s_sensorSampleTime = 0.0; // sensorSampleTime is fed into the layer later ovr_GetEyePoses(m_hSession, s_frameIndex, ovrTrue, asHmdToEyePose, asEyeRenderPose, &s_sensorSampleTime); // ovr_CalcEyePoses(sTrackingState.HeadPose.ThePose, asHmdToEyePose, asEyeRenderPose); // create rotation matrix from euler angles D3DXMATRIX sRotation; D3DXMATRIX sPitch, sYaw, sRoll; D3DXMatrixRotationX(&sPitch, m_fEulerPredicted[0]); D3DXMatrixRotationY(&sYaw, m_fEulerPredicted[1]); D3DXMatrixRotationZ(&sRoll, -m_fEulerPredicted[2]); sRotation = sYaw * sPitch * sRoll; // create per eye view matrix from rotation and position D3DXMATRIX sView[2]; for (UINT unEye = 0; unEye < 2; unEye++) { D3DXMATRIX sTranslation; D3DXMatrixTranslation(&sTranslation, (float)-asEyeRenderPose[unEye].Position.x - m_afPositionOrigin[0], (float)-asEyeRenderPose[unEye].Position.y - m_afPositionOrigin[1], (float)asEyeRenderPose[unEye].Position.z + m_afPositionOrigin[2]); sView[unEye] = sTranslation * sRotation; } // create head pose view matrix D3DXMATRIX sTranslation; D3DXMatrixTranslation(&sTranslation, (float)-sTrackingState.HeadPose.ThePose.Position.x - m_afPositionOrigin[0], (float)-sTrackingState.HeadPose.ThePose.Position.y - m_afPositionOrigin[1], (float)sTrackingState.HeadPose.ThePose.Position.z + m_afPositionOrigin[2]); m_sView = sTranslation * sRotation; // create inverse view matrix D3DXMATRIX sVInv = {}; D3DXMatrixInverse(&sVInv, nullptr, &m_sView); // get projection matrices left/right D3DXMATRIX asToEye[2]; D3DXMATRIX asProjection[2]; for (UINT unEye = 0; unEye < 2; unEye++) { // get ovr projection ovrMatrix4f sProj = ovrMatrix4f_Projection(m_sHMDDesc.DefaultEyeFov[unEye], 0.01f, 30.0f, ovrProjection_LeftHanded); // create dx projection asProjection[unEye] = D3DXMATRIX(&sProj.M[0][0]); D3DXMatrixTranspose(&asProjection[unEye], &asProjection[unEye]); // create eventual projection using inverse matrix of the head pose view matrix m_asProjection[unEye] = sVInv * sView[unEye] * asProjection[unEye]; } } #pragma endregion } else { // Initialize LibOVR, and the Rift... then create hmd handle ovrResult result = ovr_Initialize(nullptr); if (!OVR_SUCCESS(result)) { OutputDebugString(L"[OVR] Failed to initialize libOVR."); return nullptr; } result = ovr_Create(&m_hSession, &m_sLuid); if (!OVR_SUCCESS(result)) { OutputDebugString(L"[OVR] Failed to retreive HMD handle."); return nullptr; } else OutputDebugString(L"[OVR] HMD handle initialized !"); if (m_hSession) { // get the description and set pointers m_sHMDDesc = ovr_GetHmdDesc(m_hSession); // Configure Stereo settings. ovrSizei sRecommenedTex0Size = ovr_GetFovTextureSize(m_hSession, ovrEye_Left, m_sHMDDesc.DefaultEyeFov[0], 1.0f); ovrSizei sRecommenedTex1Size = ovr_GetFovTextureSize(m_hSession, ovrEye_Right, m_sHMDDesc.DefaultEyeFov[1], 1.0f); ovrSizei sTextureSize; sTextureSize.w = max(sRecommenedTex0Size.w, sRecommenedTex1Size.w); sTextureSize.h = max(sRecommenedTex0Size.h, sRecommenedTex1Size.h); m_unRenderTextureWidth = (UINT)sTextureSize.w; m_unRenderTextureHeight = (UINT)sTextureSize.h; // get view offset ovrEyeRenderDesc asEyeRenderDesc[2]; asEyeRenderDesc[0] = ovr_GetRenderDesc(m_hSession, ovrEye_Left, m_sHMDDesc.DefaultEyeFov[0]); asEyeRenderDesc[1] = ovr_GetRenderDesc(m_hSession, ovrEye_Right, m_sHMDDesc.DefaultEyeFov[1]); ovrVector3f asViewOffset[2] = { asEyeRenderDesc[0].HmdToEyePose.Position, asEyeRenderDesc[1].HmdToEyePose.Position }; // get projection matrices left/right D3DXMATRIX asToEye[2]; D3DXMATRIX asProjection[2]; for (UINT unEye = 0; unEye < 2; unEye++) { // get ovr projection ovrMatrix4f sProj = ovrMatrix4f_Projection(m_sHMDDesc.DefaultEyeFov[unEye], 0.01f, 30.0f, ovrProjection_LeftHanded); // create dx projection asProjection[unEye] = D3DXMATRIX(&sProj.M[0][0]); D3DXMatrixTranspose(&asProjection[unEye], &asProjection[unEye]); // create view offset translation matrix D3DXMatrixTranslation(&asToEye[unEye], -asViewOffset[unEye].x, -asViewOffset[unEye].y, -asViewOffset[unEye].z); // create eventual projection m_asProjection[unEye] = asToEye[unEye] * asProjection[unEye]; } } } return nullptr; }
// OVR Remote controller input void HandleRemote() { ovrInputState currentRemoteInputState; ovr_GetInputState(g_session, ovrControllerType_Remote, ¤tRemoteInputState); const unsigned int b = currentRemoteInputState.Buttons; const unsigned int b0 = lastRemoteInputState.Buttons; const int toggleShaderButton = ovrButton_Enter; const int toggleMenuButton = ovrButton_Back; if (b & toggleShaderButton) { if (!(b0 & toggleShaderButton)) { if (g_tweakbarQuad.m_showQuadInWorld == true) { g_tweakbarQuad.MouseClick(1); } else { g_gallery.ToggleShaderWorld(); } } } else if (!(b & toggleShaderButton)) { if (b0 & toggleShaderButton) { // Released button if (g_tweakbarQuad.m_showQuadInWorld == true) { g_tweakbarQuad.MouseClick(0); } else { } } } if (b & toggleMenuButton) { if (!(b0 & toggleMenuButton)) { g_tweakbarQuad.m_showQuadInWorld = !g_tweakbarQuad.m_showQuadInWorld; } } else if (!(b & toggleMenuButton)) { if (b0 & toggleMenuButton) { // Released button } } glm::vec3 remoteMove(0.0f, 0.0f, 0.0f); if (b & ovrButton_Up) { remoteMove += glm::vec3(0.f, 0.f, -1.f); } if (b & ovrButton_Down) { remoteMove += glm::vec3(0.f, 0.f, 1.f); } if (b & ovrButton_Left) { remoteMove += glm::vec3(-1.f, 0.f, 0.f); } if (b & ovrButton_Right) { remoteMove += glm::vec3(1.f, 0.f, 0.f); } m_remoteMove = remoteMove; lastRemoteInputState = currentRemoteInputState; }
void HandleXboxController() { ovrInputState currentXboxControllerInputState; ovr_GetInputState(g_session, ovrControllerType_XBox, ¤tXboxControllerInputState); const unsigned int b = currentXboxControllerInputState.Buttons; const unsigned int b0 = lastXboxControllerInputState.Buttons; const int32_t Abut = ovrButton_A; const int32_t toggleShaderButton = ovrButton_Enter; const int32_t toggleTweakbarButton = ovrButton_Y; const int32_t togglePerfHudButton = ovrButton_Back; const int32_t holdTweakbarButton = ovrButton_RThumb; if (b & toggleShaderButton) { if (!(b0 & toggleShaderButton)) { g_gallery.ToggleShaderWorld(); } } if (b & toggleTweakbarButton) { if (!(b0 & toggleTweakbarButton)) { g_tweakbarQuad.m_showQuadInWorld = !g_tweakbarQuad.m_showQuadInWorld; } } if (b & Abut) { if (!(b0 & Abut)) { g_tweakbarQuad.MouseClick(1); } } else if (!(b & Abut)) { if (b0 & Abut) { g_tweakbarQuad.MouseClick(0); } } if ((b & toggleTweakbarButton) && !(b0 & toggleTweakbarButton)) { g_tweakbarQuad.m_showQuadInWorld = !g_tweakbarQuad.m_showQuadInWorld; } if ((b & togglePerfHudButton) && !(b0 & togglePerfHudButton)) { TogglePerfHud(); } if (b & holdTweakbarButton) { if (!(b0 & holdTweakbarButton)) { g_tweakbarQuad.SetHoldingFlag(m_eyePoses[0], true); } } else if (!(b & holdTweakbarButton)) { if (b0 & holdTweakbarButton) { g_tweakbarQuad.SetHoldingFlag(m_eyePoses[0], false); } } lastXboxControllerInputState = currentXboxControllerInputState; }
void FOculusInput::SendControllerEvents() { const double CurrentTime = FPlatformTime::Seconds(); // @todo: Should be made configurable and unified with other controllers handling of repeat const float InitialButtonRepeatDelay = 0.2f; const float ButtonRepeatDelay = 0.1f; const float AnalogButtonPressThreshold = TriggerThreshold; IOculusRiftPlugin& OculusRiftPlugin = IOculusRiftPlugin::Get(); ovrSession OvrSession = OculusRiftPlugin.GetSession(); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: OvrSession = %p"), OvrSession); if (OvrSession) { ovrInputState OvrInput; ovrTrackingState OvrTrackingState; const ovrResult OvrRes = ovr_GetInputState(OvrSession, ovrControllerType_Touch, &OvrInput); const bool bOvrGCTRes = OculusRiftPlugin.GetCurrentTrackingState(&OvrTrackingState); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ovr_GetInputState() ret = %d, GetCurrentTrackingState ret = %d"), int(OvrRes), int(bOvrGCTRes)); if (OvrRes == ovrSuccess && bOvrGCTRes) { UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ConnectedControllerTypes 0x%X"), OvrInput.ConnectedControllerTypes); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ButtonState = 0x%X"), OvrInput.Buttons); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Touches = 0x%X"), OvrInput.Touches); for (FOculusTouchControllerPair& ControllerPair : ControllerPairs) { for( int32 HandIndex = 0; HandIndex < ARRAY_COUNT( ControllerPair.ControllerStates ); ++HandIndex ) { FOculusTouchControllerState& State = ControllerPair.ControllerStates[ HandIndex ]; const bool bIsLeft = (HandIndex == (int32)EControllerHand::Left); bool bIsCurrentlyTracked = (bIsLeft ? (OvrInput.ConnectedControllerTypes & ovrControllerType_LTouch) != 0 : (OvrInput.ConnectedControllerTypes & ovrControllerType_RTouch) != 0); #if OVR_TESTING bIsCurrentlyTracked = true; static float _angle = 0; OvrTrackingState.HandPoses[HandIndex].ThePose.Orientation = OVR::Quatf(OVR::Vector3f(0, 0, 1), _angle); _angle += 0.1f; OvrTrackingState.HandPoses[HandIndex].ThePose = OvrTrackingState.HeadPose.ThePose; UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Error, TEXT("SendControllerEvents: OVR_TESTING is enabled!")); #endif if (bIsCurrentlyTracked) { State.bIsCurrentlyTracked = true; const float OvrTriggerAxis = OvrInput.IndexTrigger[HandIndex]; const float OvrGripAxis = OvrInput.HandTrigger[HandIndex]; UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: IndexTrigger[%d] = %f"), int(HandIndex), OvrTriggerAxis); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: HandTrigger[%d] = %f"), int(HandIndex), OvrGripAxis); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ThumbStick[%d] = { %f, %f }"), int(HandIndex), OvrInput.Thumbstick[HandIndex].x, OvrInput.Thumbstick[HandIndex].y ); if (OvrTriggerAxis != State.TriggerAxis) { State.TriggerAxis = OvrTriggerAxis; MessageHandler->OnControllerAnalog(bIsLeft ? FGamepadKeyNames::MotionController_Left_TriggerAxis : FGamepadKeyNames::MotionController_Right_TriggerAxis, ControllerPair.UnrealControllerIndex, State.TriggerAxis); } if (OvrGripAxis != State.GripAxis) { State.GripAxis = OvrGripAxis; MessageHandler->OnControllerAnalog(bIsLeft ? FGamepadKeyNames::MotionController_Left_Grip1Axis : FGamepadKeyNames::MotionController_Right_Grip1Axis, ControllerPair.UnrealControllerIndex, State.GripAxis); } if (OvrInput.Thumbstick[HandIndex].x != State.ThumbstickAxes.X) { State.ThumbstickAxes.X = OvrInput.Thumbstick[HandIndex].x; MessageHandler->OnControllerAnalog(bIsLeft ? FGamepadKeyNames::MotionController_Left_Thumbstick_X : FGamepadKeyNames::MotionController_Right_Thumbstick_X, ControllerPair.UnrealControllerIndex, State.ThumbstickAxes.X); } if (OvrInput.Thumbstick[HandIndex].y != State.ThumbstickAxes.Y) { State.ThumbstickAxes.Y = OvrInput.Thumbstick[HandIndex].y; // we need to negate Y value to match XBox controllers MessageHandler->OnControllerAnalog(bIsLeft ? FGamepadKeyNames::MotionController_Left_Thumbstick_Y : FGamepadKeyNames::MotionController_Right_Thumbstick_Y, ControllerPair.UnrealControllerIndex, -State.ThumbstickAxes.Y); } for (int32 ButtonIndex = 0; ButtonIndex < (int32)EOculusTouchControllerButton::TotalButtonCount; ++ButtonIndex) { FOculusButtonState& ButtonState = State.Buttons[ButtonIndex]; check(!ButtonState.Key.IsNone()); // is button's name initialized? // Determine if the button is pressed down bool bButtonPressed = false; switch ((EOculusTouchControllerButton)ButtonIndex) { case EOculusTouchControllerButton::Trigger: bButtonPressed = State.TriggerAxis >= AnalogButtonPressThreshold; break; case EOculusTouchControllerButton::Grip: bButtonPressed = State.GripAxis >= AnalogButtonPressThreshold; break; case EOculusTouchControllerButton::XA: bButtonPressed = bIsLeft ? (OvrInput.Buttons & ovrButton_X) != 0 : (OvrInput.Buttons & ovrButton_A) != 0; break; case EOculusTouchControllerButton::YB: bButtonPressed = bIsLeft ? (OvrInput.Buttons & ovrButton_Y) != 0 : (OvrInput.Buttons & ovrButton_B) != 0; break; case EOculusTouchControllerButton::Thumbstick: bButtonPressed = bIsLeft ? (OvrInput.Buttons & ovrButton_LThumb) != 0 : (OvrInput.Buttons & ovrButton_RThumb) != 0; break; default: check(0); break; } // Update button state if (bButtonPressed != ButtonState.bIsPressed) { const bool bIsRepeat = false; ButtonState.bIsPressed = bButtonPressed; if (ButtonState.bIsPressed) { MessageHandler->OnControllerButtonPressed(ButtonState.Key, ControllerPair.UnrealControllerIndex, bIsRepeat); // Set the timer for the first repeat ButtonState.NextRepeatTime = CurrentTime + ButtonRepeatDelay; } else { MessageHandler->OnControllerButtonReleased(ButtonState.Key, ControllerPair.UnrealControllerIndex, bIsRepeat); } } // Apply key repeat, if its time for that if (ButtonState.bIsPressed && ButtonState.NextRepeatTime <= CurrentTime) { const bool bIsRepeat = true; MessageHandler->OnControllerButtonPressed(ButtonState.Key, ControllerPair.UnrealControllerIndex, bIsRepeat); // Set the timer for the next repeat ButtonState.NextRepeatTime = CurrentTime + ButtonRepeatDelay; } } // Handle Capacitive States for (int32 CapTouchIndex = 0; CapTouchIndex < (int32)EOculusTouchCapacitiveAxes::TotalAxisCount; ++CapTouchIndex) { FOculusTouchCapacitiveState& CapState = State.CapacitiveAxes[CapTouchIndex]; float CurrentAxisVal = 0.f; switch ((EOculusTouchCapacitiveAxes)CapTouchIndex) { case EOculusTouchCapacitiveAxes::XA: { const uint32 mask = (bIsLeft) ? ovrTouch_X : ovrTouch_A; CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f; break; } case EOculusTouchCapacitiveAxes::YB: { const uint32 mask = (bIsLeft) ? ovrTouch_Y : ovrTouch_B; CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f; break; } case EOculusTouchCapacitiveAxes::Thumbstick: { const uint32 mask = (bIsLeft) ? ovrTouch_LThumb : ovrTouch_RThumb; CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f; break; } case EOculusTouchCapacitiveAxes::Trigger: { const uint32 mask = (bIsLeft) ? ovrTouch_LIndexTrigger : ovrTouch_RIndexTrigger; CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f; break; } case EOculusTouchCapacitiveAxes::IndexPointing: { const uint32 mask = (bIsLeft) ? ovrTouch_LIndexPointing : ovrTouch_RIndexPointing; CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f; break; } case EOculusTouchCapacitiveAxes::ThumbUp: { const uint32 mask = (bIsLeft) ? ovrTouch_LThumbUp : ovrTouch_RThumbUp; CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f; break; } default: check(0); } if (CurrentAxisVal != CapState.State) { MessageHandler->OnControllerAnalog(CapState.Axis, ControllerPair.UnrealControllerIndex, CurrentAxisVal); CapState.State = CurrentAxisVal; } } const ovrPosef& OvrHandPose = OvrTrackingState.HandPoses[HandIndex].ThePose; FVector NewLocation; FQuat NewOrientation; if (OculusRiftPlugin.PoseToOrientationAndPosition(OvrHandPose, /* Out */ NewOrientation, /* Out */ NewLocation)) { // OK, we have up to date positional data! State.Orientation = NewOrientation; State.Location = NewLocation; UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: HandPOSE[%d]: Pos %.3f %.3f %.3f"), HandIndex, NewLocation.X, NewLocation.Y, NewLocation.Y); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: HandPOSE[%d]: Yaw %.3f Pitch %.3f Roll %.3f"), HandIndex, NewOrientation.Rotator().Yaw, NewOrientation.Rotator().Pitch, NewOrientation.Rotator().Roll); } else { // HMD wasn't ready. This can currently happen if we try to grab motion data before we've rendered at least one frame UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: PoseToOrientationAndPosition returned false")); } } else { // Controller isn't available right now. Zero out input state, so that if it comes back it will send fresh event deltas State = FOculusTouchControllerState((EControllerHand)HandIndex); UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Controller for the hand %d is not tracked"), int(HandIndex)); } } } } } UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("")); }