AvatarLoader.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using System;
  5. namespace TriLib.Extras
  6. {
  7. /// <summary>
  8. /// Represents an avatar loader behaviour. The main class used to load avatars.
  9. /// </summary>
  10. public class AvatarLoader : MonoBehaviour
  11. {
  12. /// <summary>
  13. /// Current Avatar reference.
  14. /// </summary>
  15. public GameObject CurrentAvatar;
  16. /// <summary>
  17. /// AnimationController that will be assigned to the loaded object.
  18. /// </summary>
  19. public RuntimeAnimatorController RuntimeAnimatorController;
  20. /// <summary>
  21. /// Amount by which the arm's length is allowed to stretch when using IK.
  22. /// </summary>
  23. public float ArmStretch = 0.05f;
  24. /// <summary>
  25. /// Modification to the minimum distance between the feet of a humanoid model.
  26. /// </summary>
  27. public float FeetSpacing = 0f;
  28. /// <summary>
  29. /// True for any human that has a translation Degree of Freedom (DoF). It is set to false by default.
  30. /// </summary>
  31. public bool HasTranslationDof = false;
  32. /// <summary>
  33. /// Amount by which the leg's length is allowed to stretch when using IK.
  34. /// </summary>
  35. public float LegStretch = 0.5f;
  36. /// <summary>
  37. /// Defines how the lower arm's roll/twisting is distributed between the elbow and wrist joints.
  38. /// </summary>
  39. public float LowerArmTwist = 0.5f;
  40. /// <summary>
  41. /// Defines how the lower leg's roll/twisting is distributed between the knee and ankle.
  42. /// </summary>
  43. public float LowerLegTwist = 0.5f;
  44. /// <summary>
  45. /// Defines how the lower arm's roll/twisting is distributed between the shoulder and elbow joints.
  46. /// </summary>
  47. public float UpperArmTwist = 0.5f;
  48. /// <summary>
  49. /// Defines how the upper leg's roll/twisting is distributed between the thigh and knee joints.
  50. /// </summary>
  51. public float UpperLegTwist = 0.5f;
  52. /// <summary>
  53. /// Object loading scale.
  54. /// </summary>
  55. public float Scale = 0.01f;
  56. /// <summary>
  57. /// Offset applied to CapsuleCollider height.
  58. /// </summary>
  59. public float HeightOffset = 0.01f;
  60. /// <summary>
  61. /// Use this field to define custom Human Bone to Unity Bone relationship, you can follow the tempĺates bellow.
  62. /// </summary>
  63. public BoneRelationshipList CustomBoneNames;
  64. /// <summary>
  65. /// 3Ds Max Biped files to Unity human bone relationship.
  66. /// </summary>
  67. private static readonly BoneRelationshipList BipedBoneNames = new BoneRelationshipList {
  68. {"Head", "Head", false},
  69. {"Neck", "Neck", true},
  70. {"Chest", "Spine3", true},
  71. {"UpperChest", "Spine1", true},
  72. {"Spine", "Spine", false},
  73. {"Hips", "Bip01", false},
  74. {"LeftShoulder", "L Clavicle", true},
  75. {"LeftUpperArm", "L UpperArm", false},
  76. {"LeftLowerArm", "L Forearm", false},
  77. {"LeftHand", "L Hand", false},
  78. {"RightShoulder", "R Clavicle", true},
  79. {"RightUpperArm", "R UpperArm", false},
  80. {"RightLowerArm", "R Forearm", false},
  81. {"RightHand", "R Hand", false},
  82. {"LeftUpperLeg", "L Thigh", false},
  83. {"LeftLowerLeg", "L Calf", false},
  84. {"LeftFoot", "L Foot", false},
  85. {"LeftToes", "L Toe0", true},
  86. {"RightUpperLeg", "R Thigh", false},
  87. {"RightLowerLeg", "R Calf", false},
  88. {"RightFoot", "R Foot", false},
  89. {"RightToes", "R Toe0", true},
  90. {"Left Thumb Proximal", "L Finger0", true},
  91. {"Left Thumb Intermediate", "L Finger01", true},
  92. {"Left Thumb Distal", "L Finger02", true},
  93. {"Left Index Proximal", "L Finger1", true},
  94. {"Left Index Intermediate", "L Finger11", true},
  95. {"Left Index Distal", "L Finger12", true},
  96. {"Left Middle Proximal", "L Finger2", true},
  97. {"Left Middle Intermediate", "L Finger21", true},
  98. {"Left Middle Distal", "L Finger22", true},
  99. {"Left Ring Proximal", "L Finger3", true},
  100. {"Left Ring Intermediate", "L Finger31", true},
  101. {"Left Ring Distal", "L Finger32", true},
  102. {"Left Little Proximal", "L Finger4", true},
  103. {"Left Little Intermediate", "L Finger41", true},
  104. {"Left Little Distal", "L Finger42", true},
  105. {"Right Thumb Proximal", "R Finger0", true},
  106. {"Right Thumb Intermediate", "R Finger01", true},
  107. {"Right Thumb Distal", "R Finger02", true},
  108. {"Right Index Proximal", "R Finger1", true},
  109. {"Right Index Intermediate", "R Finger11", true},
  110. {"Right Index Distal", "R Finger12", true},
  111. {"Right Middle Proximal", "R Finger2", true},
  112. {"Right Middle Intermediate", "R Finger21", true},
  113. {"Right Middle Distal", "R Finger22", true},
  114. {"Right Ring Proximal", "R Finger3", true},
  115. {"Right Ring Intermediate", "R Finger31", true},
  116. {"Right Ring Distal", "R Finger32", true},
  117. {"Right Little Proximal", "R Finger4", true},
  118. {"Right Little Intermediate", "R Finger41", true},
  119. {"Right Little Distal", "R Finger42", true}
  120. };
  121. /// <summary>
  122. /// Mixamo files to Unity human bone relationship.
  123. /// </summary>
  124. private static readonly BoneRelationshipList MixamoBoneNames = new BoneRelationshipList {
  125. {"Head", "Head", false},
  126. {"Neck", "Neck", true},
  127. {"Chest", "Spine1", true},
  128. {"UpperChest", "Spine2", true},
  129. {"Spine", "Spine", false},
  130. {"Hips", "Hips", false},
  131. {"LeftShoulder", "LeftShoulder", true},
  132. {"LeftUpperArm", "LeftArm", false},
  133. {"LeftLowerArm", "LeftForeArm", false},
  134. {"LeftHand", "LeftHand", false},
  135. {"RightShoulder", "RightShoulder", true},
  136. {"RightUpperArm", "RightArm", false},
  137. {"RightLowerArm", "RightForeArm", false},
  138. {"RightHand", "RightHand", false},
  139. {"LeftUpperLeg", "LeftUpLeg", false},
  140. {"LeftLowerLeg", "LeftLeg", false},
  141. {"LeftFoot", "LeftFoot", false},
  142. {"LeftToes", "LeftToeBase", true},
  143. {"RightUpperLeg", "RightUpLeg", false},
  144. {"RightLowerLeg", "RightLeg", false},
  145. {"RightFoot", "RightFoot", false},
  146. {"RightToes", "RightToeBase", true},
  147. {"Left Thumb Proximal", "LeftHandThumb1", true},
  148. {"Left Thumb Intermediate", "LeftHandThumb2", true},
  149. {"Left Thumb Distal", "LeftHandThumb3", true},
  150. {"Left Index Proximal", "LeftHandIndex1", true},
  151. {"Left Index Intermediate", "LeftHandIndex2", true},
  152. {"Left Index Distal", "LeftHandIndex3", true},
  153. {"Left Middle Proximal", "LeftHandMiddle1", true},
  154. {"Left Middle Intermediate", "LeftHandMiddle2", true},
  155. {"Left Middle Distal", "LeftHandMiddle3", true},
  156. {"Left Ring Proximal", "LeftHandRing1", true},
  157. {"Left Ring Intermediate", "LeftHandRing2", true},
  158. {"Left Ring Distal", "LeftHandRing3", true},
  159. {"Left Little Proximal", "LeftHandPinky1", true},
  160. {"Left Little Intermediate", "LeftHandPinky2", true},
  161. {"Left Little Distal", "LeftHandPinky3", true},
  162. {"Right Thumb Proximal", "RightHandThumb1", true},
  163. {"Right Thumb Intermediate", "RightHandThumb2", true},
  164. {"Right Thumb Distal", "RightHandThumb3", true},
  165. {"Right Index Proximal", "RightHandIndex1", true},
  166. {"Right Index Intermediate", "RightHandIndex2", true},
  167. {"Right Index Distal", "RightHandIndex3", true},
  168. {"Right Middle Proximal", "RightHandMiddle1", true},
  169. {"Right Middle Intermediate", "RightHandMiddle2", true},
  170. {"Right Middle Distal", "RightHandMiddle3", true},
  171. {"Right Ring Proximal", "RightHandRing1", true},
  172. {"Right Ring Intermediate", "RightHandRing2", true},
  173. {"Right Ring Distal", "RightHandRing3", true},
  174. {"Right Little Proximal", "RightHandPinky1", true},
  175. {"Right Little Intermediate", "RightHandPinky2", true},
  176. {"Right Little Distal", "RightHandPinky3", true}
  177. };
  178. /// <summary>
  179. /// Sample loading options.
  180. /// </summary>
  181. private AssetLoaderOptions _loaderOptions;
  182. /// <summary>
  183. /// Setups the Avatar Loader.
  184. /// </summary>
  185. protected void Start()
  186. {
  187. _loaderOptions = AssetLoaderOptions.CreateInstance();
  188. _loaderOptions.UseLegacyAnimations = false;
  189. _loaderOptions.DontGenerateAvatar = true;
  190. _loaderOptions.AnimatorController = RuntimeAnimatorController;
  191. }
  192. /// <summary>
  193. /// Loads the avatar from specified filename.
  194. /// </summary>
  195. /// <param name="data">Avatar file data.</param>
  196. /// <param name="extension">File extension.</param>
  197. /// <param name="templateAvatar">Template <see cref="UnityEngine.GameObject"/>.</param>
  198. /// <returns><c>true</c>, if avatar was loaded, <c>false</c> otherwise.</returns>
  199. public bool LoadAvatarFromMemory(byte[] data, string extension, GameObject templateAvatar)
  200. {
  201. GameObject loadedObject;
  202. if (CurrentAvatar != null)
  203. {
  204. Destroy(CurrentAvatar);
  205. }
  206. try
  207. {
  208. using (var assetLoader = new AssetLoader())
  209. {
  210. loadedObject = assetLoader.LoadFromMemoryWithTextures(data, extension, _loaderOptions, templateAvatar);
  211. }
  212. }
  213. #if TRILIB_OUTPUT_MESSAGES
  214. catch (Exception exception)
  215. {
  216. Debug.LogError(exception.ToString());
  217. return false;
  218. }
  219. #else
  220. catch
  221. {
  222. if (CurrentAvatar != null)
  223. {
  224. Destroy(CurrentAvatar);
  225. }
  226. return false;
  227. }
  228. #endif
  229. if (loadedObject != null)
  230. {
  231. if (templateAvatar != null)
  232. {
  233. loadedObject.transform.parent = templateAvatar.transform;
  234. CurrentAvatar = templateAvatar;
  235. }
  236. else
  237. {
  238. CurrentAvatar = loadedObject;
  239. }
  240. CurrentAvatar.transform.localScale = Vector3.one * Scale;
  241. CurrentAvatar.tag = "Player";
  242. SetupCapsuleCollider();
  243. return BuildAvatar();
  244. }
  245. return false;
  246. }
  247. /// <summary>
  248. /// Loads the avatar from specified filename.
  249. /// </summary>
  250. /// <param name="filename">Avatar filename.</param>
  251. /// <param name="templateAvatar">Template <see cref="UnityEngine.GameObject"/>.</param>
  252. /// <returns><c>true</c>, if avatar was loaded, <c>false</c> otherwise.</returns>
  253. public bool LoadAvatar(string filename, GameObject templateAvatar)
  254. {
  255. GameObject loadedObject;
  256. if (CurrentAvatar != null)
  257. {
  258. Destroy(CurrentAvatar);
  259. }
  260. try
  261. {
  262. using (var assetLoader = new AssetLoader())
  263. {
  264. loadedObject = assetLoader.LoadFromFile(filename, _loaderOptions, templateAvatar);
  265. }
  266. }
  267. #if TRILIB_OUTPUT_MESSAGES
  268. catch (Exception exception)
  269. {
  270. Debug.LogError(exception.ToString());
  271. return false;
  272. }
  273. #else
  274. catch
  275. {
  276. if (CurrentAvatar != null)
  277. {
  278. Destroy(CurrentAvatar);
  279. }
  280. return false;
  281. }
  282. #endif
  283. if (loadedObject != null)
  284. {
  285. if (templateAvatar != null)
  286. {
  287. loadedObject.transform.parent = templateAvatar.transform;
  288. CurrentAvatar = templateAvatar;
  289. }
  290. else
  291. {
  292. CurrentAvatar = loadedObject;
  293. }
  294. CurrentAvatar.transform.localScale = Vector3.one * Scale;
  295. CurrentAvatar.tag = "Player";
  296. SetupCapsuleCollider();
  297. return BuildAvatar();
  298. }
  299. return false;
  300. }
  301. /// <summary>
  302. /// Builds the object avatar, based on pre-defined templates (Mixamo, Biped), or based on the <see cref="TriLib.Extras.AvatarLoader.CustomBoneNames"></see>, if it's not null or empty.
  303. /// </summary>
  304. /// <returns><c>true</c> if avatar was built, <c>false</c> otherwise.</returns>
  305. private bool BuildAvatar()
  306. {
  307. var animator = CurrentAvatar.GetComponent<Animator>();
  308. if (animator == null)
  309. {
  310. #if TRILIB_OUTPUT_MESSAGES
  311. Debug.LogError("No animator component found on current avatar");
  312. #endif
  313. return false;
  314. }
  315. var skeletonBones = new List<SkeletonBone>();
  316. var humanBones = new List<HumanBone>();
  317. var boneTransforms = FindOutBoneTransforms(CurrentAvatar);
  318. if (boneTransforms.Count == 0)
  319. {
  320. #if TRILIB_OUTPUT_MESSAGES
  321. Debug.LogError("No suitable bones format found");
  322. #endif
  323. return false;
  324. }
  325. foreach (var boneTransform in boneTransforms)
  326. {
  327. humanBones.Add(CreateHumanBone(boneTransform.Key, boneTransform.Value.name));
  328. }
  329. var transforms = CurrentAvatar.GetComponentsInChildren<Transform>();
  330. var rootTransform = transforms[1];
  331. skeletonBones.Add(CreateSkeletonBone(rootTransform));
  332. rootTransform.localEulerAngles = Vector3.zero;
  333. for (var i = 0; i < transforms.Length; i++)
  334. {
  335. var childTransform = transforms[i];
  336. var meshRenderers = childTransform.GetComponentsInChildren<MeshRenderer>();
  337. if (meshRenderers.Length > 0)
  338. {
  339. continue;
  340. }
  341. var skinnedMeshRenderers = childTransform.GetComponentsInChildren<SkinnedMeshRenderer>();
  342. if (skinnedMeshRenderers.Length > 0)
  343. {
  344. continue;
  345. }
  346. skeletonBones.Add(CreateSkeletonBone(childTransform));
  347. }
  348. var humanDescription = new HumanDescription();
  349. humanDescription.armStretch = ArmStretch;
  350. humanDescription.feetSpacing = FeetSpacing;
  351. humanDescription.hasTranslationDoF = HasTranslationDof;
  352. humanDescription.legStretch = LegStretch;
  353. humanDescription.lowerArmTwist = LowerArmTwist;
  354. humanDescription.lowerLegTwist = LowerLegTwist;
  355. humanDescription.upperArmTwist = UpperArmTwist;
  356. humanDescription.upperLegTwist = UpperLegTwist;
  357. humanDescription.skeleton = skeletonBones.ToArray();
  358. humanDescription.human = humanBones.ToArray();
  359. animator.avatar = AvatarBuilder.BuildHumanAvatar(CurrentAvatar, humanDescription);
  360. return true;
  361. }
  362. /// <summary>
  363. /// Figures out the bone hierarchy for Avatar building.
  364. /// </summary>
  365. /// <returns>The bone hierarchy.</returns>
  366. /// <param name="loadedObject">Previously loaded object.</param>
  367. private Dictionary<string, Transform> FindOutBoneTransforms(GameObject loadedObject)
  368. {
  369. var boneTransforms = new Dictionary<string, Transform>();
  370. var boneRelationshipLists = new List<BoneRelationshipList>();
  371. boneRelationshipLists.Add(BipedBoneNames);
  372. boneRelationshipLists.Add(MixamoBoneNames);
  373. if (CustomBoneNames != null)
  374. {
  375. boneRelationshipLists.Add(CustomBoneNames);
  376. }
  377. var lastBonesValid = false;
  378. foreach (var boneRelationshipList in boneRelationshipLists)
  379. {
  380. if (lastBonesValid)
  381. {
  382. break;
  383. }
  384. lastBonesValid = true;
  385. foreach (var boneRelationship in boneRelationshipList)
  386. {
  387. var boneTransform = loadedObject.transform.FindDeepChild(boneRelationship.BoneName, true);
  388. if (boneTransform == null)
  389. {
  390. if (!boneRelationship.Optional)
  391. {
  392. boneTransforms.Clear();
  393. lastBonesValid = false;
  394. break;
  395. }
  396. continue;
  397. }
  398. boneTransforms.Add(boneRelationship.HumanBone, boneTransform);
  399. }
  400. }
  401. return boneTransforms;
  402. }
  403. /// <summary>
  404. /// Setups the avatar Capsule Collider to encapsulate the loaded object.
  405. /// </summary>
  406. private void SetupCapsuleCollider()
  407. {
  408. var capsuleCollider = CurrentAvatar.GetComponent<CapsuleCollider>();
  409. if (capsuleCollider == null)
  410. {
  411. return;
  412. }
  413. var bounds = CurrentAvatar.transform.EncapsulateBounds();
  414. var fraction = 1f / Scale;
  415. var boundExtentsX = bounds.extents.x * fraction;
  416. var boundExtentsY = bounds.extents.y * fraction;
  417. var boundExtentsZ = bounds.extents.z * fraction;
  418. capsuleCollider.height = (float)Math.Round(boundExtentsY * 2f, 1);
  419. capsuleCollider.radius = (float)Math.Round(Mathf.Sqrt(boundExtentsX * boundExtentsX + boundExtentsZ * boundExtentsZ) * 0.5f, 1);
  420. capsuleCollider.center = new Vector3(0f, (float)Math.Round(boundExtentsY, 1) + HeightOffset, 0f);
  421. }
  422. /// <summary>
  423. /// Builds a SkeletonBone.
  424. /// </summary>
  425. /// <returns>The built skeleton bone.</returns>
  426. /// <param name="boneTransform">The bone Transform to build the Skeleton from.</param>
  427. private static SkeletonBone CreateSkeletonBone(Transform boneTransform)
  428. {
  429. var skeletonBone = new SkeletonBone();
  430. skeletonBone.name = boneTransform.name;
  431. skeletonBone.position = boneTransform.localPosition;
  432. skeletonBone.rotation = boneTransform.localRotation;
  433. skeletonBone.scale = boneTransform.localScale;
  434. return skeletonBone;
  435. }
  436. /// <summary>
  437. /// Builds a Human Bone.
  438. /// </summary>
  439. /// <returns>The human bone.</returns>
  440. /// <param name="humanName">Human name.</param>
  441. /// <param name="boneName">Bone name.</param>
  442. private static HumanBone CreateHumanBone(string humanName, string boneName)
  443. {
  444. var humanBone = new HumanBone();
  445. humanBone.boneName = boneName;
  446. humanBone.humanName = humanName;
  447. humanBone.limit.useDefaultValues = true;
  448. return humanBone;
  449. }
  450. }
  451. /// <summary>
  452. /// Represents a human bone to Unity bone relationship.
  453. /// </summary>
  454. public class BoneRelationship
  455. {
  456. public string HumanBone; //Human Bone name.
  457. public string BoneName; //Unity Bone name.
  458. public bool Optional; //Is this bone optional?
  459. /// <summary>
  460. /// Initializes a new instance of the <see cref="TriLib.Extras.BoneRelationship"/> class.
  461. /// </summary>
  462. /// <param name="humanBone">Human bone.</param>
  463. /// <param name="boneName">Bone name.</param>
  464. /// <param name="optional">If set to <c>true</c> this bone relationship will be optional in the hierarchy.</param>
  465. public BoneRelationship(string humanBone, string boneName, bool optional)
  466. {
  467. HumanBone = humanBone;
  468. BoneName = boneName;
  469. Optional = optional;
  470. }
  471. }
  472. /// <summary>
  473. /// Represents a BoneRelationship list.
  474. /// </summary>
  475. [Serializable]
  476. public class BoneRelationshipList : IEnumerable<BoneRelationship>
  477. {
  478. private readonly List<BoneRelationship> _relationships; //Relationship list
  479. /// <summary>
  480. /// Initializes a new instance of the <see cref="TriLib.Extras.BoneRelationshipList"/> class.
  481. /// </summary>
  482. public BoneRelationshipList()
  483. {
  484. _relationships = new List<BoneRelationship>();
  485. }
  486. /// <summary>
  487. /// Adds a new BoneRelationship to this list.
  488. /// </summary>
  489. /// <param name="humanBone">Human bone.</param>
  490. /// <param name="boneName">Bone name.</param>
  491. /// <param name="optional">If set to <c>true</c> this bone relationship will be optional in the hierarchy.</param>
  492. public void Add(string humanBone, string boneName, bool optional)
  493. {
  494. _relationships.Add(new BoneRelationship(humanBone, boneName, optional));
  495. }
  496. /// <summary>
  497. /// Returns an enumerator that iterates through this collection.
  498. /// </summary>
  499. /// <returns>The enumerator.</returns>
  500. public IEnumerator<BoneRelationship> GetEnumerator()
  501. {
  502. return _relationships.GetEnumerator();
  503. }
  504. /// <summary>
  505. /// Gets the enumerator for this collection.
  506. /// </summary>
  507. /// <returns>The enumerator.</returns>
  508. IEnumerator IEnumerable.GetEnumerator()
  509. {
  510. return GetEnumerator();
  511. }
  512. }
  513. }