Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update Vector3 array from C++ native plugin

Marshal.Copy() Method only supports a few array types. Now I only know how to copy from IntPtr(pointing to a float array from C++ code) to float[].

IntPtr pvertices = GetVerticesFromCPP();
float[] vertices = new float[nVertices * 3];
Marshal.Copy(pvertices, vertices, 0, nVertices * 3);

But what I really want is a UnityEngine.Vector3[].

Do I need to manually convert float[] to UnityEngine.Vector3[]? Or is there a simpler and faster way that directly do this?

like image 733
landings Avatar asked Oct 20 '25 20:10

landings


1 Answers

Do I need to manually convert float[] to UnityEngine.Vector3[]? Or is there a simpler and faster way that directly do this?

Yes, you have to do that manually but there is a better way to do this.

I will assume that you need to modify a Vector3 on the native side then return the result. There is no need to use float array for this. Just create a Vector3 struct on the C++ side then use pointer to pass it between C++ and C#. Do not return the Vector3 array from C++, create it on the C# side, then pass it to the C++ function to modify and apply the changes to the argument.

C++:

This requires that you enable the unsafe keyword in Unity.

struct Vector3
{
     float x;
     float y;
     float z;
};

then your function:

extern "C" void UpdateVectorArray(Vector3* vecArray, int vecSize)
{
    for(int i = 0; i < vecSize; ++i)
    {
        //Simply modify each Vector reference
        Vector3 &vec = vecArray[i];
        vec.x = 11;
        vec.y = 20;
        vec.z = 55;
    }
}

C#:

[DllImport("Plugin Name")]
static unsafe extern void UpdateVectorArray(Vector3* vecArray, int vecSize);


void UpdateVectorArray(Vector3[] vecArray)
{
    unsafe
    {
        //Pin array then send to C++
        fixed (Vector3* vecPtr = vecArray)
        {
            UpdateVectorArray(vecPtr, vecArray.Length);
        }
    }
}

Usage:

Get vertices from model, send to C++ and modify it the re-assign the modified mesh:

void Start()
{
    Mesh mesh = GetComponent<MeshFilter>().mesh;

    Vector3[] vertices = mesh.vertices;
    UpdateVectorArray(vertices);

    //Re-assign the modified mesh
    mesh.vertices = vertices;
    mesh.RecalculateBounds();
}

To avoid using the unsafe keyword in Unity use the [In, Out] attribute.

[DllImport("Plugin Name")]
static extern void UpdateVectorArray([In, Out] Vector3[] vecArray, int vecSize);

void Start()
{
    Mesh mesh = GetComponent<MeshFilter>().mesh;

    Vector3[] vertices = mesh.vertices;
    UpdateVectorArray(vertices, vertices.Length);

    mesh.vertices = vertices;
    mesh.RecalculateBounds();
}

The C++ side remains the-same. You can also use the GCHandle to pin the array and avoid using the unsafe keyword but the unsafe keyword solution is better and faster.

like image 129
Programmer Avatar answered Oct 23 '25 11:10

Programmer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!