Streaming Individual Markers

NatNet, VRPN, TrackD, and Plugins
Hanowde
Posts: 7
Joined: Sat Oct 10, 2015 10:01 am

Re: Streaming Individual Markers

Post by Hanowde » Sat Oct 31, 2015 12:03 pm

Hello, everyone

I want to do the same too. But i cant find a solution how to read the position of a single Marker from Motive to Unity. Has anyone good idea for my problem?

@heath789 : have your find a solution for your problem?

Thank your!

iko79
Posts: 11
Joined: Fri Apr 02, 2010 5:31 am

Re: Streaming Individual Markers

Post by iko79 » Wed Jul 12, 2017 4:09 am

I realize the thread is inactive for some time, but maybe some folks will find this helpful, regarding Hanowde's question concerning Unity3D, since I also had this question rectently:

There is a very simple way of adding this functionality in the official Optitrack Untiy Plugin (I'm referring to version 1.0.1 here, but I expect you will get this done in future releases in a similar way):

In Assets/OptiTrack/Scripts/OptitrackStreamingClient.cs, there is a method called OnNatNetFrameReceived, where you get NatNetClient.NativeFrameReceivedEventArgs eventArgs as an argument. The class already implements doing most of the marshalling for you, although it is not used by the plugin (yet?), giving you an sFrameOfMocapData struct, which contains the fields OtherMarkersCount and OtherMarkers. I added a list of OptitrackMarkerState to the OptitrackStreamingClient class like this

Code: Select all

private List<OptitrackMarkerState> m_latestOtherMarkerStates = new List<OptitrackMarkerState>();
and added this to the OnNatNetFrameReceived method, just above the code where updating of rigid bodies is done:

Code: Select all

sFrameOfMocapData frame = eventArgs.MarshaledFrame;
//Debug.Log( "labeled: " + frame.LabeledMarkerCount + ", other: " + frame.OtherMarkerCount + ", sets: " + frame.MarkerSetCount );

float[] vec = new float[3 * frame.OtherMarkerCount];
System.Runtime.InteropServices.Marshal.Copy( frame.OtherMarkers, vec, 0, vec.Length );

m_latestOtherMarkerStates.Clear();
for( int i = 0; i < frame.OtherMarkerCount; i++ )
{
    OptitrackMarkerState state = new OptitrackMarkerState();
    state.Position = new Vector3( -vec[i * 3 + 0], vec[i * 3 + 1], vec[i * 3 + 2] );
    //TODO: where do i get the size from?
    state.Size = 0.01f;

    m_latestOtherMarkerStates.Add( state );
    //Debug.Log( "marker #" + i + ": [" + vec[i * 3 + 0] + ", " + vec[i * 3 + 1] + ", " + vec[i * 3 + 2] );
}
Works like a charm for me. You can also go ahead and implement an editor script so you have the markers drawn in the Unity scene view, use OptitrackRigidBodyEditor.cs as a reference, it isn't too hard.

mat_kinotek
Posts: 2
Joined: Mon Mar 05, 2018 12:18 am

Re: Streaming Individual Markers

Post by mat_kinotek » Mon Mar 05, 2018 12:33 am

Hello,
thanks for your code- I'm trying to show the individual markers in unity to better align our assets to the optitrack's rigidbodies. We edited the script following your directions but we get 2 errors in the unity console:

ArgumentNullException: Argument cannot be null.
Parameter name: src
System.Runtime.InteropServices.Marshal.Copy (IntPtr source, System.Single[] destination, Int32 startIndex, Int32 length) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs:191)
OptitrackStreamingClient.OnNatNetFrameReceived (System.Object sender, NaturalPoint.NatNetLib.NativeFrameReceivedEventArgs eventArgs) (at Assets/OptiTrack/Scripts/OptitrackStreamingClient.cs:512)
UnityEngine.Debug:LogException(Exception, Object)
OptitrackStreamingClient:OnNatNetFrameReceived(Object, NativeFrameReceivedEventArgs) (at Assets/OptiTrack/Scripts/OptitrackStreamingClient.cs:603)


and

OptitrackStreamingClient: OnNatNetFrameReceived encountered an exception.
UnityEngine.Debug:LogError(Object, Object)
OptitrackStreamingClient:OnNatNetFrameReceived(Object, NativeFrameReceivedEventArgs) (at Assets/OptiTrack/Scripts/OptitrackStreamingClient.cs:602)


the code is supposed to show x,y,z position for each marker in the consolle, right?
Any hint is really appreciated-
Thank you!
Attachments
Screenshot 2018-03-05 15.23.42.jpg
Screenshot 2018-03-05 15.23.42.jpg (225.11 KiB) Viewed 1061 times

Kopsi
Posts: 2
Joined: Wed Jun 06, 2018 5:20 am

Re: Streaming Individual Markers

Post by Kopsi » Wed Jun 06, 2018 5:25 am

So I had the same problem as you guys and I was able to figure out what caused it.
By getting rid of this line, I didn't get any further errors:

Code: Select all

[...]
 float[] vec = new float[3 * frame.OtherMarkerCount];
            //TODO: Fix this line!
            //System.Runtime.InteropServices.Marshal.Copy(frame.OtherMarkers, vec, 0, vec.Length);
[...]
Sadly, the streaming stopped too, so now I have to figure out the next steps.
Furthermore I have written a getMarkerState method and a script for displaying all unassigned markers, which I can share if anyone needs it.

Kopsi
Posts: 2
Joined: Wed Jun 06, 2018 5:20 am

Re: Streaming Individual Markers

Post by Kopsi » Wed Jun 13, 2018 5:01 am

Okay, I found a solution, that works for me; code below.

The problem was, that the marshalling expected a double or an int value array, but was given a float array. So I changed the arraytype of vec to double and later typecasted them to float for the Vector3 position.
However, I would still get the error, so I figured out, that if I didn't get any unlabeled markers from Motive, my src value would be 0, which throws the exception. As soon as markers were streamed everything worked. By adding a quick check whether there are any unlabeled markers, everything works as intended.

TL;DR: Copy the code below and add it to the OnNatNetFrameReceived method, just above the code where updating of rigid bodies is done (as shown by Iko79 above).

Code: Select all

// Update unlabeled Markers
            sFrameOfMocapData frame = eventArgs.MarshaledFrame;
            Debug.Log( "labeled: " + frame.LabeledMarkerCount + ", other: " + frame.OtherMarkerCount + ", sets: " + frame.MarkerSetCount );
           
            //if no unlabeled Markers are recieved, skip this step
            if (frame.OtherMarkerCount < 1)
            {
                double[] vec = new double[3 * frame.OtherMarkerCount];
                Marshal.Copy(frame.OtherMarkers, vec, 0, vec.Length);

                m_latestOtherMarkerStates.Clear();
                for (int i = 0; i < frame.OtherMarkerCount; i++)
                {
                    OptitrackMarkerState state = new OptitrackMarkerState();
                    state.Position = new Vector3((float)-vec[i * 3 + 0], (float)vec[i * 3 + 1], (float)vec[i * 3 + 2]);

                    state.Size = 0.01f;

                    m_latestOtherMarkerStates.Add(state);
                    Debug.Log("marker #" + i + ": [" + vec[i * 3 + 0] + ", " + vec[i * 3 + 1] + ", " + vec[i * 3 + 2]);
                }

            }

Post Reply