예제 #1
0
    // Update is called once per frame
    void Update()
    {
        if (state == State.RUNNING)
        {
            if (Input.location.status != LocationServiceStatus.Running)
            {
                state.SetState(State.STOPPED);
                Debug.LogError("Location should be running but now is: " + Input.location.status);
                onStopped.Invoke();
                return;
            }

            if (!lastData.HasValue || !EqualLocation(Input.location.lastData, lastData.Value))
            {
                lastData = Input.location.lastData;
                onNewData.Invoke(lastData.Value);
            }
        }
    }
예제 #2
0
 protected void SafeLaunchEvent(object sender, DataGram data)
 {
     NewDataEvent?.Invoke(sender, data);
 }
예제 #3
0
        /// <summary>
        /// On Update check if we need to invoke an action, process waiting data and if existing update the data access layer
        /// </summary>
        private void Update()
        {
            // Call the Unity update for the data access layer if it exists
            dataAccessLayer?.UnityUpdate();

            // Check if there are new actions to be executed and if yes execute them
            if (actionQueue.Count > 0)
            {
                // Process all actions which are waiting to be processed
                // Note: This isn't 100% thread save as we could end in a loop when there are new actions coming in faster than we are processing them.
                //       However, actions are added that rarely that we shouldn't run into issues.
                while (actionQueue.TryDequeue(out Action action))
                {
                    // Invoke the action from the queue
                    action.Invoke();
                }
            }

            // Check if there is new data to process and if yes process it
            if (dataQueue.Count > 0)
            {
                // Process all data which is waiting to be processed
                // Note: This isn't 100% thread save as we could end in a loop when there is still new data coming in faster than we are processing it.
                //       However, data is added slowly enough that we shouldn't run into issues.
                while (dataQueue.TryDequeue(out GazeAPIData gazeAPIData))
                {
                    // Initialize the resulting data object with the API data
                    GazeData gazeData = new GazeData(gazeAPIData);

                    // Add the current frame time
                    gazeData.FrameTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

                    // If we have valid gaze data process it
                    if (gazeAPIData.GazeHasValue)
                    {
                        // Crate a gaze ray based on the gaze data
                        Ray gazeRay = new Ray(gazeAPIData.GazeOrigin, gazeAPIData.GazeDirection);

                        ////
                        // The 3D gaze point is the actual position the wearer is looking at.
                        // As everything apart from the eye tracking layers is visible, we have to collide the gaze with every layer except the eye tracking layers

                        // Check if the gaze hits anything that isn't an AOI
                        gazeData.GazePointHit = Physics.Raycast(gazeRay, out RaycastHit hitInfo, Mathf.Infinity, notEyeTrackingLayerMask);

                        // If we hit something, write the hit info to the data
                        if (gazeData.GazePointHit)
                        {
                            // Write all info from the hit to the data object
                            gazeData.GazePoint     = hitInfo.point;
                            gazeData.GazePointName = hitInfo.collider.name;

                            // Cache the transform of the game object which was hit
                            Transform hitTransform = hitInfo.collider.transform;

                            // Get the position of the hit in the local coordinates of the game object which was hit
                            gazeData.GazePointOnHit = hitTransform.InverseTransformPoint(hitInfo.point);

                            // Get the info about the object which was hit
                            gazeData.GazePointHitPosition = hitTransform.position;
                            gazeData.GazePointHitRotation = hitTransform.rotation.eulerAngles;
                            gazeData.GazePointHitScale    = hitTransform.lossyScale;

                            // Update the position of the GazePoint visualization (only visible in the MRC view)
                            GazePointVis.transform.position = hitInfo.point;

                            // Get the position of the gaze point in the right and left eye if we have stereo rendering
                            if (mainCamera.stereoActiveEye != Camera.MonoOrStereoscopicEye.Mono)
                            {
                                gazeData.GazePointLeftDisplay  = mainCamera.WorldToScreenPoint(hitInfo.point, Camera.MonoOrStereoscopicEye.Left);
                                gazeData.GazePointRightDisplay = mainCamera.WorldToScreenPoint(hitInfo.point, Camera.MonoOrStereoscopicEye.Right);
                            }
                            else
                            {
                                gazeData.GazePointLeftDisplay  = null;
                                gazeData.GazePointRightDisplay = null;
                            }

                            // Also get the mono position (and always do this)
                            gazeData.GazePointMonoDisplay = mainCamera.WorldToScreenPoint(hitInfo.point, Camera.MonoOrStereoscopicEye.Mono);

                            // Get the position of the gaze point on the webcam image
                            gazeData.GazePointWebcam = webcamCamera.WorldToScreenPoint(hitInfo.point, Camera.MonoOrStereoscopicEye.Mono);
                        }
                        else
                        {
                            // Update the position of the GazePoint visualization (only visible in the MRC view)
                            GazePointVis.transform.position = Vector3.zero;
                        }

                        ////
                        // To check for AOIs we do a separate ray cast on the AOI layer

                        // Check if the gaze hits a AOI
                        gazeData.GazePointAOIHit = Physics.Raycast(gazeRay, out hitInfo, Mathf.Infinity, eyeTrackingAOILayerMask);

                        // If we hit an AOI, write the hit info to data, otherwise simply leave it empty
                        if (gazeData.GazePointAOIHit)
                        {
                            // Write all info from the hit to the data object
                            gazeData.GazePointAOI     = hitInfo.point;
                            gazeData.GazePointAOIName = hitInfo.collider.name;

                            // Cache the transform of the game object which was hit
                            Transform hitTransform = hitInfo.collider.transform;

                            // Get the position of the hit in the local coordinates of the game object which was hit
                            gazeData.GazePointAOIOnHit = hitTransform.InverseTransformPoint(hitInfo.point);

                            // Get the info about the object which was hit
                            gazeData.GazePointAOIHitPosition = hitTransform.position;
                            gazeData.GazePointAOIHitRotation = hitTransform.rotation.eulerAngles;
                            gazeData.GazePointAOIHitScale    = hitTransform.lossyScale;

                            // Get the position of the gaze point on the web cam image
                            gazeData.GazePointAOIWebcam = webcamCamera.WorldToScreenPoint(hitInfo.point, Camera.MonoOrStereoscopicEye.Mono);
                        }
                    }

                    // Get the position of the game objects we want to log

                    // Create new data array
                    gazeData.positionInfos = new PositionInfo[PositionLoggedGameObjects.Count];
                    // Go through every game object and log its position
                    for (int i = 0; i < PositionLoggedGameObjects.Count; i++)
                    {
                        // Check if the game object still exists
                        gazeData.positionInfos[i].positionValid = PositionLoggedGameObjects[i] != null;

                        // If it still exists log its position
                        if (gazeData.positionInfos[i].positionValid)
                        {
                            // Name
                            gazeData.positionInfos[i].gameObjectName = PositionLoggedGameObjects[i].name;

                            // Position
                            Vector3 position = PositionLoggedGameObjects[i].transform.position;
                            gazeData.positionInfos[i].xPosition = position.x;
                            gazeData.positionInfos[i].yPosition = position.y;
                            gazeData.positionInfos[i].zPosition = position.z;

                            // Rotation
                            Vector3 rotation = PositionLoggedGameObjects[i].transform.rotation.eulerAngles;
                            gazeData.positionInfos[i].xRotation = rotation.x;
                            gazeData.positionInfos[i].yRotation = rotation.y;
                            gazeData.positionInfos[i].zRotation = rotation.z;

                            // Scale
                            Vector3 scale = PositionLoggedGameObjects[i].transform.lossyScale;
                            gazeData.positionInfos[i].xScale = scale.x;
                            gazeData.positionInfos[i].yScale = scale.y;
                            gazeData.positionInfos[i].zScale = scale.z;
                        }
                    }

                    // Invoke new data event
                    NewDataEvent?.Invoke(gazeData);
                }
            }
        }