/*赛马娘表情导出脚本 2022.9.19更新版本*/ using System.Collections.Generic; using UnityEngine; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections; public class Facialtest : MonoBehaviour { public TextAsset FacialTarget; public List objs = new List(); private List oriTrans = new List(); private List oriRots = new List(); private List oriScal = new List(); public List morphs = new List(); public SkinnedMeshRenderer faceMesh; public SkinnedMeshRenderer eyebrowMesh; string[] typeList = new string[] { "_eyebrowTarget", "_eyeTarget", "_mouthTarget" }; [Range(0, 200)] public int show; int curShow; void Start() { if (FacialTarget == null) { Debug.LogError("无FacialTarget"); return; } objs.AddRange(GetComponentsInChildren()); foreach (Transform g in objs) { oriTrans.Add(g.localPosition); oriRots.Add(g.localRotation); oriScal.Add(g.localScale); } foreach (SkinnedMeshRenderer s in GetComponentsInChildren()) { if (s.name.Contains("Face")) faceMesh = s; if (s.name.Contains("Mayu")) eyebrowMesh = s; } JObject jObject = (JObject)JsonConvert.DeserializeObject(FacialTarget.text); if (jObject == null) return; for (int f = 0; f < typeList.Length; f++) { JArray jArray = (JArray)jObject[typeList[f]]; for (int i = 0; i < jArray.Count; i++) { JArray Group = (JArray)jArray[i]["_faceGroupInfo"]; for (int j = 0; j < Group.Count; j++) { Morph morph = new Morph(); morph.type = (Morph.morphType)f; JArray trsArray = (JArray)Group[j]["_trsArray"]; for (int n = 0; n < trsArray.Count; n++) { Bone bone = new Bone(); bone.Bonename = trsArray[n]["_path"].ToString(); bone.pos = new Vector3(Convert.ToSingle(trsArray[n]["_position"]["x"]), Convert.ToSingle(trsArray[n]["_position"]["y"]), Convert.ToSingle(trsArray[n]["_position"]["z"])); bone.rot = new Vector3(Convert.ToSingle(trsArray[n]["_rotation"]["x"]), Convert.ToSingle(trsArray[n]["_rotation"]["y"]), Convert.ToSingle(trsArray[n]["_rotation"]["z"])); bone.sca = new Vector3(Convert.ToSingle(trsArray[n]["_scale"]["x"]), Convert.ToSingle(trsArray[n]["_scale"]["y"]), Convert.ToSingle(trsArray[n]["_scale"]["z"])); bone.isValidScale = (int)trsArray[n]["_isValidScaleTransform"] == 1; //bone.isOverride = (int)trsArray[n]["IsOverrideTarget"] == 1; if (i == 0) { bone.isOverride = true; morph.name = ((Morph.morphType)f).ToString() + "_Base" + (Group.Count < 2 ? "" : (j == 0 ? "_R" : "_L")); } else morph.name = ((Morph.morphType)f).ToString() + "_" + i + (Group.Count < 2 ? "" : (j == 0 ? "_R" : "_L")); morph.bones.Add(bone); } if (i == 0) { morph.isBase = true; } morphs.Add(morph); } } } RecordBlendshape(); } private void Update() { if (curShow != show) { curShow = show; if (curShow <= morphs.Count) { if (curShow == 0) { FacialReset(); } else { ChangeMorph(morphs[curShow - 1]); } } } } public void ChangeMorph(Morph morph) { FacialReset(); foreach (Bone bone in morph.bones) { var tran = objs.Find(ani => ani.name.Equals(bone.Bonename)); if (tran) { if (morph.isBase) { tran.localRotation = fromMaya(bone.rot); tran.localPosition = bone.pos; tran.localScale = bone.sca; } else { var tmp = tran.localRotation.eulerAngles; tmp += bone.rot; tran.localRotation = fromMaya(tmp); tran.localPosition += bone.pos; tran.localScale += bone.sca; } } } } private void RecordBlendshape() { eyebrowMesh.sharedMesh.ClearBlendShapes(); faceMesh.sharedMesh.ClearBlendShapes(); foreach (Morph m in morphs) { ChangeMorph(m); switch (m.type) { case Morph.morphType.EyeBrow: case Morph.morphType.Eye: case Morph.morphType.Mouth: Mesh facemesh = new Mesh(); faceMesh.BakeMesh(facemesh); faceMesh.sharedMesh.AddBlendShapeFrame(m.name, 1, CalDelta(faceMesh.sharedMesh.vertices, facemesh.vertices), CalDelta(faceMesh.sharedMesh.normals, facemesh.normals), CalDelta(Vec4ToVec3(faceMesh.sharedMesh.tangents), Vec4ToVec3(facemesh.tangents))); break; } FacialReset(); } } public void FacialReset() { for (int i = 0; i < objs.Count; i++) { objs[i].localPosition = oriTrans[i]; objs[i].localRotation = oriRots[i]; objs[i].localScale = oriScal[i]; } } public Vector3[] Vec4ToVec3(Vector4[] vector4s) { Vector3[] tmp = new Vector3[vector4s.Length]; for (int i = 0; i < vector4s.Length; i++) { tmp[i] = new Vector3(vector4s[i].x, vector4s[i].y, vector4s[i].z); } return tmp; } public Vector3[] CalDelta(Vector3[] ori, Vector3[] end) { Vector3[] tmp = new Vector3[ori.Length]; for (int i = 0; i < ori.Length; i++) { tmp[i] = end[i] - ori[i]; } return tmp; } public static Quaternion fromMaya(Vector3 euler_angle) { euler_angle.x *= Mathf.Deg2Rad; euler_angle.y *= Mathf.Deg2Rad; euler_angle.z *= Mathf.Deg2Rad; float c = Mathf.Cos(euler_angle[0] / 2); float d = Mathf.Cos(euler_angle[1] / 2); float e = Mathf.Cos(euler_angle[2] / 2); float f = Mathf.Sin(euler_angle[0] / 2); float g = Mathf.Sin(euler_angle[1] / 2); float h = Mathf.Sin(euler_angle[2] / 2); float x = f * d * e - c * g * h; float y = c * g * e + f * d * h; float z = c * d * h - f * g * e; float w = c * d * e + f * g * h; return new Quaternion(x, y, z, w); } } [Serializable] public class Morph { public int index; public string name; public bool isBase; public enum morphType { EyeBrow, Eye, Mouth } public morphType type; public List bones = new List(); } [Serializable] public class Bone { public string Bonename; public bool isValidScale; public bool isOverride; public Vector3 pos, rot, sca; }