Discussion and Support for the OptiTrack, SmartNav and TrackIR brands by NaturalPoint

Streaming Individual Markers

NatNet, VRPN, TrackD, and Plugins

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!
Posts: 7
Joined: Sat Oct 10, 2015 10:01 am

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 );

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.
Posts: 11
Joined: Fri Apr 02, 2010 5:31 am

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

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)


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!
Screenshot 2018-03-05 15.23.42.jpg
Screenshot 2018-03-05 15.23.42.jpg (225.11 KiB) Viewed 511 times
Posts: 2
Joined: Mon Mar 05, 2018 12:18 am

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.
Posts: 2
Joined: Wed Jun 06, 2018 5:20 am

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);

                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;

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

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


Return to OptiTrack Data Streaming