3.4. C# Libigl

3.4.1. MeshManager.cs

class Libigl.MeshManager : public MonoBehaviour

Handles loading EditableMeshes and stores references, notably to the ActiveMesh.

Public Functions

LibiglMesh LoadMesh (GameObject prefab, bool unloadActiveMesh = true, bool setAsActiveMesh = true, bool performValidityChecks = false)

Instantiate a mesh that can be used with libigl

Parameters
  • prefab: Prefab to be created, see meshPrefabs

  • unloadActiveMesh: Delete the active mesh if it exists

  • setAsActiveMesh: Set this mesh as the active one

  • performValidityChecks: Check that the prefab can be properly used with libigl.

Meshes from the meshPrefabs list are checked during Start and do not need to be checked again.

Return

LibiglMesh component on the new instance, null if there was an error

void DestroyMesh (LibiglMesh libiglMesh)

Use this to delete a mesh safely. Handles case when mesh is the active one, ActiveMesh

void RegisterMesh (LibiglMesh libiglMesh)
void UnregisterMesh (LibiglMesh libiglMesh)

Public Members

GameObject[] meshPrefabs
Transform meshSpawnPoint
readonly List<LibiglMeshAllMeshes = new List<LibiglMesh>()

List of all LibiglMeshes that are instantiated

Material wireframeMaterial
Material wireframeMaterialPrimary
Material wireframeMaterialActive
GameObject boundingBoxPrefab

Events

event Action OnActiveMeshChanged = delegate { }

Invoked when the ActiveMesh is changed. Called after initialization, if the mesh is newly instantiated.

Public Static Functions

bool CheckPrefabValidity (GameObject prefab)

Checks if a prefab can be loaded and modified with libigl. Does not modify the prefab only logs errors.

Return

True if the prefab can be used with libigl

void SetActiveMesh (LibiglMesh libiglMesh)

Public Static Attributes

MeshManager get
LibiglMesh ActiveMesh

The mesh currently loaded and being modified

Private Functions

void Awake ()
void Start ()

Private Static Functions

void DestroyActiveMesh ()

Private Static Attributes

int _defaultLayer
int _holographicLayer

3.4.2. LibiglMesh.cs

class Libigl.LibiglMesh : public MonoBehaviour

This component needs to be attached to any GameObject that you want to modify with libigl.

Any libigl related code is defined in the LibiglBehaviour class. This class only handles the threading and connection with the Unity Mesh components.

Public Functions

bool IsJobRunning ()

Return

True if a job/worker thread is running on the MeshData

bool IsActiveMesh ()

Return

True if this is the active mesh set by the MeshManager

void Initialize ()
void ResetTransformToSpawn ()

Move mesh up so it is resting on the spawnPoint, ie min of bounding box is at spawnPoint

Parameters
  • mesh: Needed for bounding box

void SetWireframe (bool value)

Toggles the wireframe shader for the mesh (not the bounding box).

void UpdateBoundingBoxSize ()

Adjust the bounding box visual to fit the true bounds of the mesh.

void RepaintBounds (bool overrideVisible = false, bool primary = false)

Shows or hides the wireframe bounding box. Also changes the material accordingly.

Parameters
  • overrideVisible: Override default visibility set in the InputState

  • primary: If overriding visibility, should we highlight this as the primary bounding box

Public Members

Transform BoundingBox

Properties

Mesh Mesh { }

The Unity mesh.

MeshRenderer MeshRenderer { }
UMeshData DataRowMajor { }

The Unity Mesh data in RowMajor easily accessible as NativeArrays

LibiglBehaviour Behaviour { }

The libigl behaviour instance that is executing on this mesh

Private Functions

void OnActiveMeshChanged ()
void Update ()
void ExecuteThread ()

Creates a thread with the LibiglBehaviour code

Assert: _workerThread is null (finished and PostExecuteThread has been called)

void PostExecuteThread ()

Applies changes and cleans up the threading for re-use once the thread has finished.

Assert: _workerThread is finished executing.

void OnDestroy ()
void Dispose ()

Private Members

MeshFilter _meshFilter
Thread _workerThread

Expensive operations executed in LibiglBehaviour.Execute are done in this thread

MeshRenderer _boundingBoxRenderer

3.4.3. UMeshData.cs

class Libigl.UMeshData : public IDisposable

Stores a copy of the Unity Mesh’s arrays. This is purely for the interface between the Libigl Mesh MeshState and the Unity Mesh / what will be rendered. Important: Uses RowMajor as that is how it is stored by Unity and on the GPU.

Public Functions

UMeshData (Mesh mesh)

Parameters
  • mesh: Unity Mesh to copy from

unsafe void LinkBehaviourState (LibiglBehaviour behaviour)

Initialize the UMeshData with shared data with the behaviour .

unsafe void ApplyDirty (MeshState *state, MeshInputState inputState)

Applies changes to the C++ State to this instance. Use this to copy changes from Col to RowMajor.

Can and should be called from a worker thread. Behind the scenes this tranposes and copies the matrices.

The DirtyState is propagated so ApplyDirtyToMesh (called on the main thread) will apply the changes.

See

Native.ApplyDirty

void ApplyDirtyToMesh (Mesh mesh)

Apply MeshData changes to the Unity Mesh to see changes when rendered. Uses the DirtyState to detect what needs to be applied.

Must be called on the main thread as it accesses the Unity API.

Assert: IsRowMajor is true.

UMeshDataNative GetNative ()

Note: Changes to the dirtyState are not applied to the MeshData instance (not a reference) and needs to be set manually in a C# context.

Important: The struct itself should be treated as const as changes have no effect (it’s a copy).

Return

A MeshDataNative instance than can be passed to C++ containing all pointers

void Dispose ()

Public Members

const bool IsRowMajor = true
uint DirtyState = DirtyFlag.None
uint DirtySelections = 0
uint DirtySelectionsResized = 0
NativeArray<Vector3> V
NativeArray<Vector3> N
NativeArray<ColorC
NativeArray<Vector2> UV
NativeArray<int> F
NativeArray<uint> S
readonly int VSize
readonly int FSize

Private Functions

void Allocate (Mesh mesh)

Allocated the NativeArrays once VSize and FSize have been set.

void CopyFrom (Mesh mesh)

Copies all data (e.g. V, F) from Unity mesh into the already allocated NativeArrays

Private Members

UMeshDataNative _native

Stores pointers to the native arrays, we can pass this to C++

3.4.3.1. DirtyFlag

class Libigl.DirtyFlag

Marks which data has changed in UMeshData as a bitmask and needs to be applied to the mesh.

This is used to selectively update the Unity mesh and is only for data that Unity requires. Use these constants along with the bitwise operators.

Public Members

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

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

const uint DontComputeBounds = 64

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

const uint DontComputeColorsBySelection = 128

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

const uint VDirtyExclBoundary = 256

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

const uint All = uint.MaxValue - DontComputeNormals - DontComputeBounds

3.4.3.2. UMeshDataNative.cs

struct Libigl.UMeshDataNative

Stores pointers to the native arrays in UMeshData so we can pass this to C++. Pointers are to the first element in the respective NativeArray.

Important: As Native arrays are not managed memory, the underlying array is fixed and will not move due to Garbage Collection. So an instance’s pointers will remain valid.

Public Functions

UMeshDataNative (float *vPtr, float *nPtr, float *cPtr, float *uvPtr, int *fPtr, int vSize, int fSize)

Public Members

readonly float* VPtr
readonly float* NPtr
readonly float* CPtr
readonly float* UVPtr
readonly int* FPtr
readonly int VSize
readonly int FSize

3.4.4. LibiglBehaviour.cs

class Libigl.LibiglBehaviour : public IDisposable

This is where the behaviour that interfaces with libigl is. It follows a Pre/Post/Execute threading pattern. This is a partial class, meaning it is split between several files.

Input: This handles collecting data from the main thread for the worker thread. It sets up the MeshInputState for the Actions. This is where we decide what to execute on the worker thread.

Actions: This handles executing things on the worker thread. Actions, in this context, are things that can be executed on the worker thread. They are the entry points to the C++ code (mostly). These actions correspond to the Do* variables in the MeshInputState

Transform: This handles anything related to transformations of the mesh or selections. This is only used for calculating which transformation to do for the selections. The code for applying the transformation to selections is in Actions

See also Libigl.LibiglMesh which handles the threading and calls the Pre/Post/Execute callbacks.

Public Functions

LibiglBehaviour (LibiglMesh libiglMesh)

Create a behaviour for the Mesh MonoBehaviour component. Every Mesh has one behaviour.

void Update ()

Called every frame, the normal Unity Update. Use this to update UI, input responsively. Do not call any expensive libigl methods here, use Execute instead

Be careful not to modify the shared state if there is a job running Libigl.LibiglMesh.IsJobRunning. Consider making a copy of certain data, using PreExecute or using atomics/Interlocked. Update is called just before PreExecute.

void PreExecute ()

Called just before a new thread is started in which Execute is called. Use this to update the input state, set flags and access any Unity API from the main thread.

Called on the main thread.

void Execute ()

Perform expensive computations here. This is called similarly to Update. Called on a worker thread from which any Unity API function, with a few exceptions such as Debug.Log, cannot be called.

There is one worker thread per Libigl.LibiglMesh. You should call _libiglMesh.DataRowMajor.ApplyDirty(_state) here to apply changes to the RowMajor UMeshData outside the main thread.

void PostExecute ()

Called after Execute to apply changes to the mesh.

Called on the main thread.

Use Mesh.DataRowMajor.ApplyDirtyToMesh to apply changes

void Dispose ()

This is the destructor. Ensure all C++ owned data is deleted. Calls Native.DisposeMesh

void SetActiveSelection (int value)

Changes the active selection and triggers OnActiveSelectionChanged.

void SetActiveSelectionIncrement (int increment)

Increments the active selection and safely loops.

Public Members

MeshStateState

A pointer to the C++ state. This is allocated and deleted in C++ within Native.InitializeMesh and Native.DisposeMesh.

MeshInputState Input

The input state on the main thread. This is copied to the thread input state State.Input at the end of PreExecute and is then immediately consumed by MeshInputState.Consume.

readonly LibiglMesh Mesh

Reference to the Libigl.LibiglMesh used to apply changes to the Libigl.LibiglMesh.DataRowMajor and the Unity UnityEngine.Mesh

Events

event Action OnActiveSelectionChanged = delegate { }

Invoked when the active selection of the mesh has changed.

Private Functions

void ActionTransformSelection ()

Transforms the selections based on the TransformDeltas given in the MeshInputState It also decides which selections should be translated, storing this in _currentTranslateMaskL

void FindBrushSelectionMask (ref uint maskId, Vector3 brushPos)

Finds which selections are inside the brush and updates the maskId

void ActionTransformSelectionGeneric (ref TransformDelta transformDelta, uint maskId)

Does the actual translation, but is independent of the hands (L or R)

void ActionSelect ()

Selects what is inside the brushes of the hands.

void ActionSelectGeneric (bool doSelect, Vector3 brushPos, bool alternateSelectMode)

Does the actual selection, but is independent of the hands (L or R)

void ActionHarmonic ()

Runs the igl::harmonic Biharmonic Deformation

void ActionArap ()

Runs the igl::arap As-Rigid-As-Possible Deformation

void ActionUi ()

Applies various actions triggered from the UI or other input

void UpdateInput ()

Updates the Input every frame, from Update().

void UpdateInputTransform ()

Input for the transform tool

void UpdateInputSelect ()

Gathering input for the select tool

void PreExecuteInput ()

Updates the Input just before the worker thread is started. This copies the shared InputManager.State to the Input

void UpdateTransform ()

Updates the current transformation state from the input, regardless of what the worker thread is doing. Decides when a transformation is started/stopped (changes in the finite state machine FSM). Applies the transformation immediately if we are transforming the mesh (as this is done by Unity). Call this in Update() every frame.

void ApplyTransformToMesh ()

Gets and consumes the transformation, applying it to the LibiglMesh Transform.

void ApplyTransformToSelection ()

Save and consume the transformation, which will later be applied to the selection on the worker thread.

void PreExecuteTransform ()
void ResetTransformStartPositions ()
void GetTransformDelta (bool consumeInput, ref TransformDelta transformDelta, Space space, bool withRotate, bool isTwoHanded, bool primaryHand)

Find out the TransformDelta that should be done. Independent of what we are transforming, mesh or selection.

Parameters
  • consumeInput: Should we reset the starting positions/rotations of the hands. This is unrelated to the MeshInputState.Consume function which is for the worker thread

  • transformDelta: Where we should add our transformation to.

void GetTransformOneHanded (bool isRight, ref TransformDelta transformDelta, bool withRotate = true)

Finds out the transformation when using one hand

void GetTransformTwoHanded (ref TransformDelta transformDelta, bool withRotate = true)

Finds out the transformation when using both hands

Private Members

uint _currentTranslateMaskL

The selections which are currently being translated by the left hand. This is set by the worker thread.

uint _currentTranslateMaskR
MeshInputState _executeInput

The input state on the worker thread. When inside an Actions or anywhere on the worker thread you should exclusively access this input state.

readonly UiMeshDetails _uiDetails

The corresponding UI panel. It is initialized from here.

bool _firstTransformHand

The first hand to start a transformation. True = Right

bool _isTwoHandedTransformation

Are we using both hands in the transformation

bool _isTwoHandedTransformationPrev
bool _doTransformL
bool _doTransformPrevL
bool _doTransformR
bool _doTransformPrevR
Vector3 _transformStartHandPosL

Where the hand was when the TransformDelta was started. Or the hand position at the last time the transformation was consumed.

Vector3 _transformStartHandPosR
Quaternion _transformStartHandRotL
Quaternion _transformStartHandRotR
const float GrabPressThreshold = 0.1f

At which point do we consider the button as pressed

3.4.4.1. TransformDelta

struct Libigl.TransformDelta

Stores information about a single transformation.

Public Functions

void Add (TransformDelta other)

(experimental) Combines two transformations, does not consider the pivot.

Public Members

Vector3 Translate
Quaternion Rotate
float Scale
PivotMode Mode
Vector3 Pivot

Public Static Functions

TransformDelta Identity ()

3.4.5. MeshInputState.cs

struct Libigl.MeshInputState

Struct for storing the current input for a mesh. (This is a value type so assigning will copy). Anything that may change as we are executing should be in the InputState, as it is copied in PreExecute. Anything that is the same between all meshes may be put into the InputState. Anything related to what should be executed on the worker thread should be put here (e.g. DoSelect).

Variables that correspond to triggering Actions start with Do e.g. DoSelect

Public Functions

void Consume ()

Consumes and resets flags raised. Should be called in PreExecute after copying to the State.

Public Members

InputState Shared
InputState SharedPrev
bool DoTransformL
bool DoTransformR
bool DoTransformLPrev
bool DoTransformRPrev
bool PrimaryTransformHand
TransformDelta TransformDeltaJoint
TransformDelta TransformDeltaL
TransformDelta TransformDeltaR
int ActiveSelectionId
uint VisibleSelectionMask
bool VisibleSelectionMaskChanged
uint SCountUi

For UI, will be copied to the state in PreExecute. This is used when we create a selection in the UI on the main thread.

bool DoSelectL
bool DoSelectLPrev
bool DoSelectR
bool DoSelectRPrev
bool AlternateSelectModeL

Inverts the selection mode between SelectionMode.Add and SelectionMode.Subtract

bool AlternateSelectModeR
uint DoClearSelection

A Mask of the selections that should be cleared

Vector3 BrushPosL
Vector3 BrushPosR
float BrushRadiusLocal
bool DoHarmonic

Trigger execution once

bool DoHarmonicRepeat

Trigger execution every frame

bool HarmonicShowDisplacement
bool DoArap
bool DoArapRepeat
bool ResetV

Public Static Functions

MeshInputState GetInstance ()

Return

An instance with the default values

Private Functions

void ConsumeTransform ()

Consumes the state for the transformations

3.4.6. MeshState.cs

struct Libigl.MeshState

The C++ state for a mesh in column major. This is linked to Unity and the RowMajor version via UMeshData. It stores only pointers to the Eigen data so this can be shared between C++ and C#. The mesh data is allocated in C++ during the Native.InitializeMesh function using UMeshDataNative.

The DirtyState indicates what has been changed and needs to be applied to the Unity mesh.

As this struct is shared between a managed (C#) and native (C++) context, you must consider Marshalling when adding new variables.

void* usually represents an Eigen matrix, but can be anything.

Public Members

uint DirtyState

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

uint DirtySelections

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

uint DirtySelectionsResized

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

readonly void* VPtr
readonly void* NPtr
readonly void* CPtr
readonly void* UVPtr
readonly void* FPtr
readonly int VSize
readonly int FSize
readonly void* SPtr
uint SSize

Amount of selections enabled

readonly uint* SSizes

uint[32], vertices selected per selection

readonly uint SSizesAll

Total vertices selected

Private Members

readonly void* Native

Native only state

3.4.7. Native.cs

class Libigl.Native

Contains all C++ function declarations. C# to C++

Handles initialization of the DLL and works with the UnityNativeTool for easy reloading/recompilation.

Convention: Pass the MeshState as the first argument if the function modifies a mesh.

Public Functions

unsafe MeshStateInitializeMesh (UMeshDataNative data, string name)
unsafe void DisposeMesh (MeshState *data)
unsafe void ApplyDirty (MeshState *state, UMeshDataNative data, uint visibleSelectionMask)
unsafe void ReadOFF (string path, bool setCenter, bool normalizeScale, float scale, out float *VPtr, out int VSize, out float *NPtr, out int NSize, out uint *FPtr, out int FSize, bool calculateNormalsIfEmpty)
unsafe void TranslateAllVertices (MeshState *state, Vector3 value)
unsafe void TranslateSelection (MeshState *state, Vector3 value, uint maskId)
unsafe void TransformSelection (MeshState *state, Vector3 translation, float scale, Quaternion rotation, Vector3 pivot, uint maskId)
unsafe void Harmonic (MeshState *state, uint boundaryMask, bool showDeformationField)
unsafe void Arap (MeshState *state, uint boundaryMask)
unsafe void ResetV (MeshState *state)
unsafe void SelectSphere (MeshState *state, Vector3 position, float radius, int selectionId, uint selectionMode)
unsafe uint GetSelectionMaskSphere (MeshState *state, Vector3 position, float radius)
unsafe Vector3 GetSelectionCenter (MeshState *state, uint maskId)
unsafe void ClearSelectionMask (MeshState *state, uint maskId)
unsafe void SetColorSingleByMask (MeshState *state, uint maskId, int colorId)
unsafe void SetColorByMask (MeshState *state, uint maskId)

Public Static Functions

void Initialize ()

Initializes the native library and sets up callbacks/delegates for C++ -> C# calls. Note: this may not be called on the main thread. So Unity functions may not be available.

In the editor, this is triggered each time the dll has been loaded.

void Destroy ()

Clean up native part if required, called just before unloading of the dll.

Public Static Attributes

readonly VertexAttributeDescriptor[] VertexBufferLayout

Contains the vertex buffer layout (on the GPU) for editable meshes. There will be a copy of the mesh on the CPU which may not have the same layout. This was initially intended to be done for more a efficient applying of mesh data, but it allows for slightly more control over how meshes are stored on the GPU.

Private Functions

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

Private Members

const string DllName = “__libigl-interface”

Name of the dll without the extension. Use this with the DllImportAttribute. This is set such that in the editor we can use the UnityNativeTool and in the build we use the library directly.

In Editor: libigl-interface

In Build and Actual Name: __libigl-interface

Private Static Functions

static Native ()

In a build, Initialize in the static ctor. This is called once just before the first function is called in this class.

Please read up on static constructors before modifying this.

3.4.8. NativeCallbacks.cs

class Libigl.NativeCallbacks

Contains all callbacks from the native context. C++ to C#

Callbacks should be annotated with the MonoPInvokeCallbackAttribute so that IL2CPP builds will compile properly. Each callback needs to have a corresponding delegate (/type).

Public Functions

delegate void StringCallback (string message)

Based on https://answers.unity.com/questions/30620/how-to-debug-c-dll-code.html The ‘function pointer type’ passed to C++

Parameters
  • message: String or char* to be printed

Public Static Functions

void DebugLog (string message)

The function that we point to in C++

Parameters
  • message: String or char* to be printed

void DebugLogWarning (string message)
void DebugLogError (string message)