IEnumerator JobsSpawnerCoroutine() { // ensure that the headset is connected and ready before starting any recording var nextFrameAwaiter = new WaitForEndOfFrame(); while (!FoveManager.IsHardwareConnected()) { yield return(nextFrameAwaiter); } // if the recording rate is the same as the fove rendering rate, // we use a coroutine to be sure that recorded gazes are synchronized with frames if (recordingRate == RecordingRate._70FPS) { // Coroutines give us a bit more control over when the call happens, and also simplify the code // structure. However they are only ever called once per frame -- they processing to happen in // pieces, but they shouldn't be confused with threads. StartCoroutine(RecordDataCoroutine()); } else // otherwise we just start a vsynch asynchronous thread { StartCoroutine(RecordFoveTransformCoroutine()); collectThread = new Thread(CollectThreadFunc); collectThread.Start(); } }
static string getEyeClosedString(Fove.Eye eye) { var closedEyes = FoveManager.CheckEyesClosed(); var eyeClosed = (eye & closedEyes) != 0; return(eyeClosed.ToString()); }
private void UpdateFoveInterfaceMatrices(bool immediate) { var t = fove.transform; if (immediate) { // In the case of 120 FPS recording rate, we re-fetch the HMD latest pose // and localy recalculate the fove interface local transform var pose = FoveManager.GetHMDPose(true); var isStanding = fove.poseType == FoveInterface.PlayerPose.Standing; var hmdAdjustedPosition = (isStanding ? pose.standingPosition : pose.position).ToVector3(); var localPos = fove.fetchPosition? hmdAdjustedPosition : t.position; var localRot = fove.fetchOrientation? pose.orientation.ToQuaternion() : t.rotation; var parentTransfo = t.parent != null ? t.parent.localToWorldMatrix : Matrix4x4.identity; var localTransfo = Matrix4x4.TRS(localPos, localRot, t.localScale); lock (foveInterfaceTransfo) { foveInterfaceTransfo.HMDToWorld = parentTransfo * localTransfo; foveInterfaceTransfo.HMDToLocal = localTransfo; } } else { // no need to lock the object, we are in synchronize mode (access from the same thread) foveInterfaceTransfo.HMDToWorld = t.localToWorldMatrix; foveInterfaceTransfo.HMDToLocal = Matrix4x4.TRS(t.localPosition, t.localRotation, t.localScale); } }
// Update is called once per frame void Update() { ManagerOrientText.text = toFomattedString(FoveManager.GetHmdRotation().value); ManagerPosText.text = toFomattedString(FoveManager.GetHmdPosition(false).value); ManagerGazeText.text = toFomattedString(FoveManager.GetHmdCombinedGazeRay().value.direction); InterfaceOrientText.text = toFomattedString(fove.transform.rotation); InterfacePosText.text = toFomattedString(fove.transform.position); InterfaceGazeText.text = toFomattedString(fove.GetCombinedGazeRay().value.direction); }
// Update is called once per frame void Update() { // IOD & IPD iodText.text = toMilliString(FoveManager.GetUserIOD()); ipdText.text = toMilliString(FoveManager.GetUserIPD()); // Eye radius UpdateEyeTexts(Fove.Eye.Left); UpdateEyeTexts(Fove.Eye.Right); }
// Update is called once per frame void Update() { if (FoveManager.GetGazedObject() == gazedReference) { mat.color = Color.yellow; } else { mat.color = Color.gray; } }
void Start() { var caps = Fove.ClientCapabilities.EyeTorsion | Fove.ClientCapabilities.EyeballRadius | Fove.ClientCapabilities.IrisRadius | Fove.ClientCapabilities.PupilRadius | Fove.ClientCapabilities.UserIOD | Fove.ClientCapabilities.UserIPD; FoveManager.RegisterCapabilities(caps); }
// Update is called once per frame void Update() { var pose = FoveManager.GetHMDPose(); var conv = FoveManager.GetHMDGazeConvergence(); var foveConv = fove.GetGazeConvergence(); ManagerOrientText.text = toFomattedString(pose.orientation.ToQuaternion()); ManagerPosText.text = toFomattedString(pose.position.ToVector3()); ManagerGazeText.text = toFomattedString(conv.ray.direction); InterfaceOrientText.text = toFomattedString(fove.transform.rotation); InterfacePosText.text = toFomattedString(fove.transform.position); InterfaceGazeText.text = toFomattedString(foveConv.ray.direction); }
void Start() { var profileNames = FoveManager.ListProfiles().value; foreach (var profile in profileNames) { var item = GameObject.Instantiate(profileItemPrefab); item.transform.SetParent(layout.transform, false); var controller = item.GetComponent <ProfileItemController>(); controller.ProfileName = profile; controllers.Add(controller); } }
// Update is called once per frame void Update() { var gazeRay = FoveManager.GetHmdCombinedGazeRay().value; var gazeDepth = FoveManager.GetCombinedGazeDepth().value; var dist = useGazeConvergenceDepth ? gazeDepth : distance; if (float.IsInfinity(dist) || float.IsNaN(dist)) { dist = distance; } transform.localPosition = gazeRay.origin + dist * gazeRay.direction; pointRenderer.enabled = !FoveManager.IsEyeTrackingCalibrating(); }
// Update is called once per frame void Update() { if (Input.GetKeyDown(KeyCode.T)) { FoveManager.TareOrientation(); } if (Input.GetKeyDown(KeyCode.M)) { calibOptions.method = (CalibrationMethod)(((int)calibOptions.method + 1) % Enum.GetNames(typeof(CalibrationMethod)).Length); RestartCalibrationIfRunning(); } if (Input.GetKeyDown(KeyCode.C)) { calibRenderer.enabled = !calibRenderer.enabled; RestartCalibrationIfRunning(); } if (Input.GetKeyDown(KeyCode.E)) { calibOptions.eyeByEye = (EyeByEyeCalibration)(((int)calibOptions.eyeByEye + 1) % Enum.GetNames(typeof(EyeByEyeCalibration)).Length); RestartCalibrationIfRunning(); } if (Input.GetKeyDown(KeyCode.R)) { calibOptions.restart = !calibOptions.restart; RestartCalibrationIfRunning(); } if (Input.GetKeyDown(KeyCode.L)) { calibOptions.lazy = !calibOptions.lazy; RestartCalibrationIfRunning(); } if (Input.GetKeyDown(KeyCode.Space)) { FoveManager.StartEyeTrackingCalibration(calibOptions); } if (Input.GetKeyDown(KeyCode.S)) { FoveManager.StopEyeTrackingCalibration(); } isCalibratedText.text = "IsCalibrated: " + FoveManager.IsEyeTrackingCalibrated().value; isCalibratingText.text = "IsCalibrating: " + FoveManager.IsEyeTrackingCalibrating().value; stateText.text = "Calibration State: " + FoveManager.GetEyeTrackingCalibrationState().value; lazyText.text = "Lazy Calibration: " + calibOptions.lazy; restartText.text = "Restart Calibration: " + calibOptions.restart; eyeByEyeText.text = "Eye-by-eye Calibration: " + calibOptions.eyeByEye; methodText.text = "Calibration Method: " + calibOptions.method; renderModeText.text = "Custom Calibration Rendering: " + calibRenderer.enabled; }
private void RestartCalibrationIfRunning() { if (!FoveManager.IsEyeTrackingCalibrating()) { return; } var restartOpts = new CalibrationOptions { restart = true, eyeByEye = calibOptions.eyeByEye, method = calibOptions.method, }; FoveManager.StartEyeTrackingCalibration(restartOpts); }
// Use this for initialization void Start() { FoveManager.RegisterCapabilities(Fove.ClientCapabilities.EyesImage | Fove.ClientCapabilities.EyeShape); for (var i = 0; i < EyeShape.OutlinePointCount; ++i) { eyePointsLeft[i] = (GameObject)Instantiate(eyePointPrefab, eyePointRootLeft, false); eyePointsRight[i] = (GameObject)Instantiate(eyePointPrefab, eyePointRootRight, false); var size = 7f; eyePointsLeft[i].transform.localScale = size * new Vector3(1, -1, 1); eyePointsRight[i].transform.localScale = size * new Vector3(1, -1, 1); eyePointsLeft[i].GetComponentInChildren <Text>().text = i.ToString(); eyePointsRight[i].GetComponentInChildren <Text>().text = i.ToString(); } }
private void UpdateEyeTexts(Fove.Eye eye) { var isLeft = eye == Fove.Eye.Left; var infoTexts = isLeft ? leftEyeInfoTexts : rightEyeInfoTexts; // eye closed or open infoTexts.stateText.text = getEyeStateString(eye); // Eye radius infoTexts.eyeText.text = toMilliString(FoveManager.GetEyeballRadius(eye)); infoTexts.irisText.text = toMilliString(FoveManager.GetIrisRadius(eye)); infoTexts.pupilText.text = toMilliString(FoveManager.GetPupilRadius(eye)); var torsion = FoveManager.GetEyeTorsion(eye); var torsionText = torsion.Failed ? torsion.error.ToString() : torsion.value.ToString("F2"); infoTexts.torsionText.text = torsionText; }
// Use this for initialization void Start() { FoveManager.RegisterCapabilities(Fove.ClientCapabilities.GazedObjectDetection); if (gazedReference == null) { gazedReference = gameObject; } var renderer = GetComponent <Renderer>(); if (renderer != null) { mat = GetComponent <Renderer>().material; } else { mat = GetComponent <Image>().material; } }
void UpdateEyeShape(Fove.Eye eye) { var shapeResult = FoveManager.GetEyeShape(eye); if (shapeResult.Failed) { Debug.LogWarning("Failed to retrieve eye shape"); return; } var shapes = shapeResult.value; var eyePoints = eye == Fove.Eye.Left ? eyePointsLeft : eyePointsRight; int i = 0; foreach (var point in shapes.Outline) { eyePoints[i++].transform.localPosition = new Vector3(point.x, point.y, 0); } }
// Update is called once per frame void FixedUpdate() { var obj = FoveManager.GetGazedObject().value; if (obj == null) { return; } var rbody = obj.GetComponent <Rigidbody>(); if (rbody == null) { return; } var gazeRay = fove.GetCombinedGazeRay().value; rbody.AddForce(25 * gazeRay.direction); }
private void UpdateFoveInterfaceMatrices(bool immediate) { var t = fove.transform; var markKeyDown = Input.GetKey(markFrameKey); var gazedObjectResult = FoveManager.GetGazedObject(); var gazedObjectName = new Result <string>(gazedObjectResult.value? gazedObjectResult.value.name : "", gazedObjectResult.error); if (immediate) { // In the case of 120 FPS recording rate, we re-fetch the HMD latest pose // and locally recalculate the fove interface local transform var isStanding = fove.poseType == FoveInterface.PlayerPose.Standing; var hmdAdjustedPosition = FoveManager.GetHmdPosition(isStanding); var localPos = fove.fetchPosition? hmdAdjustedPosition : t.position; var localRot = fove.fetchOrientation? FoveManager.GetHmdRotation() : t.rotation; var parentTransfo = t.parent != null ? t.parent.localToWorldMatrix : Matrix4x4.identity; var localTransfo = Matrix4x4.TRS(localPos, localRot, t.localScale); lock (unityThreadData) { unityThreadData.HMDToWorld = parentTransfo * localTransfo; unityThreadData.HMDToLocal = localTransfo; unityThreadData.markKeyDown = markKeyDown; unityThreadData.gazedObject = gazedObjectName; unityThreadData.HMDPosition = localPos; unityThreadData.HMDOrientation = localRot; } } else { // no need to lock the object, we are in synchronize mode (access from the same thread) unityThreadData.HMDToWorld = t.localToWorldMatrix; unityThreadData.HMDToLocal = Matrix4x4.TRS(t.localPosition, t.localRotation, t.localScale); unityThreadData.markKeyDown = markKeyDown; unityThreadData.gazedObject = gazedObjectName; unityThreadData.HMDPosition = t.localPosition; unityThreadData.HMDOrientation = t.localRotation; } }
void validateSelectedItem(bool setCurrent) { var controller = controllers[selectedIndex]; controller.ValidateName(); var newProfileName = controller.GetEditValue(); if (setCurrent && controller.ProfileName == newProfileName) // it is a set { FoveManager.SetCurrentProfile(newProfileName); } else if (string.IsNullOrEmpty(controller.ProfileName)) // create case { FoveManager.CreateProfile(newProfileName); } else { FoveManager.RenameProfile(controller.ProfileName, newProfileName); } controller.ProfileName = newProfileName; }
private Stopwatch stopwatch = new Stopwatch(); // Unity Time.time can't be use outside of main thread. // Use this for initialization. void Start() { stopwatch.Start(); if (!Stopwatch.IsHighResolution) { Debug.LogWarning("High precision stopwatch is not supported on this machine. Recorded frame times may not be highly accurate."); } // Check to make sure that the FOVE interface variable is assigned. This prevents a ton of errors // from filling your log if you forget to assign the interface through the inspector. if (fove == null) { Debug.LogWarning("Forgot to assign a Fove interface to the FOVERecorder object."); enabled = false; return; } var caps = ClientCapabilities.EyeTracking; if (exportFields.GazeDepth) { caps |= ClientCapabilities.GazeDepth; } if (exportFields.PupilsRadius) { caps |= ClientCapabilities.PupilRadius; } if (exportFields.GazedObject) { caps |= ClientCapabilities.GazedObjectDetection; } if (exportFields.EyeTorsion) { caps |= ClientCapabilities.EyeTorsion; } if (exportFields.UserPresence) { caps |= ClientCapabilities.UserPresence; } if (exportFields.UserAttentionShift) { caps |= ClientCapabilities.UserAttentionShift; } if (exportFields.IPD) { caps |= ClientCapabilities.UserIPD; } if (exportFields.IOD) { caps |= ClientCapabilities.UserIOD; } if (exportFields.EyeballRadius) { caps |= ClientCapabilities.EyeballRadius; } if (exportFields.EyeShape) { caps |= ClientCapabilities.EyeShape; } if (exportFields.PupilShape) { caps |= ClientCapabilities.PupilShape; } FoveManager.RegisterCapabilities(caps); // We set the initial data slice capacity to the expected size + 1 so that we never waste time reallocating and // copying data under the hood. If the system ever requires more than a single extra entry, there is likely // a severe problem causing delays which should be addressed. dataSlice = new AggregatedData(writeAtDataCount + 1); // If overwrite is not set, then we need to make sure our selected file name is valid before proceeding. if (!Directory.Exists(OutputFolder)) { Directory.CreateDirectory(OutputFolder); } { string testFileName = Path.Combine(OutputFolder, outputFileName + ".csv"); if (!overwriteExistingFile) { int counter = 1; while (File.Exists(testFileName)) { testFileName = Path.Combine(OutputFolder, outputFileName + "_" + (counter++) + ".csv"); // e.g., "results_12.csv" } } outputFileName = testFileName; Debug.Log("Writing data to " + outputFileName); } dataToWrite.Enqueue(new DataHeaderSerializer(exportFields)); // Create the write thread to call "WriteThreadFunc", and then start it. writeThread = new Thread(WriteThreadFunc); writeThread.Start(); StartCoroutine(JobsSpawnerCoroutine()); }
private void RecordDatum(bool immediate) { // If recording is stopped (which is it by default), loop back around next frame. if (recordingStopped) { return; } if (!immediate) // we run in the same thread as unity we can update the transformations in a synchronized way { UpdateFoveInterfaceMatrices(false); } Matrix4x4 transformMat; lock (foveInterfaceTransfo) { switch (raysCoordinateSpace) { case CoordinateSpace.World: transformMat = foveInterfaceTransfo.HMDToWorld; break; case CoordinateSpace.Local: transformMat = foveInterfaceTransfo.HMDToLocal; break; default: transformMat = Matrix4x4.identity; break; } } var leftEyeOffset = FoveManager.GetLeftEyeOffset(immediate); var rightEyeOffset = FoveManager.GetRightEyeOffset(immediate); var leftEyeVector = FoveManager.GetLeftEyeVector(immediate); var rightEyeVector = FoveManager.GetRightEyeVector(immediate); Ray leftRay, rightRay; Utils.CalculateGazeRays(ref transformMat, ref leftEyeVector, ref rightEyeVector, ref leftEyeOffset, ref rightEyeOffset, out leftRay, out rightRay); // If you add new fields, be sure to write them here. var datum = new RecordingDatum { frameTime = stopwatch.Elapsed.TotalSeconds, leftGaze = leftRay, rightGaze = rightRay, }; dataSlice.Add(datum); if (dataSlice.Count >= writeAtDataCount) { // Make sure we have exclusive access by locking the mutex, but only wait for up to 30 milliseconds. if (!writingDataMutex.WaitOne(30)) { // If we got here, it means that we couldn't acquire exclusive access within the specified time // limit. Likely this means an error happened, but it could also mean that more data was being // written than it took to gather another set of data -- in which case you may need to extend the // timeout duration, though that will cause a noticeable frame skip in your application. // For now, the best thing we can do is continue the loop and try writing data again next frame. long excess = dataSlice.Count - writeAtDataCount; if (excess > 1) { Debug.LogError("Data slice is " + excess + " entries over where it should be; this is" + "indicative of a major performance concern in the data recording and writing" + "process."); } return; } CheckForNullDataToWrite(); // Move our current slice over to dataToWrite, and then create a new slice. dataToWrite = dataSlice; dataSlice = new List <RecordingDatum>((int)(writeAtDataCount + 1)); // Release our claim on the mutex. writingDataMutex.ReleaseMutex(); if (!threadWaitHandle.Set()) { Debug.LogError("Error setting the event to wake up the file writer thread"); } } }
void Update() { EyeImage.texture = FoveManager.GetEyesImage(); PositionImage.texture = FoveManager.GetPositionImage(); MirrorImage.texture = FoveManager.GetMirrorTexture(); }
void Start() { var caps = Fove.ClientCapabilities.EyesImage | Fove.ClientCapabilities.PositionImage; FoveManager.RegisterCapabilities(caps); }
public void Calibration() { FoveManager.EnsureEyeTrackingCalibration(); }
void Update() { if (Input.GetKeyDown(KeyCode.Delete)) { var controller = controllers[selectedIndex]; FoveManager.DeleteProfile(controller.ProfileName); Destroy(controller.gameObject); controllers.RemoveAt(selectedIndex); } else if (Input.GetKeyDown(KeyCode.DownArrow)) { validateSelectedItem(false); ++selectedIndex; } else if (Input.GetKeyDown(KeyCode.UpArrow)) { validateSelectedItem(false); --selectedIndex; } else if (Input.GetKeyDown(KeyCode.F2)) { controllers[selectedIndex].EnterNameEditMode(); } else if (Input.GetKeyDown(KeyCode.Insert)) { var item = GameObject.Instantiate(profileItemPrefab); item.transform.SetParent(layout.transform, false); var controller = item.GetComponent <ProfileItemController>(); controller.EnterNameEditMode(); controllers.Add(controller); selectedIndex = controllers.Count - 1; } else if (Input.GetKeyDown(KeyCode.Return)) { validateSelectedItem(true); } if (controllers.Count == 0) { return; } // else if RENAME // else if CREATE selectedIndex = (selectedIndex + controllers.Count) % controllers.Count; string selectedProfile = controllers[selectedIndex].ProfileName; string selectedProfileDataPath = ""; var currProfile = FoveManager.GetCurrentProfile().value; if (!string.IsNullOrEmpty(selectedProfile)) { selectedProfileDataPath = FoveManager.GetProfileDataPath(selectedProfile); } dataPathText.text = "Data Path: \"" + selectedProfileDataPath + "\""; for (int i = 0; i < controllers.Count; i++) { var controller = controllers[i]; controller.isSelected = i == selectedIndex; controller.isCurrent = controller.ProfileName == currProfile; } }
// Use this for initialization void Start() { FoveManager.TareOrientation(); }
// Currently does not support editing of multiple objects at once. // I do not anticipate any problems with this since you should only // ever really have one per scene anyway. public sealed override void OnInspectorGUI() { // A decent style. Light grey text inside a border. helpStyle = new GUIStyle(GUI.skin.box); helpStyle.wordWrap = true; helpStyle.alignment = TextAnchor.UpperLeft; helpStyle.normal.textColor = Color.red; // Update the serializedobject serializedObject.Update(); // Cache the editor's playing state so we can prevent editing fields that shouldn't update during // a live play session. bool isPlaying = EditorApplication.isPlaying; EditorGUILayout.Space(); EditorGUILayout.LabelField("Client fetches and sync:", EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); { EditorGUI.indentLevel++; EditorGUILayout.PropertyField(_gaze, fetchGazeLabel); EditorGUILayout.PropertyField(_orientation, fetchOrientationLabel); EditorGUILayout.PropertyField(_position, fetchPositionLabel); EditorGUI.indentLevel--; } EditorGUILayout.Space(); EditorGUILayout.PropertyField(_eyeTargets); EditorGUILayout.PropertyField(_poseType); GUI.enabled = true; _showGazeCast = EditorGUILayout.Foldout(_showGazeCast, "Gaze Object Detection"); if (_showGazeCast) { EditorGUI.indentLevel++; EditorGUILayout.PropertyField(_registerCameraObject, registerCameraLabel); EditorGUILayout.PropertyField(_gazeCastCullMask, castCullMaskLabel); EditorGUI.indentLevel--; } GUI.enabled = true; _showCullingMasks = EditorGUILayout.Foldout(_showCullingMasks, "Per-Eye Culling Masks"); if (_showCullingMasks) { EditorGUI.indentLevel++; EditorGUILayout.PropertyField(_cullMaskLeft); EditorGUILayout.PropertyField(_cullMaskRight); EditorGUI.indentLevel--; } GUI.enabled = true; _showCompositorAttribs = EditorGUILayout.Foldout(_showCompositorAttribs, "Compositor options"); if (_showCompositorAttribs) { GUI.enabled = !isPlaying; EditorGUI.indentLevel++; //EditorGUILayout.PropertyField(_compositorLayerType); EditorGUILayout.PropertyField(_compositorDisableTimewarp); //EditorGUILayout.PropertyField(_compositorDisableDistortion); EditorGUI.indentLevel--; } GUI.enabled = true; if (isPlaying && GUILayout.Button("Ensure calibration")) { Debug.Log("Manually triggering eye tracking calibration check from inspector..."); FoveManager.StartEyeTrackingCalibration(new CalibrationOptions { lazy = true }); } if (Application.targetFrameRate != -1) { GUILayout.Label( "WARNING: Your target framerate is set to " + Application.targetFrameRate + ". Having a target framerate can artificially slow down FOVE frame submission. We recommend disabling this." , helpStyle , GUILayout.ExpandWidth(true)); } serializedObject.ApplyModifiedProperties(); }
static string getEyeStateString(Fove.Eye eye) { var state = FoveManager.GetEyeState(eye).value; return(state.ToString()); }
private void RecordDatum(bool immediate) { // If recording is stopped (which is it by default), loop back around next frame. if (!shouldRecord) { return; } if (!immediate) // we run in the same thread as unity we can update the transformations in a synchronized way { UpdateFoveInterfaceMatrices(false); } bool frameMarked; Result <string> gazedObjectName; Matrix4x4 transformMat; Vector3 hmdPosition; Quaternion hmdOrientation; lock (unityThreadData) { switch (gazeCoordinateSpace) { case CoordinateSpace.World: transformMat = unityThreadData.HMDToWorld; break; case CoordinateSpace.Local: transformMat = unityThreadData.HMDToLocal; break; default: transformMat = Matrix4x4.identity; break; } frameMarked = unityThreadData.markKeyDown; gazedObjectName = unityThreadData.gazedObject; hmdPosition = unityThreadData.HMDPosition; hmdOrientation = unityThreadData.HMDOrientation; } var eyeOffsets = FoveManager.GetEyeOffsets(); var eyeVectorL = FoveManager.GetHmdGazeVector(Eye.Left); var eyeVectorR = FoveManager.GetHmdGazeVector(Eye.Right); Stereo <Result <Ray> > eyeRays; eyeRays.left = Utils.CalculateWorldGazeVector(ref transformMat, ref eyeOffsets.value.left, ref eyeVectorL); eyeRays.right = Utils.CalculateWorldGazeVector(ref transformMat, ref eyeOffsets.value.right, ref eyeVectorR); var gazeDepth = FoveManager.GetCombinedGazeDepth(); var combinedRay = FoveManager.GetHmdCombinedGazeRay(); combinedRay.value.origin = transformMat.MultiplyPoint(combinedRay.value.origin); combinedRay.value.direction = transformMat.MultiplyVector(combinedRay.value.direction).normalized; var pupilRadiusLeft = FoveManager.GetPupilRadius(Eye.Left); var pupilRadiusRight = FoveManager.GetPupilRadius(Eye.Right); var eyeStateL = FoveManager.GetEyeState(Eye.Left); var eyeStateR = FoveManager.GetEyeState(Eye.Right); var eyeTorsionL = FoveManager.GetEyeTorsion(Eye.Left); var eyeTorsionR = FoveManager.GetEyeTorsion(Eye.Right); // If you add new fields, be sure to write them here. var datum = new Datum { AppTime = (float)stopwatch.Elapsed.TotalSeconds, UserMark = frameMarked, GazedObjectName = gazedObjectName, HeadsetPosition = new Result <Vector3>(hmdPosition), HeadsetOrientation = new Result <Quaternion>(hmdOrientation), CombinedRay = combinedRay, GazeDepth = gazeDepth, EyeRays = eyeRays, EyesState = new Stereo <Result <EyeState> >(eyeStateL, eyeStateR), PupilsRadius = new Stereo <Result <float> >(pupilRadiusLeft, pupilRadiusRight), EyeTorsions = new Stereo <Result <float> >(eyeTorsionL, eyeTorsionR), UserPresence = FoveManager.IsUserPresent(), UserAttentionShift = FoveManager.IsUserShiftingAttention(), IPD = FoveManager.GetUserIPD(), IOD = FoveManager.GetUserIOD(), EyeballRadius = new Stereo <Result <float> >(FoveManager.GetEyeballRadius(Eye.Left), FoveManager.GetEyeballRadius(Eye.Right)), ScreenGaze = new Stereo <Result <Vector2> >(FoveManager.GetGazeScreenPosition(Eye.Left), FoveManager.GetGazeScreenPosition(Eye.Right)), EyeShape = new Stereo <Result <Fove.Unity.EyeShape> >(FoveManager.GetEyeShape(Eye.Left), FoveManager.GetEyeShape(Eye.Right)), PupilShape = new Stereo <Result <Fove.Unity.PupilShape> >(FoveManager.GetPupilShape(Eye.Left), FoveManager.GetPupilShape(Eye.Right)), }; dataSlice.Add(datum); if (dataSlice.Count >= writeAtDataCount) { flushData(); } }
// Update is called once per frame void Update() { var isVisible = spriteRenders[0].enabled || spriteRenders[1].enabled || canvas.enabled; // tick and pull calibration state var result = FoveManager.TickEyeTrackingCalibration(Time.deltaTime, isVisible); if (result.Failed) { Debug.LogError("Failed to tick calibration. Error:" + result.error); spriteRenders[0].enabled = false; spriteRenders[1].enabled = false; canvas.enabled = false; return; } // update the target position var calibrationData = result.value; var targets = calibrationData.targets; for (int i = 0; i < targets.ElementCount; i++) { var target = calibrationData.targets[i]; var spriteRenderer = spriteRenders[i]; if (target.recommendedSize > 0) { spriteRenderer.enabled = true; spriteRenderer.transform.localPosition = target.position; spriteRenderer.transform.localScale = 4f * target.recommendedSize * Vector3.one; } else { spriteRenderer.enabled = false; } } // update the text canvas.enabled = true; switch (calibrationData.state) { case Fove.CalibrationState.WaitingForUser: text.text = "Look at the target"; break; case Fove.CalibrationState.ProcessingData: text.text = "Processing..."; break; case Fove.CalibrationState.Successful_HighQuality: text.text = "Successful high quality!"; break; case Fove.CalibrationState.Successful_MediumQuality: text.text = "Successful medium quality"; break; case Fove.CalibrationState.Successful_LowQuality: text.text = "Successful low quality"; break; case Fove.CalibrationState.Failed_Aborted: text.text = "Calibration Aborted"; break; case Fove.CalibrationState.Failed_InaccurateData: text.text = "Calibration failed: Inaccurate data"; break; case Fove.CalibrationState.Failed_NoRenderer: text.text = "Calibration failed: no renderer"; break; case Fove.CalibrationState.Failed_NoUser: text.text = "Calibration failed: no user"; break; case Fove.CalibrationState.Failed_Unknown: text.text = "Calibration failed: unknown issue"; break; case Fove.CalibrationState.NotStarted: case Fove.CalibrationState.CollectingData: default: canvas.enabled = false; break; } if (calibrationData.state.IsSuccessful() || calibrationData.state.IsFailure()) { timeSinceCompletion += Time.deltaTime; if (timeSinceCompletion > 1.5) { canvas.enabled = false; } } else { timeSinceCompletion = 0; } }