public void Initialize() { if (FocusSizeFromCenter == null) { Reset(); } #if UNITY_EDITOR || DEVELOPMENT_BUILD VISFixationEnds.Add("discard", new List <Fixation>()); VISFixationEnds.Add("out of range", new List <Fixation>()); VISFixationEnds.Add("microsleep", new List <Fixation>()); VISFixationEnds.Add("off transform", new List <Fixation>()); var viewer = FindObjectOfType <FixationVisualizer>(); if (viewer != null) { viewer.SetTarget(this); } var saccade = FindObjectOfType <SaccadeDrawer>(); if (saccade != null) { saccade.SetTarget(this); } //gameObject.AddComponent<FixationVisualizer>().SetTarget(this); if (DebugMaterial != null) { lastEyeTrackingPointer = GameObject.CreatePrimitive(PrimitiveType.Sphere); lastEyeTrackingPointer.transform.localScale = Vector3.one * 0.2f; lastEyeTrackingPointer.GetComponent <MeshRenderer>().material = DebugMaterial; Destroy(lastEyeTrackingPointer.GetComponent <SphereCollider>()); } #endif ActiveFixation = new Fixation(); for (int i = 0; i < CachedEyeCaptures; i++) { EyeCaptures[i] = new EyeCapture() { Discard = true }; } #if CVR_FOVE fovebase = FindObjectOfType <FoveInterfaceBase>(); #elif CVR_TOBIIVR if (EyeTracker == null) { EyeTracker = FindObjectOfType <Tobii.Research.Unity.VREyeTracker>(); } #elif CVR_AH ah_calibrator = Calibrator.Instance; eyetracker = EyeTracker.Instance; #endif }
/// <summary> /// for a smooth pursuit fixation, is transform /// </summary> /// <param name="capture"></param> /// <returns></returns> bool IsGazeOffTransform(EyeCapture capture) { if (!IsFixating) { return(true); } if (capture.HitDynamicTransform != ActiveFixation.LocalTransform) { return(true); } return(false); }
//called just before new eyecapture is recorded. this has been around 1 second, so 'safe' to actually record public void AddEyeCapture(EyeCapture eyeCapture) { bool validEyeCapture = true; if (eyeCapture.Discard) { validEyeCapture = false; } else { LastNonDiscardedTime = eyeCapture.Time; } if (eyeCapture.EyesClosed) { validEyeCapture = false; } else { LastEyesOpen = eyeCapture.Time; } if (eyeCapture.OutOfRange) { validEyeCapture = false; } else { LastInRange = eyeCapture.Time; } if (eyeCapture.OffTransform) { validEyeCapture = false; } else { LastOnTransform = eyeCapture.Time; } //basically just add duration if (validEyeCapture) { LastUpdated = eyeCapture.Time; DurationMs = StartMs - LastUpdated; } }
/// <summary> /// returns true if gaze is NOT within active fixation /// updates average fixation position /// removes old smooth pursuit eye captures points (DynamicRollingAverageMS) /// </summary> /// <param name="capture"></param> /// <returns></returns> bool IsGazeOutOfRange(EyeCapture capture) { if (!IsFixating) { return(true); } if (ActiveFixation.IsLocal) { if (ActiveFixation.LocalTransform == null) { return(true); } if (capture.SkipPositionForFixationAverage || capture.OffTransform) { var _fixationWorldPosition = ActiveFixation.LocalTransform.TransformPoint(ActiveFixation.LocalPosition); var _fixationDirection = (_fixationWorldPosition - capture.HmdPosition).normalized; var _eyeCaptureWorldPos = ActiveFixation.LocalTransform.TransformPoint(capture.LocalPosition); var _eyeCaptureDirection = (_eyeCaptureWorldPos - capture.HmdPosition).normalized; var _eyeCaptureScreenPos = GameplayReferences.HMDCameraComponent.WorldToViewportPoint(_eyeCaptureWorldPos); var _screendist = Vector2.Distance(_eyeCaptureScreenPos, Vector3.one * 0.5f); var _rescale = FocusSizeFromCenter.Evaluate(_screendist); var _adjusteddotangle = Mathf.Cos(MaxFixationAngle * _rescale * DynamicFixationSizeMultiplier * Mathf.Deg2Rad); if (Vector3.Dot(_eyeCaptureDirection, _fixationDirection) < _adjusteddotangle) { return(true); } return(false); } else { //try to move fixation to include this capture too Vector3 averagelocalpos = Vector3.zero; foreach (var v in CachedEyeCapturePositions) { averagelocalpos += v; } averagelocalpos += capture.LocalPosition; averagelocalpos /= (CachedEyeCapturePositions.Count + 1); var _fixationWorldPosition = ActiveFixation.LocalTransform.TransformPoint(averagelocalpos); var _fixationDirection = (_fixationWorldPosition - capture.HmdPosition).normalized; var _eyeCaptureWorldPos = ActiveFixation.LocalTransform.TransformPoint(capture.LocalPosition); var _eyeCaptureDirection = (_eyeCaptureWorldPos - capture.HmdPosition).normalized; var _eyeCaptureScreenPos = GameplayReferences.HMDCameraComponent.WorldToViewportPoint(_eyeCaptureWorldPos); var _screendist = Vector2.Distance(_eyeCaptureScreenPos, Vector3.one * 0.5f); var _rescale = FocusSizeFromCenter.Evaluate(_screendist); var _adjusteddotangle = Mathf.Cos(MaxFixationAngle * _rescale * DynamicFixationSizeMultiplier * Mathf.Deg2Rad); if (Vector3.Dot(_eyeCaptureDirection, _fixationDirection) < _adjusteddotangle) { return(true); } float distance = Vector3.Magnitude(_fixationWorldPosition - capture.HmdPosition); float currentRadius = Mathf.Atan(MaxFixationAngle * Mathf.Deg2Rad) * distance; ActiveFixation.MaxRadius = Mathf.Max(ActiveFixation.MaxRadius, currentRadius); CachedEyeCapturePositions.Add(capture.LocalPosition); ActiveFixation.LocalPosition = averagelocalpos; return(false); } } else { var screenpos = GameplayReferences.HMDCameraComponent.WorldToViewportPoint(capture.WorldPosition); var screendist = Vector2.Distance(screenpos, Vector3.one * 0.5f); var rescale = FocusSizeFromCenter.Evaluate(screendist); var adjusteddotangle = Mathf.Cos(MaxFixationAngle * rescale * Mathf.Deg2Rad); if (capture.SkipPositionForFixationAverage) //eye capture is invalid (probably from looking at skybox) { Vector3 lookDir = (capture.WorldPosition - capture.HmdPosition).normalized; Vector3 fixationDir = (ActiveFixation.WorldPosition - capture.HmdPosition).normalized; if (Vector3.Dot(lookDir, fixationDir) < adjusteddotangle) { return(true); } else { //looking at skybox. will not update fixation radius } } else { Vector3 averageworldpos = Vector3.zero; foreach (var v in CachedEyeCapturePositions) { averageworldpos += v; } averageworldpos += capture.WorldPosition; averageworldpos /= (CachedEyeCapturePositions.Count + 1); Vector3 lookDir = (capture.WorldPosition - capture.HmdPosition).normalized; Vector3 fixationDir = (averageworldpos - capture.HmdPosition).normalized; if (Vector3.Dot(lookDir, fixationDir) < adjusteddotangle) { return(true); } float distance = Vector3.Magnitude(ActiveFixation.WorldPosition - capture.HmdPosition); float currentRadius = Mathf.Atan(MaxFixationAngle * Mathf.Deg2Rad) * distance; ActiveFixation.MaxRadius = Mathf.Max(ActiveFixation.MaxRadius, currentRadius); CachedEyeCapturePositions.Add(capture.WorldPosition); ActiveFixation.WorldPosition = averageworldpos; } } return(false); }