4.2. C++ API Reference

4.2.1. Native.h

This is the central file with all exported functions that are callable from C#. These are the ‘entry points’. As this is a library we do not have a main(), however we have the Initialize() function as a replacement. Unity also triggers the functions UnityPluginLoad() and UnityPluginUnload() at the start and end. These are called first and last, notably Initialize() is called after UnityPluginLoad().

The two important functions for the lifecycle of a mesh are InitializeMesh() and DisposeMesh(). These are called whenever a LibiglMesh is instaniated or destroyed in Unity. This is where the C++ owned memory is allocated and deleted.

To make these functions callable from C# we must put the declarations inside an extern "C" scope, as well as prepending the UNITY_INTERFACE_EXPORT to the declaration. This is because C# and C++ use different default calling conventions, see x86 Calling Conventions specifically __stdcall. This also is different for every platform, but luckily the IUnityInterface header handles this for us if we use this macro.

Note that the implementations of the defined functions are split across several cpp files, as indicated in the code. This is done so we have one central place where we have all the exported functions that are callable from C#.

Functions

void Initialize(StringCallback debugCallback, StringCallback debugWarningCallback, StringCallback debugErrorCallback)

Called just before the first function is called from this library. Use this to pass initial data from C#

See

C# Native.Initialize()

Parameters
  • debugCallback: A C# delegate (function pointer) to print to the Unity Debug.Log

MeshState *InitializeMesh(const UMeshDataNative data, const char *name)

Called when a new mesh is loaded. Initialize global variables, do pre-calculations for a mesh

Return

A pointer to the C++ state for this mesh

Parameters
  • data: The Unity MeshData

  • name: Name of the mesh

void DisposeMesh(MeshState *state)

Disposes all C++ state tied to a mesh properly

void UnityPluginLoad(IUnityInterfaces *unityInterfaces)

Called when the plugin is loaded, this can be after/before Initialize()

Declared in IUnityInterface.h

Parameters
  • unityInterfaces: Unity class for accessing minimal Unity functionality exposed to C++ Plugins

void UnityPluginUnload()

Called when the plugin is unloaded, clean up here Declared in IUnityInterface.h

void ApplyDirty(MeshState *state, const UMeshDataNative data, const unsigned int visibleSelectionMask)

Propagates changes from the libigl mesh (Eigen matrices) to the Unity NativeArrays so we can apply it to the mesh in C#. This functions also recalculated selection sizes, colors based on the selection. This should be called once after apply all wanted changes to the libigl mesh. This function itself does not modify the Unity mesh, see UMeshData.cs

Parameters
  • data: Pointers to the Unity Mesh Data, where to apply changes to.

  • visibleSelectionMask: Selections which are currently visible, will ignore changes to invisible selections.

void ReadOFF(const char *path, const bool setCenter, const bool normalizeScale, const float scale, void *&VPtr, int &VSize, void *&NPtr, int &NSize, void *&FPtr, int &FSize, bool calculateNormalsIfEmpty = false)

Reads an .off file into row major Eigen matrices, these can then be mapped by a NativeArray in C#. Matrices are allocated with new and must be deleted manually (e.g. by NativeArray<T>.Dispose() or converting with Allocator.Temp).

Parameters
  • path: The asset path, absolute or relative to the project root e.g. AssetImportContext.assetPath or “Assets/model.off”

  • setCenter: Set the center as the mean vertex, see ApplyScale

  • normalizeScale: Whether to normalize the y-scale to 1

  • scale: Scale the mesh by this factor after normalization

  • [out] VPtr: Pointer to the first element of the Vertex matrix

  • [out] VSize: Number of vertices, rows of V

  • [out] NPtr: Pointer to the first element of the Normals matrix

  • [out] NSize: Number of normals, usually equal to VSize

  • [out] FPtr: Pointer to the first element of the Face/Indices matrix, one row is a triangle

  • [out] FSize: Number of faces, rows of F

  • calculateNormalsIfEmpty: Calculate per vertex normals, if no normals are present in the .off file

void TranslateAllVertices(MeshState *state, Vector3 value)

Debug function to simply translate all vertices by the value.

void TranslateSelection(MeshState *state, Vector3 value, unsigned int maskId = -1)

Translate vertices in specific selections.

Parameters
  • value: displacement in local space

  • maskId: Which selections to transform as a bitmask

void TransformSelection(MeshState *state, Vector3 translation, float scale, Quaternion rotation, Vector3 pivot, unsigned int maskId = -1)

Transform the selected vertices in place. Translate + Rotate + Scale in this order. Rotation is currently only around the origin of the mesh

Parameters
  • maskId: Which selections to transform

void Harmonic(MeshState *state, unsigned int boundaryMask = -1, bool showDeformationField = true)

Run the igl::harmonic biharmonic deformation on the mesh with provided fixed boundary conditions.

Remark

From libigl Tutorial 401, https://libigl.github.io/tutorial/#biharmonic-deformation

Parameters
  • boundaryMask: Which selections to use as the boundary

  • showDeformationField: Whether to show the deformation field, see libigl tutorial

void Arap(MeshState *state, unsigned int boundaryMask = -1)

Run the igl::arap As-Rigid-As-Possible deformation on the mesh with the provided fixed boundary conditions.

Remark

From libigl Tutorial 405, https://libigl.github.io/tutorial/#as-rigid-as-possible

Parameters
  • boundaryMask: Which selections to use as the boundary

void ResetV(MeshState *state)

Reset the vertices to their initial position V0 (set when loading the mesh).

void SelectSphere(MeshState *state, Vector3 position, float radius, int selectionId = 0, unsigned int selectionMode = SelectionMode::Add)

Modify the selection inside a sphere.

Parameters
  • position: Center of the sphere in local space

  • radius: Radius of the sphere in local space

  • selectionId: Which selection to modify

  • selectionMode: How to change the selection, use SelectionMode constants.

unsigned int GetSelectionMaskSphere(MeshState *state, Vector3 position, float radius)

Return

A mask of all selections partially inside the sphere (based on if a vertex is inside).

Parameters
  • position: Center of the sphere in local space

  • radius: Radius of the sphere in local space

Vector3 GetSelectionCenter(MeshState *state, unsigned int maskId)

Return

The mean vertex of the specified selections

void ClearSelectionMask(MeshState *state, unsigned int maskId = -1)

Resets a particular selections, can clear multiple selections at once.

Parameters
  • maskId: Which selections to clear as a bitmask

void SetColorSingleByMask(MeshState *state, unsigned int maskId = -1, int colorId = 0)

Naive SetColorByMask. Show all selections in the mask in the same color.

Parameters
  • maskId: Which selections to show in the color

  • colorId: Which color to use, see Color::GetColorById

void SetColorByMask(MeshState *state, unsigned int maskId = -1)

Set the vertex colors based on a bitmask of visible selections.

Parameters
  • maskId: Which selections to show

Variables

IUnityInterfaces *s_IUnityInterfaces

Access to the Unity interfaces, currently not used.

4.2.2. InterfaceTypes.h

This file includes all the types that are shared between C# and C++. These are declared once in both languages and if one if modified the other must also be updated. In C# this corresponds to the classes with the attribute [StructLayout(LayoutKind.Sequential)]. The MeshState is also an interface type but has its own file.

Note

UNITY_INTERFACE_EXPORT is a macro provided by Unity in external/Unity/IUnityInterface.h, which allows the function to be callable from C# (given it is within an extern "C" clause)

struct Vector3
#include <InterfaceTypes.h>

The Unity Vector3 with functonality for converting to/from Eigen::Vector3f (float).

Public Functions

Vector3() = default
Vector3(float x, float y, float z)
Vector3(Eigen::Vector3f value)
Eigen::Vector3f AsEigen() const
Eigen::RowVector3f AsEigenRow() const

Public Members

float x
float y
float z

Public Static Functions

Vector3 Zero()
struct Quaternion
#include <InterfaceTypes.h>

The Unity Quaternion with functonality for converting to/from Eigen::Quaternionf (float).

Beware: Unity and Eigen have different conventions for ordering the values.

Public Functions

Quaternion() = default
Quaternion(float x, float y, float z, float w)
Quaternion(Eigen::Quaternionf &q)
Eigen::Quaternionf AsEigen() const

Warning

Eigen has a different ordering of the values, handled safely by this function. We cannot simply reinterpret the bits.

Public Members

float x
float y
float z
float w

Public Static Functions

Quaternion Identity()
struct DirtyFlag
#include <InterfaceTypes.h>

Marks which data has changed in UMeshDataNative as a bitmask

Public Static Attributes

const unsigned int None = 0
const unsigned int VDirty = 1
const unsigned int NDirty = 2
const unsigned int CDirty = 4
const unsigned int UVDirty = 8
const unsigned int FDirty = 16
const unsigned int DontComputeNormals = 32

Don’t recaluclate normals when VDirty is set. NDirty overrides this.

const unsigned int DontComputeBounds = 64

Don’t recalculate bounds when VDirty is set. Bounds are used for occlusion culling.

const unsigned int DontComputeColorsBySelection = 128

Don’t recompute colors if a visible selection has changed.

const unsigned int VDirtyExclBoundary = 256

Use this when the vertex positions have changed, but the boundary conditions are unaffected. VDirty overrides this.

const unsigned int All = (unsigned int)-1 - DontComputeNormals - DontComputeBounds - DontComputeColorsBySelection
struct UMeshDataNative
#include <InterfaceTypes.h>

Stores all pointers to the MeshData arrays.

Usually this should be as a const parameter.

Public Members

float *VPtr
float *NPtr
float *CPtr
float *UVPtr
int *FPtr
int VSize
int FSize
struct SelectionMode
#include <InterfaceTypes.h>

Constants related to how a select operation modifies the current selection.

Public Static Attributes

const unsigned int Add = 0
const unsigned int Subtract = 1
const unsigned int Toggle = 2

4.2.3. NativeCallbacks.h

Defines

STR(message)

Macro to easily concatenate strings using stringstream, use the operator<<

STR("My value: " << 123)

LOG(message)

Macro to easily and safely print to the Unity Debug.Log, disabled in release. Uses STR.

LOG("My value: " << 123)

LOGWARN(message)

Call Unity Debug.LogWarning safely. Uses STR.

LOGERR(message)

Call Unity Debug.LogError safely. Uses STR.

Typedefs

typedef void (*StringCallback)(const char *message)

Function pointer to a C# delegate: void MyFct(string message)

Note

C# delegates are fixed by default, so we do not have to worry about these pointers becoming invalid due to the Garbage Collector.

Variables

StringCallback DebugLog

Print to the Unity Debug.Log. Check that the function pointer is not null before using

if (DebugLog) DebugLog("Hello");

This is what the LOG macro does, use that instead.

See

Callbacks like this are set in Initialize and reset to nullptr in UnityPluginUnload

StringCallback DebugLogWarning
StringCallback DebugLogError

4.2.4. Deform.h

This is where the deformations are as well as other functions which manipulate the vertices. This (the .cpp) is a good place to start for how to implement your own deformation.

Functions

bool UpdateBoundary(MeshState *state, unsigned int boundaryMask)

Recalculates the boundary state->Native->Boundary MeshStateNative.Boundary if the relevant selections have changed

Return

True if boundary has changed

Parameters
  • boundaryMask: The current mask of selections part of the boundary

bool UpdateBoundaryConditions(MeshState *state)

Recalculates the boundary conditions state->Native->BoundaryConditions MeshStateNative.BoundaryConditions for Harmonic and Arap

Return

True if the boundary conditions have changed

4.2.5. MeshState.h

This is the shared state between C++/C# and changes in one must be applied to the other. If the two structs do not match exactly problems arise with reading/writing to the wrong memory.

struct MeshState
#include <MeshState.h>

Stores all data related to a specific mesh. Members are shared between native(C++) and managed(C#). Some members point to native only or managed only and are depicted as void*

Public Functions

MeshState(UMeshDataNative udata)

Initialise the shared state from a Unity mesh

Parameters
  • udata: All data required to create the state

~MeshState()

This is where all C++ allocated memory for a mesh is deleted.

Public Members

unsigned int DirtyState = {DirtyFlag::None}

Tells us what has changed with the mesh using the DirtyFlag constants

unsigned int DirtySelections = {0}

Tells us which selections have been modified, as a bitmask. Each bit represents one selection.

unsigned int DirtySelectionsResized = {0}

Less stricter version than DirtySelections, where we only consider a selection dirty if the selected vertices size changes, see SSizes.

Eigen::MatrixXf *V

The vertex matrix in column major with dimensions VSize x 3. Stores position for each vertex, one row represents one vertex.

Eigen::MatrixXf *N

The normals matrix in column major with dimensions VSize x 3. Stores the normal for each vertex.

Eigen::MatrixXf *C

The rgba color matrix in column major with dimensions VSize x 4. Stores the color for each vertex.

Eigen::MatrixXf *UV

The UV0 matrix in column major with dimensions VSize x 2. Stores the 2D uv coordinate for each vertex.

Eigen::MatrixXi *F

The Face/Indices matrix in column major with dimensions FSize x 3. Stores the vertex indices for each face/triangle, one row represents one face.

int VSize = {0}

Number of vertices, columns in V

int FSize = {0}

Number of faces, columns in F

Eigen::VectorXi *S

The selection vector, stores the selection state for each vertex. We store one uint per vertex. The selection is represented as a bitmask, with each bit indicating if the vertex is in that selection or not. So there are max 32 selections (32 bits)

unsigned int SSize = {1}

Amount of selections that are in use

unsigned int *SSizes

uint[32], number of vertices selected per selection. Stored as a pointer so we can easily share this with C#.

unsigned int SSizesAll = {0}

Total vertices selected

MeshStateNative *Native

Native only state, a void* in C#

4.2.6. MeshStateNative.h

This contains mesh specific data only used in C++, e.g. pre-calculations.

struct MeshStateNative
#include <MeshStateNative.h>

Contains all variables that are only used in C++ for a specific mesh. We use one MeshStateNative per mesh.

Public Functions

MeshStateNative(Eigen::MatrixXf *V)
~MeshStateNative()

Public Members

Eigen::VectorXi Boundary = {Eigen::VectorXi::Zero(0)}

Vertices part of the boundary. Has a variable length.

Note

Evaluated in a lazy manner.

Eigen::MatrixXf BoundaryConditions = {Eigen::VectorXf::Zero(0)}

Positions of vertices in the Boundary (rows correspond). Has a variable length, the same as Boundary.

Note

Evaluated in a lazy manner.

unsigned int BoundaryMask = {0}

The selections currently used for the Boundary.

Note

Evaluated in a lazy manner.

unsigned int DirtySelectionsForBoundary = {0}

Selections that have changed since the last time the Boundary was calculated. Used for lazy recalculation of Boundary.

bool DirtyBoundaryConditions = {true}

Whether the boundary conditions have changed since the last time they were calculated. Used for lazy recalculation of BoundaryConditions.

Eigen::MatrixXf *V0

Initial V, before deformations. Used for deformations and resetting V

bool harmonicShowDeformationField = {false}

The harmonic deformation field value at the last recalculation

igl::ARAPData<float> *ArapData = {nullptr}

Pre-computations for Arap

4.2.7. Util.h

Contains various helper functions, classes and constants.

Typedefs

using Color_t = Eigen::RowVector4f

RGBA color

Functions

template<typename Matrix, typename Scalar>
void TransposeToMap(Matrix *from, Scalar *to)

Transpose an Eigen::Matrix to an Eigen::Map, given by the pointer to the first element Dimensions are inferred from the Matrix

Template Parameters
  • Matrix: An Eigen Matrix

  • Scalar: Type on one element

Parameters
  • to: Pointer to the first element of a matrix or an array

template<typename Scalar, typename Matrix>
void TransposeFromMap(Scalar *from, Matrix *to)

Transpose an Eigen::Map to an Eigen::Matrix

Template Parameters
  • Scalar: Type on one element

  • Matrix: An Eigen Matrix

Parameters
  • from: Pointer to the first element of a matrix or an array

template<typename V_T>
void CenterToMean(float *VPtr, int VSize)

Set the center/origin of the mesh to be the mean vertex

Template Parameters
  • V_T: Type of the vertex matrix to support both Col and RowMajor

template<typename V_T>
void ApplyScale(float *VPtr, int VSize, bool centerToMean = true, bool normalize = true, float targetScale = 1.f)

Applies the scale of a mesh to the vertices, i.e. cwise multiply. If targetScale is set to zero, the model scale is normalized so it has unit height.

Note

y-axis center will be the center of the bounding box for easier positioning

Parameters
  • centerToMean: If true sets the center to the mean vertex.

  • normalize: If set to true the absolute y-height of the model will be targetScale otherwise only the targetScale factor is applied.

Template Parameters
  • V_T: Type of the vertex matrix to support both Col and RowMajor

struct Color
#include <Util.h>

Contains color constants

Public Static Functions

const Color_t &GetColorById(int selectionId)

Gets color based on the selectionId, matched C#

Public Static Attributes

Color_t White
Color_t Gray
Color_t Black
Color_t Red
Color_t Green
Color_t Blue
Color_t Orange
Color_t Purple
Color_t GreenLight
Color_t BlueLight
Color_t Yellow