Skip to content

Instantly share code, notes, and snippets.

@KevinRoussel
Created March 30, 2024 21:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KevinRoussel/14ae70260cf459c6e643546ec4738347 to your computer and use it in GitHub Desktop.
Save KevinRoussel/14ae70260cf459c6e643546ec4738347 to your computer and use it in GitHub Desktop.
FaceMapper_AutoSetup / Need UnityLiveCapture & NaughtyAttributes packages
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NaughtyAttributes;
using Unity.LiveCapture.ARKitFaceCapture;
using Unity.LiveCapture.ARKitFaceCapture.DefaultMapper;
using UnityEngine;
public class FaceMapperAutoSetup : MonoBehaviour
{
[SerializeField] DefaultFaceMapper _mapper;
[SerializeField] string SkinnedMeshNameGo = "head";
IEnumerable<string> AllARFaces => Enum.GetNames(typeof(FaceBlendShape)).Except(new[] { "Invalid" });
// Mesh data
SkinnedMeshRenderer Skin => (_mapper
.GetType()
.GetField("m_RigPrefab", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(_mapper) as GameObject)
.transform
.Find(SkinnedMeshNameGo)
.GetComponent<SkinnedMeshRenderer>();
// Face Data
object Maps => _mapper.GetType().GetPrivateField("m_Maps").GetValue(_mapper); // List<RendererMapping>
Array MapsEl => Maps.GetType().GetPrivateField("_items").GetValue(Maps) as Array; // Array[RendererMapping]
Array HeadBindings => MapsEl.GetValue(0)
.GetType()
.GetPrivateField("m_Bindings")
.GetValue(MapsEl.GetValue(0)) as Array; // Binding[]
IEnumerable<(object, FaceBlendShape, int)> GetBindings()
{
for (int i = 0; i < HeadBindings.Length; i++)
{
var el = HeadBindings.GetValue(i); // Binding
var type = el.GetType();
FaceBlendShape face = (FaceBlendShape)(type.GetPrivateField("m_Location").GetValue(el));
int faceIdx = (int)(type.GetPrivateField("m_ShapeIndex").GetValue(el));
yield return (el, face, faceIdx);
}
}
void SetBinding(object binding, int value) => binding.GetType().GetPrivateField("m_ShapeIndex").SetValue(binding, value);
[Button]
void AutoSetup()
{
var blendShape = Skin.sharedMesh.GetBlendShapeData();
foreach (var el in GetBindings())
{
var txtlower = Enum.GetName(typeof(FaceBlendShape), el.Item2).ToLower();
var rightBlendShapeIndex = blendShape.First(i => i.Item2 == txtlower).Item1;
SetBinding(el.Item1, rightBlendShapeIndex);
}
UnityEditor.EditorUtility.SetDirty(_mapper);
}
}
public static class MyExtension
{
public static FieldInfo GetPrivateField(this Type @this, string n)
=> @this.GetField(n, BindingFlags.NonPublic | BindingFlags.Instance);
public static IEnumerable<(int, string)> GetBlendShapeData(this Mesh @this)
{
(int, string)[] data = new (int, string)[@this.blendShapeCount];
for (int i = 0; i < @this.blendShapeCount; i++)
{
data[i] = (i, @this.GetBlendShapeName(i).ToLower());
}
return data;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment