public void Start () { // Try to find RUISTracker that uses Razer Hydra in some way RUISTracker[] trackers = Object.FindObjectsOfType(typeof(RUISTracker)) as RUISTracker[]; for(int i = 0; i < trackers.Length; ++i) { // Below complicated clauses make sure that this is a properly configured Razer Hydra tracker if( trackers[i].headPositionInput == RUISTracker.HeadPositionSource.RazerHydra || ( trackers[i].headRotationInput == RUISTracker.HeadRotationSource.RazerHydra && !trackers[i].useOculusRiftRotation) || ( trackers[i].compass == RUISTracker.CompassSource.RazerHydra && trackers[i].externalDriftCorrection && ( trackers[i].useOculusRiftRotation || trackers[i].headRotationInput == RUISTracker.HeadRotationSource.InputTransform ))) if(trackers[i].isRazerBaseMobile) // Found a Razer Hydra tracker that claims to have mobile base headTracker = trackers[i]; } }
public void Start() { // Try to find RUISTracker that uses Razer Hydra in some way RUISTracker[] trackers = Object.FindObjectsOfType(typeof(RUISTracker)) as RUISTracker[]; for (int i = 0; i < trackers.Length; ++i) { // Below complicated clauses make sure that this is a properly configured Razer Hydra tracker if (trackers[i].headPositionInput == RUISTracker.HeadPositionSource.RazerHydra || (trackers[i].headRotationInput == RUISTracker.HeadRotationSource.RazerHydra && !trackers[i].useOculusRiftRotation) || (trackers[i].compass == RUISTracker.CompassSource.RazerHydra && trackers[i].externalDriftCorrection && (trackers[i].useOculusRiftRotation || trackers[i].headRotationInput == RUISTracker.HeadRotationSource.InputTransform))) { if (trackers[i].isRazerBaseMobile) // Found a Razer Hydra tracker that claims to have mobile base { headTracker = trackers[i]; } } } }
void Awake() { if (!scriptEnabled) { return; } inputManager = FindObjectOfType(typeof(RUISInputManager)) as RUISInputManager; bool kinect2 = false; bool kinect = false; bool psmove = false; bool razer = false; bool oculusDK2 = false; bool isRiftConnected = false; //#if UNITY_EDITOR //if(UnityEditorInternal.InternalEditorUtility.HasPro()) //#endif { try { // Find out if an Oculus HMD is connected if (OVRManager.display != null) { isRiftConnected = OVRManager.display.isPresent; } // Find out the Oculus HMD version if (OVRManager.capiHmd != null) { ovrHmdVersion = OVRManager.capiHmd.GetDesc().Type; } } catch (UnityException e) { Debug.LogError(e); } } if (inputManager) { if (isRiftConnected && (ovrHmdVersion == Ovr.HmdType.DK2 || ovrHmdVersion == Ovr.HmdType.Other)) { oculusDK2 = true; } kinect2 = inputManager.enableKinect2; kinect = inputManager.enableKinect; psmove = inputManager.enablePSMove; razer = inputManager.enableRazerHydra; int trackerCount = 0; RUISTracker closestMatch = null; int currentMatchScore = 0; RUISHeadTrackerAssigner[] assigners = FindObjectsOfType(typeof(RUISHeadTrackerAssigner)) as RUISHeadTrackerAssigner[]; if (!allowMultipleAssigners && assigners.Length > 1) { Debug.LogError("Multiple active RUISHeadTrackerAssigner scripts found while 'Allow Multiple Assigners' is false: " + "Disabling all headtrackers and their child objects that are listed in the RUISHeadTrackerAssigner " + "component of '" + gameObject.name + "' object."); for (int i = 0; i < headTrackers.Capacity; ++i) { if (headTrackers[i] && headTrackers[i].gameObject.activeInHierarchy) { headTrackers[i].gameObject.SetActive(false); } } return; } foreach (RUISTracker trackerScript in headTrackers) { if (trackerScript && trackerScript.gameObject.activeInHierarchy) { ++trackerCount; int foundTrackerScore = 0; // Give score to found head trackers if (oculusDK2 && trackerScript.headPositionInput == RUISTracker.HeadPositionSource.OculusDK2) { foundTrackerScore = 7; print(trackerScript); } else if (psmove && trackerScript.headPositionInput == RUISTracker.HeadPositionSource.PSMove) { foundTrackerScore = 6; } else if (razer && trackerScript.isRazerBaseMobile && // Legacy: Mobile Hydra Base (custom tracker) trackerScript.headPositionInput == RUISTracker.HeadPositionSource.RazerHydra && trackerScript.mobileRazerBase == RUISTracker.RazerHydraBase.InputTransform) { foundTrackerScore = 5; } else if (kinect2 && trackerScript.headPositionInput == RUISTracker.HeadPositionSource.Kinect2) { foundTrackerScore = 4; } else if (kinect && razer && trackerScript.isRazerBaseMobile && // Legacy: Mobile Hydra Base (Kinect) trackerScript.headPositionInput == RUISTracker.HeadPositionSource.RazerHydra && trackerScript.mobileRazerBase == RUISTracker.RazerHydraBase.Kinect1) { foundTrackerScore = 3; } else if (kinect && trackerScript.headPositionInput == RUISTracker.HeadPositionSource.Kinect1) { foundTrackerScore = 2; } else if (razer && trackerScript.headPositionInput == RUISTracker.HeadPositionSource.RazerHydra && // Plain ol' Razer Hydra !trackerScript.isRazerBaseMobile) { foundTrackerScore = 1; } // Assign new best head tracker candidate if it is better than the previously found if (currentMatchScore < foundTrackerScore) { closestMatch = trackerScript; currentMatchScore = foundTrackerScore; } } } if (trackerCount == 0 && Application.isEditor) { Debug.LogError("No active GameObjects with RUISTracker script found from headTrackers list!"); } string positionTracker = "<None>"; string logString = ""; string names = ""; RUISCamera ruisCamera = null; if (closestMatch == null) { // Disable all but the first active head tracker from the headTrackers list logString = "Could not find a suitable head tracker with regard to " + "enabled devices in RUISInputManager!"; bool disabling = false; int leftEnabledIndex = -1; for (int i = 0; i < headTrackers.Capacity; ++i) { if (headTrackers[i] && headTrackers[i].gameObject.activeInHierarchy) { if (disabling) { if (names.Length > 0) { names = names + ", "; } names = names + headTrackers[i].gameObject.name; headTrackers[i].gameObject.SetActive(false); } else { leftEnabledIndex = i; closestMatch = headTrackers[leftEnabledIndex]; positionTracker = headTrackers[leftEnabledIndex].gameObject.name; disabling = true; } } } if (leftEnabledIndex >= 0) { logString = logString + " Choosing the first head tracker in the list. Using " + positionTracker + " for tracking head position"; if (names.Length > 0) { logString = logString + ", and disabling the following: " + names; } logString = logString + ". This choice was made using a pre-selected list of " + "head trackers."; ruisCamera = headTrackers[leftEnabledIndex].gameObject.GetComponentInChildren <RUISCamera>(); } Debug.LogError(logString); } else { // Disable all but the closest match head tracker from the headTrackers list for (int i = 0; i < headTrackers.Capacity; ++i) { if (headTrackers[i] && headTrackers[i].gameObject.activeInHierarchy) { if (headTrackers[i] != closestMatch) { if (names.Length > 0) { names = names + ", "; } names = names + headTrackers[i].gameObject.name; headTrackers[i].gameObject.SetActive(false); } else { positionTracker = headTrackers[i].gameObject.name; } } } logString = "Found the best head tracker with regard to enabled devices in " + "RUISInputManager! Using " + positionTracker + " for tracking head position"; if (names.Length > 0) { logString = logString + ", and disabling the following: " + names; } Debug.Log(logString + ". This choice was made using a pre-selected list of head trackers."); ruisCamera = closestMatch.gameObject.GetComponentInChildren <RUISCamera>(); if (changePivotIfNoKinect && psmove && !kinect && !kinect2 && closestMatch.headPositionInput == RUISTracker.HeadPositionSource.PSMove) { RUISCharacterController characterController = gameObject.GetComponentInChildren <RUISCharacterController>(); if (characterController != null && characterController.characterPivotType != RUISCharacterController.CharacterPivotType.MoveController) { characterController.characterPivotType = RUISCharacterController.CharacterPivotType.MoveController; characterController.moveControllerId = closestMatch.positionPSMoveID; Debug.Log("PS Move enabled and Kinect disabled. Setting " + characterController.name + "'s CharacterCamera Pivot as PS Move controller #" + closestMatch.positionPSMoveID + ". PS Move position offset for this pivot is " + characterController.psmoveOffset); } } } if (ruisCamera) { if (display == null) { Debug.LogWarning("No RUISDisplay attached to the RUISHeadTrackerAssigner script!"); RUISDisplay[] displays = FindObjectsOfType(typeof(RUISDisplay)) as RUISDisplay[]; for (int i = 0; i < displays.Length; ++i) { if (displays[i].linkedCamera == null) { Debug.LogWarning("Assigned RUISCamera component from the child of " + positionTracker + " to render on " + displays[i].gameObject.name + " because that " + "RUISDisplay component's RUISCamera field was empty."); displays[i].linkedCamera = ruisCamera; break; } } } else { if (display.linkedCamera == null) { Debug.Log("Assigned RUISCamera component from the child of " + positionTracker + " to render on " + display.gameObject.name); display.linkedCamera = ruisCamera; } else { Debug.LogWarning("RUISDisplay " + display.gameObject.name + " is already connected with a " + "RUISCamera object! Leave the RUISCamera field empty in your RUISDisplay " + "component if you want RUISHeadTrackerAssigner script to automatically " + "assign a RUISCamera to your RUISDisplay."); } } } else { if (closestMatch) { Debug.LogError(positionTracker + " did not have a child with RUISCamera component, " + "and therefore it is not used to draw on any of the displays in " + "DisplayManager."); } } // If we are using Razer with a static base for head tracking, then apply onlyRazerOffset // on the parent objects of the Razer head tracker and the hand-held Razer if (closestMatch != null && razer && closestMatch.headPositionInput == RUISTracker.HeadPositionSource.RazerHydra && !closestMatch.isRazerBaseMobile) { // The parent object of the Razer head tracker must not have RUISCharacterConroller, // because that script will modify the object's position if (closestMatch.transform.parent != null && closestMatch.transform.parent.GetComponent <RUISCharacterController>() == null && (onlyRazerOffset.x != 0 || onlyRazerOffset.y != 0 || onlyRazerOffset.z != 0)) { string razerWandOffsetInfo = ""; closestMatch.transform.parent.localPosition += onlyRazerOffset; if (razerWandParent != null) { razerWandParent.localPosition += onlyRazerOffset; razerWandOffsetInfo = " and " + razerWandParent.gameObject.name + " (parent of hand-held Razer " + "Hydra)"; } Debug.Log("Applying offset of " + onlyRazerOffset + " to " + closestMatch.transform.parent.gameObject.name + " (parent of Razer Hydra head tracker)" + razerWandOffsetInfo + "."); } } // If no Razer, Kinect, or PS Move is available, then apply onlyMouseOffset // on the parent object of the head tracker that is left enabled // if( closestMatch != null && !razer && !kinect && !psmove) // { // // The parent object of the Razer head tracker must not have RUISCharacterConroller, // // because that script will modify the object's position // if( closestMatch.transform.parent != null // && closestMatch.transform.parent.GetComponent<RUISCharacterController>() == null // && (onlyMouseOffset.x != 0 || onlyMouseOffset.y != 0 || onlyMouseOffset.z != 0) ) // { // closestMatch.transform.parent.localPosition += onlyMouseOffset; // Debug.Log( "Applying offset of " + onlyMouseOffset + " to " // + closestMatch.transform.parent.gameObject.name + " (parent of assigned head tracker)."); // } // } // *** TODO: Below is slightly hacky // Read inputConfig.xml to see if Kinect yaw drift correction for Oculus Rift should be enabled if (closestMatch != null && closestMatch.useOculusRiftRotation && applyKinectDriftCorrectionPreference) { if (inputManager.kinectDriftCorrectionPreferred) { // Preference is to use Kinect for drift correction (if PS Move is not used for head tracking) switch (closestMatch.headPositionInput) { case RUISTracker.HeadPositionSource.Kinect1: if (!psmove && kinect) { closestMatch.externalDriftCorrection = true; closestMatch.compass = RUISTracker.CompassSource.Kinect1; } break; case RUISTracker.HeadPositionSource.RazerHydra: if (!psmove && kinect && razer) { if (closestMatch.isRazerBaseMobile) { closestMatch.externalDriftCorrection = true; closestMatch.compass = RUISTracker.CompassSource.Kinect1; } } break; } } else { // Preference is NOT to use Kinect for drift correction if (closestMatch.headPositionInput == RUISTracker.HeadPositionSource.Kinect1 && !psmove && kinect) { closestMatch.externalDriftCorrection = false; } } } } }
public override void OnInspectorGUI() { serializedObject.Update(); EditorGUILayout.PropertyField(defaultPosition, new GUIContent("Default Position (meters)", "Head position before tracking starts")); //EditorGUILayout.PropertyField(skeletonManager, new GUIContent("skeletonManager", "Can be None")); if(serializedObject.targetObject is RUISTracker) { trackerScript = (RUISTracker) serializedObject.targetObject; if(trackerScript) ovrCameraRig = trackerScript.gameObject.GetComponentInChildren<OVRCameraRig>(); if(ovrCameraRig) { riftFound = true; } else { riftFound = false; } } if(!riftFound) { EditorGUILayout.PropertyField(pickRotationSource, new GUIContent( "Pick Rotation Source", "If disabled, then the Rotation " + "Tracker is same as Position Tracker")); } EditorGUILayout.Space(); EditorGUILayout.PropertyField(headPositionInput, new GUIContent("Position Tracker", "Device that tracks the head position")); EditorGUI.indentLevel += 2; switch (headPositionInput.enumValueIndex) { case (int)RUISTracker.HeadPositionSource.OculusDK2: EditorGUILayout.PropertyField(positionOffsetOculus, new GUIContent("Position Offset (meters)", "Adds an position offset to Oculus Rift's " + "tracked position. This should be zero when using Oculus Rift positional " + "tracking together with Kinect skeleton tracking.")); break; case (int)RUISTracker.HeadPositionSource.Kinect1: case (int)RUISTracker.HeadPositionSource.Kinect2: positionPlayerID.intValue = Mathf.Clamp(positionPlayerID.intValue, 0, maxKinectSkeletons - 1); if(positionNoiseCovarianceKinect.floatValue < minNoiseCovariance) positionNoiseCovarianceKinect.floatValue = minNoiseCovariance; EditorGUILayout.PropertyField(positionPlayerID, new GUIContent("Kinect Player Id", "Between 0 and 3")); EditorGUILayout.PropertyField(positionJoint, new GUIContent("Joint", "Head is the best joint for tracking head position")); EditorGUILayout.PropertyField(positionOffsetKinect, new GUIContent("Position Offset (meters)", "Kinect joint's position in " + "the tracked object's local coordinate system. Set these values " + "according to the joint's offset from the tracked object's " + "origin (head etc.). When using Kinect for head tracking, then zero " + "vector is the best choice if head is the position Joint.")); EditorGUILayout.PropertyField(filterPositionKinect, new GUIContent("Filter Position", "Enables simple Kalman filtering for position " + "tracking. Recommended for Kinect.")); if(filterPositionKinect.boolValue) EditorGUILayout.PropertyField(positionNoiseCovarianceKinect, new GUIContent("Filter Strength", "Noise covariance of Kalman filtering: " + "a bigger value means smoother results but a slower " + "response to changes.")); break; case (int)RUISTracker.HeadPositionSource.PSMove: positionPSMoveID.intValue = Mathf.Clamp(positionPSMoveID.intValue, 0, maxPSMoveControllers - 1); if(positionNoiseCovariancePSMove.floatValue < minNoiseCovariance) positionNoiseCovariancePSMove.floatValue = minNoiseCovariance; EditorGUILayout.PropertyField(positionPSMoveID, new GUIContent("PS Move ID", "Between 0 and 3")); EditorGUILayout.PropertyField(positionOffsetPSMove, new GUIContent("Position Offset (meters)", "PS Move controller's position in " + "the tracked object's local coordinate system. Set these values " + "according to the controller's offset from the tracked object's " + "origin (head etc.).")); EditorGUILayout.PropertyField(filterPositionPSMove, new GUIContent("Filter Position", "Enables simple Kalman filtering for position " + "tracking. Best left disabled for PS Move.")); if(filterPositionPSMove.boolValue) EditorGUILayout.PropertyField(positionNoiseCovariancePSMove, new GUIContent("Filter Strength", "Noise covariance of Kalman filtering: " + "a bigger value means smoother results but a slower " + "response to changes.")); break; case (int)RUISTracker.HeadPositionSource.RazerHydra: if(positionNoiseCovarianceHydra.floatValue < minNoiseCovariance) positionNoiseCovarianceHydra.floatValue = minNoiseCovariance; EditorGUILayout.PropertyField(isRazerBaseMobile, new GUIContent("Moving Base Station", "Enable this if the Razer Hydra base station is " + "attached to something that is moving (e.g. Kinect tracked player's belt)")); EditorGUILayout.PropertyField(positionRazerID, new GUIContent("Razer Hydra ID", "Either LEFT or RIGHT")); EditorGUILayout.PropertyField(positionOffsetHydra, new GUIContent("Position Offset (meters)", "Razer Hydra controller's position in " + "the tracked object's local coordinate system. Set these values " + "according to the controller's offset from the tracked object's " + "origin (head etc.).")); EditorGUILayout.PropertyField(filterPositionHydra, new GUIContent("Filter Position", "Enables simple Kalman filtering for position " + "tracking. Best left disabled for Razer Hydra.")); if(filterPositionHydra.boolValue) EditorGUILayout.PropertyField(positionNoiseCovarianceHydra, new GUIContent("Filter Strength", "Noise covariance of Kalman filtering: " + "a bigger value means smoother results but a slower " + "response to changes.")); break; case (int)RUISTracker.HeadPositionSource.InputTransform: if(positionNoiseCovarianceTransform.floatValue < minNoiseCovariance) positionNoiseCovarianceTransform.floatValue = minNoiseCovariance; EditorGUILayout.PropertyField(positionInput, new GUIContent("Input Transform", "All other position trackers are supported " + "through this transform. Drag and drop here a transform " + "whose position is controlled by a tracking device.")); EditorGUILayout.PropertyField(filterPositionTransform, new GUIContent("Filter Position", "Enables simple Kalman filtering for position " + "tracking.")); if(filterPositionTransform.boolValue) EditorGUILayout.PropertyField(positionNoiseCovarianceTransform, new GUIContent("Filter Strength", "Noise covariance of Kalman filtering: " + "a bigger value means smoother results but a slower " + "response to changes.")); break; } // if(headPositionInput.enumValueIndex != (int)RUISTracker.HeadPositionSource.None) // { // EditorGUILayout.PropertyField(filterPosition, new GUIContent("Filter Position", "Enables simple Kalman filtering for position " // + "tracking. Only recommended for Kinect.")); // EditorGUILayout.PropertyField(positionNoiseCovariance, new GUIContent("Filter Strength", "Noise covariance of Kalman filtering: " // + "a bigger value means smoother results but a slower " // + "response to changes.")); // } EditorGUI.indentLevel -= 2; EditorGUILayout.Space(); if(riftFound) { EditorGUILayout.LabelField("Rotation Tracker: Oculus Rift", EditorStyles.boldLabel); EditorGUI.indentLevel += 2; EditorGUILayout.PropertyField(oculusID, new GUIContent("Oculus Rift ID", "Choose which Rift is the source of the head tracking. " + "Leave this to 0 (multiple Rifts are not supported yet).")); EditorStyles.textField.wordWrap = true; EditorGUILayout.TextArea(typeof(OVRCameraRig) + " script detected in a child object of this " + trackerScript.gameObject.name + ". Assuming that you want to use rotation from Oculus Rift. Disabling other Rotation Tracker " + "options. You can access other rotation trackers when you remove or disable the child object " + "that has the " + typeof(OVRCameraRig) + " component.", GUILayout.Height(120)); EditorGUILayout.LabelField( new GUIContent("Reset Orientation Button(s):", "The button(s) that reset Oculus Rift's yaw " + "rotation to zero."), EditorStyles.boldLabel); EditorGUI.indentLevel += 1; EditorGUILayout.PropertyField(resetKey, new GUIContent("KeyCode", "The button that resets Oculus Rift's yaw rotation to zero.")); if(externalDriftCorrection.boolValue && compass.enumValueIndex == (int)RUISTracker.CompassSource.RazerHydra) EditorGUILayout.LabelField(new GUIContent(("BUMPER+START Razer Hydra " + compassRazerID.enumNames[compassRazerID.enumValueIndex]), "BUMPER and START of the Razer Hydra controller that you use for Yaw Drift Correction."), EditorStyles.label); else if(headPositionInput.enumValueIndex == (int)RUISTracker.HeadPositionSource.RazerHydra) EditorGUILayout.LabelField(new GUIContent(("BUMPER+START Razer Hydra " + positionRazerID.enumNames[positionRazerID.enumValueIndex]), "BUMPER and START of the Razer Hydra controller that you use for position tracking."), EditorStyles.label); if(externalDriftCorrection.boolValue && compass.enumValueIndex == (int)RUISTracker.CompassSource.PSMove) EditorGUILayout.LabelField(new GUIContent(("MOVE button on PS Move #" + compassPSMoveID.intValue), "MOVE button of the PS Move controller that you use for Yaw Drift Correction."), EditorStyles.label); else if(headPositionInput.enumValueIndex == (int)RUISTracker.HeadPositionSource.PSMove) EditorGUILayout.LabelField(new GUIContent(("MOVE button on PS Move #" + positionPSMoveID.intValue), "MOVE button of the PS Move controller that you use for position tracking."), EditorStyles.label); EditorGUI.indentLevel -= 1; } else { if(!pickRotationSource.boolValue) { switch (headPositionInput.enumValueIndex) { case (int)RUISTracker.HeadPositionSource.Kinect1: { headRotationInput.enumValueIndex = (int)RUISTracker.HeadRotationSource.Kinect1; rotationPlayerID.intValue = positionPlayerID.intValue; rotationJoint.enumValueIndex = positionJoint.enumValueIndex; break; } case (int)RUISTracker.HeadPositionSource.Kinect2: { headRotationInput.enumValueIndex = (int)RUISTracker.HeadRotationSource.Kinect2; rotationPlayerID.intValue = positionPlayerID.intValue; rotationJoint.enumValueIndex = positionJoint.enumValueIndex; break; } case (int)RUISTracker.HeadPositionSource.PSMove: { headRotationInput.enumValueIndex = (int)RUISTracker.HeadRotationSource.PSMove; rotationPSMoveID.intValue = positionPSMoveID.intValue; break; } case (int)RUISTracker.HeadPositionSource.RazerHydra: { headRotationInput.enumValueIndex = (int)RUISTracker.HeadRotationSource.RazerHydra; rotationRazerID.intValue = positionRazerID.intValue; break; } case (int)RUISTracker.HeadPositionSource.InputTransform: { headRotationInput.enumValueIndex = (int)RUISTracker.HeadRotationSource.InputTransform; rotationInput.objectReferenceValue = positionInput.objectReferenceValue; break; } case (int)RUISTracker.HeadPositionSource.None: { headRotationInput.enumValueIndex = (int)RUISTracker.HeadRotationSource.None; break; } } } EditorGUI.BeginDisabledGroup(!pickRotationSource.boolValue); EditorGUILayout.PropertyField(headRotationInput, new GUIContent("Rotation Tracker", "Device that tracks the head rotation")); EditorGUI.EndDisabledGroup(); EditorGUI.indentLevel += 2; switch (headRotationInput.enumValueIndex) { case (int)RUISTracker.HeadRotationSource.Kinect1: case (int)RUISTracker.HeadRotationSource.Kinect2: rotationPlayerID.intValue = Mathf.Clamp(rotationPlayerID.intValue, 0, maxKinectSkeletons - 1); if(rotationNoiseCovarianceKinect.floatValue < minNoiseCovariance) rotationNoiseCovarianceKinect.floatValue = minNoiseCovariance; EditorGUI.BeginDisabledGroup(!pickRotationSource.boolValue); EditorGUILayout.PropertyField(rotationPlayerID, new GUIContent("Kinect Player ID", "Between 0 and 3")); EditorGUILayout.PropertyField(rotationJoint, new GUIContent("Joint", "ATTENTION: Torso has most stable joint rotation " + "for head tracking! Currently OpenNI's head joint rotation " + "is always the same as torso rotation, except its tracking " + "fails more often.")); EditorGUI.EndDisabledGroup(); EditorGUILayout.PropertyField(rotationOffsetKinect, new GUIContent("Rotation Offset", "Tracked joint's rotation in tracked " + "object's local coordinate system. If using Kinect for head " + "tracking, then zero vector is usually the best choice if " + "torso or head is the Rotation Joint.")); EditorGUILayout.PropertyField(filterRotationKinect, new GUIContent("Filter Rotation", "Enables simple Kalman filtering for rotation " + "tracking. Recommended for Kinect.")); if(filterRotationKinect.boolValue) EditorGUILayout.PropertyField(rotationNoiseCovarianceKinect, new GUIContent("Filter Strength", "Noise covariance of Kalman filtering: " + "a bigger value means smoother results but a slower " + "response to changes.")); break; case (int)RUISTracker.HeadRotationSource.PSMove: rotationPSMoveID.intValue = Mathf.Clamp(rotationPSMoveID.intValue, 0, maxPSMoveControllers - 1); if(rotationNoiseCovariancePSMove.floatValue < minNoiseCovariance) rotationNoiseCovariancePSMove.floatValue = minNoiseCovariance; EditorGUI.BeginDisabledGroup(!pickRotationSource.boolValue); EditorGUILayout.PropertyField(rotationPSMoveID, new GUIContent("PS Move ID", "Between 0 and 3")); EditorGUI.EndDisabledGroup(); EditorGUILayout.PropertyField(rotationOffsetPSMove, new GUIContent("Rotation Offset", "Tracked PS Move controller's " + "rotation in tracked object's local coordinate system. " + "Set these euler angles according to the orientation in " + "which Move is attached to the tracked object (head etc.).")); EditorGUILayout.PropertyField(filterRotationPSMove, new GUIContent("Filter Rotation", "Enables simple Kalman filtering for rotation " + "tracking. Best left disabled for PS Move.")); if(filterRotationPSMove.boolValue) EditorGUILayout.PropertyField(rotationNoiseCovariancePSMove, new GUIContent("Filter Strength", "Noise covariance of Kalman filtering: " + "a bigger value means smoother results but a slower " + "response to changes.")); break; case (int)RUISTracker.HeadRotationSource.RazerHydra: if(rotationNoiseCovarianceHydra.floatValue < minNoiseCovariance) rotationNoiseCovarianceHydra.floatValue = minNoiseCovariance; EditorGUI.BeginDisabledGroup(!pickRotationSource.boolValue); EditorGUILayout.PropertyField(isRazerBaseMobile, new GUIContent("Moving Base Station", "Enable this if the Razer Hydra base station is " + "attached to something that is moving (e.g. Kinect tracked player's " + "belt)")); EditorGUILayout.PropertyField(rotationRazerID, new GUIContent("Razer Hydra ID", "Either LEFT or RIGHT")); EditorGUI.EndDisabledGroup(); EditorGUILayout.PropertyField(rotationOffsetHydra, new GUIContent("Rotation Offset", "Tracked Razer Hydra controller's " + "rotation in tracked object's local coordinate system. " + "Set these euler angles according to the orientation in which " + "the Razer Hydra is attached to the tracked object (head etc.).")); EditorGUILayout.PropertyField(filterRotationHydra, new GUIContent("Filter Rotation", "Enables simple Kalman filtering for rotation " + "tracking. Best left disabled for Razer Hydra.")); if(filterRotationHydra.boolValue) EditorGUILayout.PropertyField(rotationNoiseCovarianceHydra, new GUIContent("Filter Strength", "Noise covariance of Kalman filtering: " + "a bigger value means smoother results but a slower " + "response to changes.")); break; case (int)RUISTracker.HeadRotationSource.InputTransform: if(rotationNoiseCovarianceTransform.floatValue < minNoiseCovariance) rotationNoiseCovarianceTransform.floatValue = minNoiseCovariance; EditorGUI.BeginDisabledGroup(!pickRotationSource.boolValue); EditorGUILayout.PropertyField(rotationInput, new GUIContent("Input Transform", "All other rotation trackers are supported " + "through this transform. Drag and drop here a transform " + "whose rotation is controlled by a tracking device.")); EditorGUI.EndDisabledGroup(); EditorGUILayout.PropertyField(filterRotationTransform, new GUIContent("Filter Rotation", "Enables simple Kalman filtering " + "for rotation tracking.")); if(filterRotationTransform.boolValue) EditorGUILayout.PropertyField(rotationNoiseCovarianceTransform, new GUIContent("Filter Strength", "Noise covariance of Kalman " + "filtering: a bigger value means smoother results but a slower " + "response to changes.")); break; } // if(headRotationInput.enumValueIndex != (int)RUISTracker.HeadRotationSource.None) // { // EditorGUILayout.PropertyField(filterRotation, new GUIContent("Filter Rotation", "Enables simple Kalman filtering for rotation " // + "tracking. Only recommended for Kinect.")); // EditorGUILayout.PropertyField(rotationNoiseCovariance, new GUIContent("Filter Strength", "Noise covariance of Kalman filtering: " // + "a bigger value means smoother results but a slower " // + "response to changes.")); // } } EditorGUI.indentLevel -= 2; EditorGUILayout.Space(); if(!riftFound && headRotationInput.enumValueIndex != (int)RUISTracker.HeadRotationSource.InputTransform) { EditorGUI.BeginDisabledGroup(true); EditorGUILayout.PropertyField(externalDriftCorrection, new GUIContent("Yaw Drift Correction", "Enables external yaw drift correction " + "using Kinect, PS Move, or some other device")); if( headRotationInput.enumValueIndex == (int)RUISTracker.HeadRotationSource.Kinect1 || headRotationInput.enumValueIndex == (int)RUISTracker.HeadRotationSource.Kinect2) EditorGUILayout.LabelField("Kinect joints don't need drift correction"); if(headRotationInput.enumValueIndex == (int)RUISTracker.HeadRotationSource.PSMove) EditorGUILayout.LabelField("PS Move doesn't need drift correction"); if(headRotationInput.enumValueIndex == (int)RUISTracker.HeadRotationSource.RazerHydra) EditorGUILayout.LabelField("Razer Hydra doesn't need drift correction"); if(headRotationInput.enumValueIndex == (int)RUISTracker.HeadRotationSource.None) EditorGUILayout.LabelField("No Rotation Tracker: Drift correction disabled"); EditorGUI.EndDisabledGroup(); } else { EditorGUILayout.PropertyField(externalDriftCorrection, new GUIContent("Yaw Drift Correction", "Enables external yaw drift correction " + "using Kinect, PS Move, or some other device")); if(externalDriftCorrection.boolValue) { EditorGUI.indentLevel += 2; EditorGUILayout.PropertyField(compassIsPositionTracker, new GUIContent("Use Position Tracker", "If enabled, rotation from the " + "above Position Tracker will act as a compass that " + "corrects yaw drift of the Rotation Tracker")); if(compassIsPositionTracker.boolValue) { switch(headPositionInput.enumValueIndex) { case (int)RUISTracker.HeadPositionSource.Kinect1: { compass.enumValueIndex = (int)RUISTracker.CompassSource.Kinect1; compassPlayerID.intValue = positionPlayerID.intValue; compassJoint.enumValueIndex = positionJoint.enumValueIndex; break; } case (int)RUISTracker.HeadPositionSource.Kinect2: { compass.enumValueIndex = (int)RUISTracker.CompassSource.Kinect2; compassPlayerID.intValue = positionPlayerID.intValue; compassJoint.enumValueIndex = positionJoint.enumValueIndex; break; } case (int)RUISTracker.HeadPositionSource.PSMove: { compass.enumValueIndex = (int)RUISTracker.CompassSource.PSMove; compassPSMoveID.intValue = positionPSMoveID.intValue; break; } case (int)RUISTracker.HeadPositionSource.RazerHydra: { compass.enumValueIndex = (int)RUISTracker.CompassSource.RazerHydra; compassRazerID.enumValueIndex = positionRazerID.enumValueIndex; break; } case (int)RUISTracker.HeadPositionSource.InputTransform: { compass.enumValueIndex = (int)RUISTracker.CompassSource.InputTransform; compassTransform.objectReferenceValue = positionInput.objectReferenceValue; break; } case (int)RUISTracker.HeadPositionSource.None: { compass.enumValueIndex = (int)RUISTracker.CompassSource.None; break; } } } EditorGUI.BeginDisabledGroup(compassIsPositionTracker.boolValue); EditorGUILayout.PropertyField(compass, new GUIContent("Compass Tracker", "Tracker that will be used to correct the yaw drift of " + "Rotation Tracker")); EditorGUI.EndDisabledGroup(); if(compassIsPositionTracker.boolValue && headPositionInput.enumValueIndex == (int)RUISTracker.HeadPositionSource.None) EditorGUILayout.LabelField("Position Tracker is set to None!"); else switch (compass.enumValueIndex) { case (int)RUISTracker.CompassSource.Kinect1: case (int)RUISTracker.CompassSource.Kinect2: compassPlayerID.intValue = Mathf.Clamp(compassPlayerID.intValue, 0, maxKinectSkeletons - 1); driftCorrectionRateKinect.floatValue = Mathf.Clamp(driftCorrectionRateKinect.floatValue, minDriftCorrectionRate, maxDriftCorrectionRate ); EditorGUI.BeginDisabledGroup(compassIsPositionTracker.boolValue); EditorGUILayout.PropertyField(compassPlayerID, new GUIContent("Kinect Player ID", "Between 0 and 3")); EditorGUILayout.PropertyField(compassJoint, new GUIContent("Compass Joint", "ATTENTION: Torso has most stable " + "joint rotation for drift correction! Currently OpenNI's " + "head joint rotation is always the same as torso rotation, " + "except its tracking fails more often.")); EditorGUI.EndDisabledGroup(); EditorGUILayout.PropertyField(compassRotationOffsetKinect, new GUIContent("Compass Rotation Offset", "Kinect joint's " + "rotation in tracked object's local coordinate system. If using " + "Kinect for head tracking yaw drif correction, then zero vector is " + "usually the best choice if torso or head is the Compass Joint. " + "IT IS IMPORTANT THAT THIS PARAMETER IS CORRECT." + "Use 'Optional visualizers' to help finding the right values.")); EditorGUILayout.PropertyField(correctOnlyWhenFacingForward, new GUIContent("Only Forward Corrections", "Allows drift " + "correction to occur only when the player is detected as " + "standing towards Kinect (+-90 degrees). This is useful when " + "you know that the players will be mostly facing towards Kinect " + "and you want to improve drift correction by ignoring OpenNI's " + "tracking errors where the player is detected falsely " + "standing backwards (happens often).")); EditorGUILayout.PropertyField(driftCorrectionRateKinect, new GUIContent("Correction Rate", "Positive values only. How fast " + "the drifting rotation is shifted towards the compass' " + "rotation. Kinect tracked skeleton is quite inaccurate as a " + "compass, and the default 0.08 might be good. You might want " + "to adjust this to suit your liking.")); break; case (int)RUISTracker.CompassSource.PSMove: compassPSMoveID.intValue = Mathf.Clamp(compassPSMoveID.intValue, 0, maxPSMoveControllers - 1); driftCorrectionRatePSMove.floatValue = Mathf.Clamp(driftCorrectionRatePSMove.floatValue, minDriftCorrectionRate, maxDriftCorrectionRate ); EditorGUI.BeginDisabledGroup(compassIsPositionTracker.boolValue); EditorGUILayout.PropertyField(compassPSMoveID, new GUIContent("PS Move ID", "Between 0 and 3")); EditorGUI.EndDisabledGroup(); EditorGUILayout.PropertyField(compassRotationOffsetPSMove, new GUIContent("Compass Rotation Offset", "Tracked PS Move " + "controller's rotation in tracked object's local coordinate " + "system. Set these euler angles according to the orientation " + "in which Move Compass is attached to your tracked object " + "(head etc.). IT IS IMPORTANT THAT THIS PARAMETER IS CORRECT. " + "Use 'Optional visualizers' to help finding the right values.")); EditorGUILayout.PropertyField(driftCorrectionRatePSMove, new GUIContent("Correction Rate", "Positive values only. How fast " + "the drifting rotation is shifted towards the compass' " + "rotation. Default of 0.1 is good.")); break; case (int)RUISTracker.CompassSource.RazerHydra: driftCorrectionRateHydra.floatValue = Mathf.Clamp(driftCorrectionRateHydra.floatValue, minDriftCorrectionRate, maxDriftCorrectionRate ); EditorGUI.BeginDisabledGroup(compassIsPositionTracker.boolValue); EditorGUILayout.PropertyField(isRazerBaseMobile, new GUIContent("Moving Base Station", "Enable this if the Razer Hydra " + "base station is attached to something that is " + "moving (e.g. Kinect tracked player's belt)")); EditorGUILayout.PropertyField(compassRazerID, new GUIContent("Razer Hydra ID", "Either LEFT or RIGHT")); EditorGUI.EndDisabledGroup(); EditorGUILayout.PropertyField(compassRotationOffsetHydra, new GUIContent("Compass Rotation Offset", "Tracked Razer Hydra " + "controller's rotation in tracked object's local " + "coordinate system. Set these euler angles according " + "to the orientation in which the Razer Hydra is " + "attached to your tracked object (head etc.). " + "IT IS IMPORTANT THAT THIS PARAMETER IS CORRECT." + "Use 'Optional visualizers' to help finding the right values.")); EditorGUILayout.PropertyField(driftCorrectionRateHydra, new GUIContent("Correction Rate", "Positive values only. How fast " + "the drifting rotation is shifted towards the compass' " + "rotation. Default of 0.1 is good.")); break; case (int)RUISTracker.CompassSource.InputTransform: driftCorrectionRateTransform.floatValue = Mathf.Clamp(driftCorrectionRateTransform.floatValue, minDriftCorrectionRate, maxDriftCorrectionRate ); EditorGUI.BeginDisabledGroup(compassIsPositionTracker.boolValue); EditorGUILayout.PropertyField(compassTransform, new GUIContent("Input Transform", "Drift correction via all other " + "trackers is supported through this transform. Drag " + "and drop here a transform whose rotation cannot drift.")); EditorGUI.EndDisabledGroup(); EditorGUILayout.PropertyField(driftCorrectionRateTransform, new GUIContent("Correction Rate", "Positive values only. " + "How fast the drifting rotation is shifted towards the " + "compass' rotation.")); break; } EditorGUILayout.Space(); EditorGUILayout.LabelField("Optional visualizers:"); EditorGUILayout.PropertyField(enableVisualizers, new GUIContent("Enable Visualizers", "Below visualizers are optional and meant to" + "illustrate the performance of the drift correction.")); if(enableVisualizers.boolValue) { EditorGUI.indentLevel += 1; EditorGUILayout.PropertyField(driftingDirectionVisualizer, new GUIContent("Drifter Rotation Visualizer", "Drag and drop a Game " + "Object here to visualize rotation from Rotation Tracker")); EditorGUILayout.PropertyField(compassDirectionVisualizer, new GUIContent("Compass Yaw Visualizer", "Drag and drop a Game Object " + "here to visualize yaw rotation from Compass Tracker")); EditorGUILayout.PropertyField(correctedDirectionVisualizer, new GUIContent("Corrected Rotation Visualizer", "Drag and drop a Game " + "Object here to visualize the final, corrected rotation")); EditorGUILayout.PropertyField(driftVisualizerPosition, new GUIContent("Visualizer Position", "Drag and drop a Transform here " + "that defines the position where the above three " + "visualizers will appear")); EditorGUI.indentLevel -= 1; } EditorGUI.indentLevel -= 2; } } if(isRazerBaseMobile.boolValue) { if(headPositionInput.enumValueIndex == (int)RUISTracker.HeadPositionSource.RazerHydra) movingBaseAnnouncement = "Razer Hydra base station set as moving in Position Tracker"; else if(headRotationInput.enumValueIndex == (int)RUISTracker.HeadRotationSource.RazerHydra && !riftFound) movingBaseAnnouncement = "Razer Hydra base station set as moving in Rotation Tracker"; else if( compass.enumValueIndex == (int)RUISTracker.CompassSource.RazerHydra && externalDriftCorrection.boolValue && (riftFound || headRotationInput.enumValueIndex == (int)RUISTracker.HeadRotationSource.InputTransform) ) movingBaseAnnouncement = "Razer Hydra base station set as moving in Yaw Drift Correction"; else { movingBaseAnnouncement = ""; isRazerBaseMobile.boolValue = false; // When all the ifs fail, we can set isRazerBaseMobile to false } } if(isRazerBaseMobile.boolValue) { EditorGUILayout.PropertyField(mobileRazerBase, new GUIContent("Razer Base Tracker", "The tracker onto which the Razer Hydra " + "base station is attached to")); EditorGUI.indentLevel += 2; if(movingBaseAnnouncement.Length > 0) { EditorStyles.textField.wordWrap = true; EditorGUILayout.TextArea(movingBaseAnnouncement, GUILayout.Height(30)); } switch(mobileRazerBase.enumValueIndex) { case (int) RUISTracker.RazerHydraBase.Kinect1: hydraBaseKinectPlayerID.intValue = Mathf.Clamp(hydraBaseKinectPlayerID.intValue, 0, maxKinectSkeletons - 1); if(hydraBasePositionCovarianceKinect.floatValue < minNoiseCovariance) hydraBasePositionCovarianceKinect.floatValue = minNoiseCovariance; if(hydraBaseRotationCovarianceKinect.floatValue < minNoiseCovariance) hydraBaseRotationCovarianceKinect.floatValue = minNoiseCovariance; EditorGUILayout.PropertyField(hydraBaseKinectPlayerID, new GUIContent("Kinect Player Id", "Between 0 and 3")); EditorGUILayout.PropertyField(hydraBaseJoint, new GUIContent("Joint", "Kinect joint onto which Razer Hydra base station " + "is attached to")); EditorGUILayout.PropertyField(hydraBasePositionOffsetKinect, new GUIContent("Base Position Offset (meters)", "Razer Hydra " + "base station's position in the tracked joint's local coordinate " + "system. Set these values according to the base station's position " + "offset from the tracked joint's origin.")); EditorGUILayout.PropertyField(hydraBaseRotationOffsetKinect, new GUIContent("Base Rotation Offset", "Razer Hydra " + "base station's rotation in the tracked joint's local coordinate " + "system. Set these euler angles according to the orientation in which " + "Razer Hydra base station is attached to the tracked joint. " + "IT IS IMPORTANT THAT THIS PARAMETER IS CORRECT.")); EditorGUILayout.PropertyField(inferBaseRotationFromRotationTrackerKinect, new GUIContent("Use Rotation Tracker", "If the " + "above Position Tracker or Compass Razer Hydra is attached to the " + "Rotation Tracker (e.g. Oculus Rift), then use them together to " + "calculate the base station's rotation. Recommended for " + "Kinect.")); if(inferBaseRotationFromRotationTrackerKinect.boolValue) { EditorGUI.indentLevel += 1; EditorGUILayout.PropertyField(hydraAtRotationTrackerOffset, new GUIContent("Razer Hydra Rotation Offset", "Tracked " + "Razer Hydra controller's rotation in tracked object's local coordinate " + "system. Set these euler angles according to the orientation in which " + "the Razer Hydra is attached to the tracked object (head etc.). " + "IT IS IMPORTANT THAT THIS PARAMETER IS CORRECT.")); EditorGUI.indentLevel -= 1; } EditorGUILayout.PropertyField(filterHydraBasePoseKinect, new GUIContent("Filter Tracking", "Enables simple " + "Kalman filtering for position and rotation tracking of the Razer " + "Hydra base station. Recommended for Kinect.")); if(filterHydraBasePoseKinect.boolValue) { EditorGUILayout.PropertyField(hydraBasePositionCovarianceKinect, new GUIContent("Filter Position Strength", "Position " + "noise covariance of Kalman filtering: a bigger value means " + "smoother results but a slower response to changes.")); EditorGUILayout.PropertyField(hydraBaseRotationCovarianceKinect, new GUIContent("Filter Rotation Strength", "Rotation " + "noise covariance of Kalman filtering: a bigger value means " + "smoother results but a slower response to changes.")); } break; case (int) RUISTracker.RazerHydraBase.InputTransform: if(hydraBasePositionCovarianceTransform.floatValue < minNoiseCovariance) hydraBasePositionCovarianceTransform.floatValue = minNoiseCovariance; if(hydraBaseRotationCovarianceTransform.floatValue < minNoiseCovariance) hydraBaseRotationCovarianceTransform.floatValue = minNoiseCovariance; EditorGUILayout.PropertyField(hydraBaseInput, new GUIContent("Input Transform", "All other trackers are supported " + "through this transform. Drag and drop here a transform " + "whose position and rotation is controlled by a tracking device.")); EditorGUILayout.PropertyField(inferBaseRotationFromRotationTrackerTransform, new GUIContent("Use Rotation Tracker", "If the " + "above Position Tracker or Compass Razer Hydra is attached to the " + "Rotation Tracker (e.g. Oculus Rift), then use them together to " + "calculate the base station's rotation.")); if(inferBaseRotationFromRotationTrackerTransform.boolValue) { EditorGUI.indentLevel += 1; EditorGUILayout.PropertyField(hydraAtRotationTrackerOffset, new GUIContent("Razer Hydra Rotation Offset", "Tracked " + "Razer Hydra controller's rotation in tracked object's local coordinate " + "system. Set these euler angles according to the orientation in which " + "the Razer Hydra is attached to the tracked object (head etc.). " + "IT IS IMPORTANT THAT THIS PARAMETER IS CORRECT.")); EditorGUI.indentLevel -= 1; } EditorGUILayout.PropertyField(filterHydraBasePoseTransform, new GUIContent("Filter Tracking", "Enables simple " + "Kalman filtering for position and rotation tracking of the Razer " + "Hydra base station.")); if(filterHydraBasePoseTransform.boolValue) { EditorGUILayout.PropertyField(hydraBasePositionCovarianceTransform, new GUIContent("Filter Position Strength", "Position " + "noise covariance of Kalman filtering: a bigger value means " + "smoother results but a slower response to changes.")); EditorGUILayout.PropertyField(hydraBaseRotationCovarianceTransform, new GUIContent("Filter Rotation Strength", "Rotation " + "noise covariance of Kalman filtering: a bigger value means " + "smoother results but a slower response to changes.")); } break; } EditorGUI.indentLevel -= 2; } serializedObject.ApplyModifiedProperties(); }