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?
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.