示例#1
0
    //Get marker IDs for cue for cue stick
    private void getCueMarkers()
    {
        OptitrackRigidBodyState     rbState = StreamingClient.GetLatestRigidBodyState(RigidBodyId); //access rigidbody
        List <OptitrackMarkerState> markers = new List <OptitrackMarkerState>();                    //initialize list of marker objects from rigidbody

        markers = StreamingClient.GetLatestMarkerStates();                                          //get objects of all markers from rigidbody

        SortedList <float, int> sortedMarkers = new SortedList <float, int>();

        for (int j = 0; j < markers.Count; j++)
        {
            OptitrackMarkerState m = markers[j];
            int     mID            = m.Id;
            Vector3 pos            = m.Position;
            Debug.Log(pos.ToString("f4"));
            Debug.Log(mID);
            float zpos = pos.z;

            sortedMarkers.Add(zpos, mID);
        }
        backID1   = sortedMarkers.Values[1];
        backID2   = sortedMarkers.Values[2];
        frontID1  = sortedMarkers.Values[4];
        frontID2  = sortedMarkers.Values[5];
        markerIDs = false;

        Debug.Log("bid  " + backID1);
        Debug.Log("bid2  " + backID2);
        Debug.Log(frontID1);
        Debug.Log("fid2  " + frontID2);
    }
示例#2
0
    //Function to get IDs of markers in corresponding pockets for calibration
    private void getCalMarkerId()
    {
        OptitrackRigidBodyState     rbState = StreamingClient.GetLatestRigidBodyState(RigidBodyId); //access rigidbody
        List <OptitrackMarkerState> markers = new List <OptitrackMarkerState>();                    //initialize list of marker objects from rigidbody

        markers = StreamingClient.GetLatestMarkerStates();                                          //get objects of all markers from rigidbody
        List <int> idList = new List <int>();

        float maxz = -1000f;
        int   idz  = -1;
        float maxx = -1000f;
        int   idx  = -1;

        for (int j = 0; j < markers.Count; j++)
        {
            OptitrackMarkerState m = markers[j];
            int     mID            = m.Id;
            Vector3 pos            = m.Position;
            idList.Add(mID);

            // one corner is placed further to the positive z (right)
            if (pos.x > maxx)
            {
                maxx = pos.x;
                idx  = mID;
            }
            // one marker is placed further to the negative x (toward end of table)
            if (pos.z > maxz)
            {
                maxz = pos.z;
                idz  = mID;
            }
        }
        idList.Remove(idz);
        idList.Remove(idx);

        //store marker IDs
        corner1ID = idList[0]; //by elimination we get the 3rd corner
        corner2ID = idx;
        corner3ID = idz;
    }
示例#3
0
    /// <summary>Get the most recently received state for streamed markers.</summary>
    /// <returns>The most recent available marker states, or null if none available.</returns>
    public List <OptitrackMarkerState> GetLatestMarkerStates()
    {
        List <OptitrackMarkerState> markerStates = new List <OptitrackMarkerState>();

        lock (m_frameDataUpdateLock)
        {
            foreach (KeyValuePair <Int32, OptitrackMarkerState> markerEntry in m_latestMarkerStates)
            {
                OptitrackMarkerState newMarkerState = new OptitrackMarkerState
                {
                    Position = markerEntry.Value.Position,
                    Labeled  = markerEntry.Value.Labeled,
                    Size     = markerEntry.Value.Size,
                    Id       = markerEntry.Value.Id
                };
                markerStates.Add(newMarkerState);
            }
        }

        return(markerStates);
    }
示例#4
0
    /// <summary>
    /// Returns the <see cref="OptitrackMarkerState"/> corresponding to the provided <paramref name="markerId"/>.
    /// If the requested state object does not exist yet, it will initialize and return a newly-created one.
    /// </summary>
    /// <remarks>Makes the assumption that the lock on <see cref="m_frameDataUpdateLock"/> is already held.</remarks>
    /// <param name="markerId">The ID of the rigid body for which to retrieve the corresponding state.</param>
    /// <returns>The existing state object, or a newly created one if necessary.</returns>
    private OptitrackMarkerState GetOrCreateMarkerState(Int32 markerId)
    {
        OptitrackMarkerState returnedState = null;

        if (m_latestMarkerStates.ContainsKey(markerId))
        {
            returnedState = m_latestMarkerStates[markerId];
        }
        else
        {
            OptitrackMarkerState newMarkerState = new OptitrackMarkerState
            {
                Position = new Vector3(),
            };

            m_latestMarkerStates[markerId] = newMarkerState;

            returnedState = newMarkerState;
        }

        return(returnedState);
    }
    /// <summary>
    /// Draws marker visualizations in the editor viewport for any selected OptitrackRigidBody component.
    /// </summary>
    void OnSceneGUI()
    {
        OptitrackRigidBody rb = target as OptitrackRigidBody;

        if (!rb || rb.StreamingClient == null)
        {
            return;
        }

        rb.StreamingClient._EnterFrameDataUpdateLock();

        try
        {
            OptitrackRigidBodyState rbState = rb.StreamingClient.GetLatestRigidBodyState(rb.RigidBodyId);

            if (rbState != null && rbState.Markers != null)
            {
                for (int iMarker = 0; iMarker < rbState.Markers.Count; ++iMarker)
                {
                    OptitrackMarkerState marker = rbState.Markers[iMarker];
                    Vector3 markerPos           = marker.Position;

                    if (rb.transform.parent)
                    {
                        markerPos = rb.transform.parent.TransformPoint(markerPos);
                    }

                    Matrix4x4 markerTransform = Matrix4x4.TRS(markerPos, Quaternion.identity, new Vector3(marker.Size, marker.Size, marker.Size));
                    Graphics.DrawMesh(m_markerMesh, markerTransform, m_markerMaterial, 0, camera: null, submeshIndex: 0, properties: null, castShadows: false, receiveShadows: false);
                }
            }
        }
        finally
        {
            rb.StreamingClient._ExitFrameDataUpdateLock();
        }
    }
示例#6
0
    /// <summary>
    /// Event handler for NatNet frame delivery. Updates our simplified state representations.
    /// NOTE: This executes in the context of the NatNetLib network service thread!
    /// </summary>
    /// <remarks>
    /// Because the <see cref="sFrameOfMocapData"/> type is expensive to marshal, we instead utilize the
    /// <see cref="NatNetClient.NativeFrameReceivedEventArgs.NativeFramePointer"/>, treating it as as opaque, and
    /// passing it to some helper "accessor" functions to retrieve the subset of data we care about, using only
    /// blittable types which do not cause any garbage to be allocated.
    /// </remarks>
    /// <param name="sender"></param>
    /// <param name="eventArgs"></param>
    private void OnNatNetFrameReceived(object sender, NatNetClient.NativeFrameReceivedEventArgs eventArgs)
    {
        // In the event of contention, drop the frame being delivered and return immediately.
        // We don't want to stall NatNetLib's internal network service thread.
        if (!Monitor.TryEnter(m_frameDataUpdateLock))
        {
            return;
        }

        try
        {
            // Update health markers.
            m_receivedFrameSinceConnect = true;
            Interlocked.Exchange(ref m_lastFrameDeliveryTimestamp.m_ticks, OptitrackHiResTimer.Now().m_ticks);

            // Process received frame.
            IntPtr      pFrame = eventArgs.NativeFramePointer;
            NatNetError result = NatNetError.NatNetError_OK;

            // Update rigid bodies.
            Int32 frameRbCount;
            result = NaturalPoint.NatNetLib.NativeMethods.NatNet_Frame_GetRigidBodyCount(pFrame, out frameRbCount);
            NatNetException.ThrowIfNotOK(result, "NatNet_Frame_GetRigidBodyCount failed.");

            for (int rbIdx = 0; rbIdx < frameRbCount; ++rbIdx)
            {
                sRigidBodyData rbData = new sRigidBodyData();
                result = NaturalPoint.NatNetLib.NativeMethods.NatNet_Frame_GetRigidBody(pFrame, rbIdx, out rbData);
                NatNetException.ThrowIfNotOK(result, "NatNet_Frame_GetRigidBody failed.");

                bool bTrackedThisFrame = (rbData.Params & 0x01) != 0;
                if (bTrackedThisFrame == false)
                {
                    continue;
                }

                // Ensure we have a state corresponding to this rigid body ID.
                OptitrackRigidBodyState rbState = GetOrCreateRigidBodyState(rbData.Id);

                rbState.DeliveryTimestamp = OptitrackHiResTimer.Now();

                // Flip coordinate handedness from right to left by inverting X and W.
                rbState.Pose.Position    = new Vector3(-rbData.X, rbData.Y, rbData.Z);
                rbState.Pose.Orientation = new Quaternion(-rbData.QX, rbData.QY, rbData.QZ, -rbData.QW);
            }

            // Update skeletons.
            Int32 frameSkeletonCount;
            result = NaturalPoint.NatNetLib.NativeMethods.NatNet_Frame_GetSkeletonCount(pFrame, out frameSkeletonCount);
            NatNetException.ThrowIfNotOK(result, "NatNet_Frame_GetSkeletonCount failed.");

            for (int skelIdx = 0; skelIdx < frameSkeletonCount; ++skelIdx)
            {
                Int32 skeletonId;
                result = NaturalPoint.NatNetLib.NativeMethods.NatNet_Frame_Skeleton_GetId(pFrame, skelIdx, out skeletonId);
                NatNetException.ThrowIfNotOK(result, "NatNet_Frame_Skeleton_GetId failed.");

                // Ensure we have a state corresponding to this skeleton ID.
                OptitrackSkeletonState skelState = GetOrCreateSkeletonState(skeletonId);

                // Enumerate this skeleton's bone rigid bodies.
                Int32 skelRbCount;
                result = NaturalPoint.NatNetLib.NativeMethods.NatNet_Frame_Skeleton_GetRigidBodyCount(pFrame, skelIdx, out skelRbCount);
                NatNetException.ThrowIfNotOK(result, "NatNet_Frame_Skeleton_GetRigidBodyCount failed.");

                for (int boneIdx = 0; boneIdx < skelRbCount; ++boneIdx)
                {
                    sRigidBodyData boneData = new sRigidBodyData();
                    result = NaturalPoint.NatNetLib.NativeMethods.NatNet_Frame_Skeleton_GetRigidBody(pFrame, skelIdx, boneIdx, out boneData);
                    NatNetException.ThrowIfNotOK(result, "NatNet_Frame_Skeleton_GetRigidBody failed.");

                    // In the context of frame data (unlike in the definition data), this ID value is a
                    // packed composite of both the asset/entity (skeleton) ID and member (bone) ID.
                    Int32 boneSkelId, boneId;
                    NaturalPoint.NatNetLib.NativeMethods.NatNet_DecodeID(boneData.Id, out boneSkelId, out boneId);

                    // TODO: Could pre-populate this map when the definitions are retrieved.
                    // Should never allocate after the first frame, at least.
                    if (skelState.BonePoses.ContainsKey(boneId) == false)
                    {
                        skelState.BonePoses[boneId] = new OptitrackPose();
                    }

                    // Flip coordinate handedness from right to left by inverting X and W.
                    skelState.BonePoses[boneId].Position    = new Vector3(-boneData.X, boneData.Y, boneData.Z);
                    skelState.BonePoses[boneId].Orientation = new Quaternion(-boneData.QX, boneData.QY, boneData.QZ, -boneData.QW);
                }
            }

            // Update markers
            Int32 MarkerCount;
            result = NaturalPoint.NatNetLib.NativeMethods.NatNet_Frame_GetLabeledMarkerCount(pFrame, out MarkerCount);
            NatNetException.ThrowIfNotOK(result, "NatNet_Frame_GetSkeletonCount failed.");

            m_latestMarkerStates.Clear();

            for (int markerIdx = 0; markerIdx < MarkerCount; ++markerIdx)
            {
                sMarker marker = new sMarker();
                result = NaturalPoint.NatNetLib.NativeMethods.NatNet_Frame_GetLabeledMarker(pFrame, markerIdx, out marker);
                NatNetException.ThrowIfNotOK(result, "NatNet_Frame_GetLabeledMarker failed.");

                // Flip coordinate handedness
                Vector3 markerPos = new Vector3(-marker.X, marker.Y, marker.Z);
                OptitrackMarkerState markerState = GetOrCreateMarkerState(marker.Id);
                markerState.Position = markerPos;
                markerState.Size     = marker.Size;
                markerState.Labeled  = (marker.Params & 0x10) == 0;
                markerState.Id       = marker.Id;
            }
        }
        catch (Exception ex)
        {
            Debug.LogError(GetType().FullName + ": OnNatNetFrameReceived encountered an exception.", this);
            Debug.LogException(ex, this);
        }
        finally
        {
            Monitor.Exit(m_frameDataUpdateLock);
        }
    }
示例#7
0
    void calibrateTable()
    {
        numCalSamples++;

        //Get marker positions
        OptitrackRigidBodyState     rbState      = StreamingClient.GetLatestRigidBodyState(RigidBodyId); //access rigidbody
        List <OptitrackMarkerState> markerStates = new List <OptitrackMarkerState>();                    //initialize list of marker objects from rigidbody

        markerStates = StreamingClient.GetLatestMarkerStates();                                          //get objects of all markers from rigidbody

        //loop through all markers
        for (int idx = 0; idx < markerStates.Count; idx++)
        {
            OptitrackMarkerState marker = markerStates[idx];
            int mID = marker.Id;
            if (mID == corner1ID)
            {
                C1.Add(marker.Position);
            }
            if (mID == corner2ID)
            {
                C2.Add(marker.Position);
            }
            if (mID == corner3ID)
            {
                C3.Add(marker.Position);
            }
        }

        //stop calibratiing after 100 samples and print results
        if (numCalSamples > 100)
        {
            Vector3 avgC1 = Experiment.AverageVec(C1);
            Vector3 avgC2 = Experiment.AverageVec(C2);
            Vector3 avgC3 = Experiment.AverageVec(C3);

            //derive C2 based on equalateral right triangle
            float   length    = (avgC2 - avgC1).magnitude;
            Vector3 direction = Quaternion.Euler(0, -90f, 0) * (avgC2 - avgC1).normalized;
            Vector3 derivedC3 = avgC1 + length * direction;

            //Unity Corner Positions
            PlayerPrefs.SetFloat("Ucorner1x", Experiment.corner1.position.x);
            PlayerPrefs.SetFloat("Ucorner1y", Experiment.corner1.position.y);
            PlayerPrefs.SetFloat("Ucorner1z", Experiment.corner1.position.z);
            PlayerPrefs.SetFloat("Ucorner2x", Experiment.corner2.position.x);
            PlayerPrefs.SetFloat("Ucorner2y", Experiment.corner2.position.y);
            PlayerPrefs.SetFloat("Ucorner2z", Experiment.corner2.position.z);
            PlayerPrefs.SetFloat("Ucorner3x", Experiment.corner3.position.x);
            PlayerPrefs.SetFloat("Ucorner3y", Experiment.corner3.position.y);
            PlayerPrefs.SetFloat("Ucorner3z", Experiment.corner3.position.z);

            //Optitrack Corner Positions
            PlayerPrefs.SetFloat("Ocorner1x", avgC1.x);
            PlayerPrefs.SetFloat("Ocorner1y", avgC1.y);
            PlayerPrefs.SetFloat("Ocorner1z", avgC1.z);
            PlayerPrefs.SetFloat("Ocorner2x", avgC2.x);
            PlayerPrefs.SetFloat("Ocorner2y", avgC2.y);
            PlayerPrefs.SetFloat("Ocorner2z", avgC2.z);
            PlayerPrefs.SetFloat("Ocorner3x", derivedC3.x);
            PlayerPrefs.SetFloat("Ocorner3y", derivedC3.y);
            PlayerPrefs.SetFloat("Ocorner3z", derivedC3.z);

            //Cue ball starting position in unity
            PlayerPrefs.SetFloat("Ocuex", avgC3.x);
            PlayerPrefs.SetFloat("Ocuey", avgC3.y);
            PlayerPrefs.SetFloat("Ocuez", avgC3.z);
            //Experiment.optiPocketPoints = new float[,] { { avgC1.x, avgC2.x, avgC3.x }, { avgC1.z, avgC2.z, avgC3.z }, { 1f, 1f, 1f } };

            if (test)
            {
                Debug.Log("corner1ID = " + corner1ID);
                Debug.Log("corner1 position = " + avgC1.ToString("f4"));
                Debug.Log("corner2ID = " + corner2ID);
                Debug.Log("corner2 position = " + avgC2.ToString("f4"));
                Debug.Log("derived C3    " + derivedC3.ToString("f4"));
                Debug.Log("corner3ID = " + corner3ID);
                Debug.Log("corner3 position = " + avgC3.ToString("f4"));
                Debug.Log("Unity positions");
                Debug.Log("corner1" + Experiment.corner1.position.ToString("f4"));
                Debug.Log("corner2" + Experiment.corner2.position.ToString("f4"));
                Debug.Log("corner3" + Experiment.corner3.position.ToString("f4"));

                float optiPocketDist  = (avgC1 - avgC2).magnitude;
                float unityPocketDist = (Experiment.corner1.position - Experiment.corner2.position).magnitude;
                PlayerPrefs.SetFloat("optiToUnity", unityPocketDist / optiPocketDist);

                test = false;
            }
        }
    }
示例#8
0
    /*
     *  Method to update the position of the cue rigidbody every by reading the data from the Optitrack client
     */
    void UpdatePose()
    {
        #region Cue State Variables

        OptitrackRigidBodyState rbState = StreamingClient.GetLatestRigidBodyState(RigidBodyId); //access rigidbody
        Vector3 OfrontPos = new Vector3();                                                      //optitrack front position
        Vector3 ObackPos  = new Vector3();                                                      //optitrack back position
        List <OptitrackMarkerState> markerStates = new List <OptitrackMarkerState>();           //initialize list of marker objects from rigidbody
        List <Vector3> markerPositions           = new List <Vector3>();                        //list of all cue marker positions

        #endregion


        if (rbState != null)
        {
            //Get marker positions
            markerStates = StreamingClient.GetLatestMarkerStates(); //get objects of all markers from rigidbody

            #region Check if valid Optitrack markers
            //if not all markers are tracked, make cue stick invisible
            if (markerStates.Count < 4)
            {
                Experiment.cuestickMesh.enabled = false;
                //Debug.Log(markerStates.Count);
                cuePos = prevPos;
                return;
            }
            Experiment.cuestickMesh.enabled = true;

            #endregion

            #region Access & store marker poitions
            //Loop through markers
            for (int idx = 0; idx < markerStates.Count; idx++)
            {
                OptitrackMarkerState marker = markerStates[idx];
                int     markerID            = marker.Id;
                Vector3 pos = marker.Position;
                markerPositions.Add(marker.Position);
            }

            #endregion

            #region Derive Unity cue position
            IEnumerable <Vector3> sorted = markerPositions.OrderBy(v => v.z); //sort marker positions by z position
            OfrontPos = (sorted.ElementAt(3) + sorted.ElementAt(2)) / 2;
            Vector3 dif = OfrontPos - sorted.ElementAt(1);
            ObackPos = sorted.ElementAt(0) + dif;

            //Translate optitrack positions to unity using helper methods ( [Xo, Zo, 1] * M = [Xu, Zu, 1])
            float[,] frontMatrix = new float[, ] {
                { OfrontPos.x }, { OfrontPos.z }, { 1 }
            };
            float[,] backMatrix = new float[, ] {
                { ObackPos.x }, { ObackPos.z }, { 1 }
            };
            float[,] frontU = Experiment.MultiplyMatrix(Experiment.M, frontMatrix);
            float[,] backU  = Experiment.MultiplyMatrix(Experiment.M, backMatrix);
            Vector3 backPos  = new Vector3(backU[0, 0], ObackPos.y * Experiment.yratio, backU[1, 0]);
            Vector3 frontPos = new Vector3(frontU[0, 0], OfrontPos.y * Experiment.yratio, frontU[1, 0]);

            //cue position is front position plus projected vector
            Vector3 direction = (frontPos - backPos).normalized;
            cuePos = frontPos + (direction * PlayerPrefs.GetFloat("tip_marker1") * PlayerPrefs.GetFloat("cmToUnity"));

            //limit cuetip height to table surface height
            if (cuePos.y < Experiment.corner1.position.y)
            {
                cuePos = new Vector3(cuePos.x, Experiment.corner1.position.y, cuePos.z);
            }

            #endregion

            #region Calculate cue velocity
            //calculate velocity
            cueVelocity = (cuePos - prevPos) / Time.fixedDeltaTime;
            if (cueVelocity.magnitude > 3)
            {
                cueVelocity = 3f * cueVelocity.normalized;
            }
            VelocityList.Add(cueVelocity);
            //avgVelocity = AverageVelocity(VelocityList, Experiment.numVelocitiesAverage);
            prevPos = cuePos;

            #endregion

            //move cue rigidbody to updated position
            Experiment.cueFront.transform.position = cuePos;
            //get forward direction by lookng at forwrd position from actual optitrack position (could also do with transformed positions)
            Experiment.cueFront.transform.rotation = Quaternion.LookRotation(frontPos - backPos) * Quaternion.Euler(0f, 0f, 0f);
        }
    }