CubismModel3Json.cs 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. /**
  2. * Copyright(c) Live2D Inc. All rights reserved.
  3. *
  4. * Use of this source code is governed by the Live2D Open Software license
  5. * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
  6. */
  7. using Live2D.Cubism.Core;
  8. using System;
  9. using System.IO;
  10. using Live2D.Cubism.Framework.MouthMovement;
  11. using Live2D.Cubism.Framework.Physics;
  12. using Live2D.Cubism.Framework.UserData;
  13. using Live2D.Cubism.Framework.Pose;
  14. using Live2D.Cubism.Framework.Expression;
  15. using Live2D.Cubism.Framework.MotionFade;
  16. using Live2D.Cubism.Framework.Raycasting;
  17. using Live2D.Cubism.Rendering;
  18. using Live2D.Cubism.Rendering.Masking;
  19. #if UNITY_EDITOR
  20. using UnityEditor;
  21. #endif
  22. using UnityEngine;
  23. namespace Live2D.Cubism.Framework.Json
  24. {
  25. /// <summary>
  26. /// Exposes moc3.json asset data.
  27. /// </summary>
  28. [Serializable]
  29. // ReSharper disable once ClassCannotBeInstantiated
  30. public sealed class CubismModel3Json
  31. {
  32. #region Delegates
  33. /// <summary>
  34. /// Handles the loading of assets.
  35. /// </summary>
  36. /// <param name="assetType">The asset type to load.</param>
  37. /// <param name="assetPath">The path to the asset.</param>
  38. /// <returns></returns>
  39. public delegate object LoadAssetAtPathHandler(Type assetType, string assetPath);
  40. /// <summary>
  41. /// Picks a <see cref="Material"/> for a <see cref="CubismDrawable"/>.
  42. /// </summary>
  43. /// <param name="sender">Event source.</param>
  44. /// <param name="drawable">Drawable to pick for.</param>
  45. /// <returns>Picked material.</returns>
  46. public delegate Material MaterialPicker(CubismModel3Json sender, CubismDrawable drawable);
  47. /// <summary>
  48. /// Picks a <see cref="Texture2D"/> for a <see cref="CubismDrawable"/>.
  49. /// </summary>
  50. /// <param name="sender">Event source.</param>
  51. /// <param name="drawable">Drawable to pick for.</param>
  52. /// <returns>Picked texture.</returns>
  53. public delegate Texture2D TexturePicker(CubismModel3Json sender, CubismDrawable drawable);
  54. #endregion
  55. #region Load Methods
  56. /// <summary>
  57. /// Loads a model.json asset.
  58. /// </summary>
  59. /// <param name="assetPath">The path to the asset.</param>
  60. /// <returns>The <see cref="CubismModel3Json"/> on success; <see langword="null"/> otherwise.</returns>
  61. public static CubismModel3Json LoadAtPath(string assetPath)
  62. {
  63. // Use default asset load handler.
  64. return LoadAtPath(assetPath, BuiltinLoadAssetAtPath);
  65. }
  66. /// <summary>
  67. /// Loads a model.json asset.
  68. /// </summary>
  69. /// <param name="assetPath">The path to the asset.</param>
  70. /// <param name="loadAssetAtPath">Handler for loading assets.</param>
  71. /// <returns>The <see cref="CubismModel3Json"/> on success; <see langword="null"/> otherwise.</returns>
  72. public static CubismModel3Json LoadAtPath(string assetPath, LoadAssetAtPathHandler loadAssetAtPath)
  73. {
  74. // Load Json asset.
  75. var modelJsonAsset = loadAssetAtPath(typeof(string), assetPath) as string;
  76. // Return early in case Json asset wasn't loaded.
  77. if (modelJsonAsset == null)
  78. {
  79. return null;
  80. }
  81. // Deserialize Json.
  82. var modelJson = JsonUtility.FromJson<CubismModel3Json>(modelJsonAsset);
  83. // Finalize deserialization.
  84. modelJson.AssetPath = assetPath;
  85. modelJson.LoadAssetAtPath = loadAssetAtPath;
  86. // Set motion references.
  87. var value = CubismJsonParser.ParseFromString(modelJsonAsset);
  88. // Return early if there is no references.
  89. if (!value.Get("FileReferences").GetMap(null).ContainsKey("Motions"))
  90. {
  91. return modelJson;
  92. }
  93. var motionGroupNames = value.Get("FileReferences").Get("Motions").KeySet().ToArray();
  94. modelJson.FileReferences.Motions.GroupNames = motionGroupNames;
  95. var motionGroupNamesCount = motionGroupNames.Length;
  96. modelJson.FileReferences.Motions.Motions = new SerializableMotion[motionGroupNamesCount][];
  97. for (var i = 0; i < motionGroupNamesCount; i++)
  98. {
  99. var motionGroup = value.Get("FileReferences").Get("Motions").Get(motionGroupNames[i]);
  100. var motionCount = motionGroup.GetVector(null).ToArray().Length;
  101. modelJson.FileReferences.Motions.Motions[i] = new SerializableMotion[motionCount];
  102. var fadeInTime = -1.0f;
  103. var fadeOutTime = -1.0f;
  104. for (var j = 0; j < motionCount; j++)
  105. {
  106. // Reset fade time cache.
  107. fadeInTime = -1.0f;
  108. fadeOutTime = -1.0f;
  109. if (motionGroup.Get(j).GetMap(null).ContainsKey("File"))
  110. {
  111. modelJson.FileReferences.Motions.Motions[i][j].File = motionGroup.Get(j).Get("File").toString();
  112. }
  113. if (motionGroup.Get(j).GetMap(null).ContainsKey("Sound"))
  114. {
  115. modelJson.FileReferences.Motions.Motions[i][j].Sound = motionGroup.Get(j).Get("Sound").toString();
  116. }
  117. if (motionGroup.Get(j).GetMap(null).ContainsKey("FadeInTime"))
  118. {
  119. fadeInTime = motionGroup.Get(j).Get("FadeInTime").ToFloat();
  120. }
  121. modelJson.FileReferences.Motions.Motions[i][j].FadeInTime = fadeInTime;
  122. if (motionGroup.Get(j).GetMap(null).ContainsKey("FadeOutTime"))
  123. {
  124. fadeOutTime = motionGroup.Get(j).Get("FadeOutTime").ToFloat();
  125. }
  126. modelJson.FileReferences.Motions.Motions[i][j].FadeOutTime = fadeOutTime;
  127. }
  128. }
  129. return modelJson;
  130. }
  131. #endregion
  132. /// <summary>
  133. /// Path to <see langword="this"/>.
  134. /// </summary>
  135. public string AssetPath { get; private set; }
  136. /// <summary>
  137. /// Method for loading assets.
  138. /// </summary>
  139. private LoadAssetAtPathHandler LoadAssetAtPath { get; set; }
  140. #region Json Data
  141. /// <summary>
  142. /// The motion3.json format version.
  143. /// </summary>
  144. [SerializeField]
  145. public int Version;
  146. /// <summary>
  147. /// The file references.
  148. /// </summary>
  149. [SerializeField]
  150. public SerializableFileReferences FileReferences;
  151. /// <summary>
  152. /// Groups.
  153. /// </summary>
  154. [SerializeField]
  155. public SerializableGroup[] Groups;
  156. /// <summary>
  157. /// Hit areas.
  158. /// </summary>
  159. [SerializeField]
  160. public SerializableHitArea[] HitAreas;
  161. #endregion
  162. /// <summary>
  163. /// The contents of the referenced moc3 asset.
  164. /// </summary>
  165. /// <remarks>
  166. /// The contents isn't cached internally.
  167. /// </remarks>
  168. public byte[] Moc3
  169. {
  170. get
  171. {
  172. return LoadReferencedAsset<byte[]>(FileReferences.Moc);
  173. }
  174. }
  175. /// <summary>
  176. /// <see cref="CubismPose3Json"/> backing field.
  177. /// </summary>
  178. [NonSerialized]
  179. private CubismPose3Json _pose3Json;
  180. /// <summary>
  181. /// The contents of pose3.json asset.
  182. /// </summary>
  183. public CubismPose3Json Pose3Json
  184. {
  185. get
  186. {
  187. if(_pose3Json != null)
  188. {
  189. return _pose3Json;
  190. }
  191. var jsonString = string.IsNullOrEmpty(FileReferences.Pose) ? null : LoadReferencedAsset<String>(FileReferences.Pose);
  192. _pose3Json = CubismPose3Json.LoadFrom(jsonString);
  193. return _pose3Json;
  194. }
  195. }
  196. /// <summary>
  197. /// <see cref="Expression3Jsons"/> backing field.
  198. /// </summary>
  199. [NonSerialized]
  200. private CubismExp3Json[] _expression3Jsons;
  201. /// <summary>
  202. /// The referenced expression assets.
  203. /// </summary>
  204. /// <remarks>
  205. /// The references aren't cached internally.
  206. /// </remarks>
  207. public CubismExp3Json[] Expression3Jsons
  208. {
  209. get
  210. {
  211. // Fail silently...
  212. if(FileReferences.Expressions == null)
  213. {
  214. return null;
  215. }
  216. // Load expression only if necessary.
  217. if (_expression3Jsons == null)
  218. {
  219. _expression3Jsons = new CubismExp3Json[FileReferences.Expressions.Length];
  220. for (var i = 0; i < _expression3Jsons.Length; ++i)
  221. {
  222. var expressionJson = (string.IsNullOrEmpty(FileReferences.Expressions[i].File))
  223. ? null
  224. : LoadReferencedAsset<string>(FileReferences.Expressions[i].File);
  225. _expression3Jsons[i] = CubismExp3Json.LoadFrom(expressionJson);
  226. }
  227. }
  228. return _expression3Jsons;
  229. }
  230. }
  231. /// <summary>
  232. /// The contents of physics3.json asset.
  233. /// </summary>
  234. public string Physics3Json
  235. {
  236. get
  237. {
  238. return string.IsNullOrEmpty(FileReferences.Physics) ? null : LoadReferencedAsset<string>(FileReferences.Physics);
  239. }
  240. }
  241. public string UserData3Json
  242. {
  243. get
  244. {
  245. return string.IsNullOrEmpty(FileReferences.UserData) ? null : LoadReferencedAsset<string>(FileReferences.UserData);
  246. }
  247. }
  248. /// <summary>
  249. /// The contents of cdi3.json asset.
  250. /// </summary>
  251. public string DisplayInfo3Json
  252. {
  253. get
  254. {
  255. return string.IsNullOrEmpty(FileReferences.DisplayInfo) ? null : LoadReferencedAsset<string>(FileReferences.DisplayInfo);
  256. }
  257. }
  258. /// <summary>
  259. /// <see cref="Textures"/> backing field.
  260. /// </summary>
  261. [NonSerialized]
  262. private Texture2D[] _textures;
  263. /// <summary>
  264. /// The referenced texture assets.
  265. /// </summary>
  266. /// <remarks>
  267. /// The references aren't cached internally.
  268. /// </remarks>
  269. public Texture2D[] Textures
  270. {
  271. get
  272. {
  273. // Load textures only if necessary.
  274. if (_textures == null)
  275. {
  276. _textures = new Texture2D[FileReferences.Textures.Length];
  277. for (var i = 0; i < _textures.Length; ++i)
  278. {
  279. _textures[i] = LoadReferencedAsset<Texture2D>(FileReferences.Textures[i]);
  280. }
  281. }
  282. return _textures;
  283. }
  284. }
  285. #region Constructors
  286. /// <summary>
  287. /// Makes construction only possible through factories.
  288. /// </summary>
  289. private CubismModel3Json()
  290. {
  291. }
  292. #endregion
  293. /// <summary>
  294. /// Instantiates a <see cref="CubismMoc">model source</see> and a <see cref="CubismModel">model</see> with the default texture set.
  295. /// </summary>
  296. /// <param name="shouldImportAsOriginalWorkflow">Should import as original workflow.</param>
  297. /// <returns>The instantiated <see cref="CubismModel">model</see> on success; <see langword="null"/> otherwise.</returns>
  298. public CubismModel ToModel(bool shouldImportAsOriginalWorkflow = false)
  299. {
  300. return ToModel(CubismBuiltinPickers.MaterialPicker, CubismBuiltinPickers.TexturePicker, shouldImportAsOriginalWorkflow);
  301. }
  302. /// <summary>
  303. /// Instantiates a <see cref="CubismMoc">model source</see> and a <see cref="CubismModel">model</see>.
  304. /// </summary>
  305. /// <param name="pickMaterial">The material mapper to use.</param>
  306. /// <param name="pickTexture">The texture mapper to use.</param>
  307. /// <param name="shouldImportAsOriginalWorkflow">Should import as original workflow.</param>
  308. /// <returns>The instantiated <see cref="CubismModel">model</see> on success; <see langword="null"/> otherwise.</returns>
  309. public CubismModel ToModel(MaterialPicker pickMaterial, TexturePicker pickTexture, bool shouldImportAsOriginalWorkflow = false)
  310. {
  311. // Initialize model source and instantiate it.
  312. var mocAsBytes = Moc3;
  313. if (mocAsBytes == null)
  314. {
  315. return null;
  316. }
  317. var moc = CubismMoc.CreateFrom(mocAsBytes);
  318. var model = CubismModel.InstantiateFrom(moc);
  319. if (model == null)
  320. {
  321. return null;
  322. }
  323. model.name = Path.GetFileNameWithoutExtension(FileReferences.Moc);
  324. #if UNITY_EDITOR
  325. // Add parameters and parts inspectors.
  326. model.gameObject.AddComponent<CubismParametersInspector>().hideFlags = HideFlags.DontSaveInBuild;
  327. model.gameObject.AddComponent<CubismPartsInspector>().hideFlags = HideFlags.DontSaveInBuild;
  328. #endif
  329. // Create renderers.
  330. var rendererController = model.gameObject.AddComponent<CubismRenderController>();
  331. var renderers = rendererController.Renderers;
  332. var drawables = model.Drawables;
  333. if (renderers == null || drawables == null)
  334. {
  335. return null;
  336. }
  337. // Initialize materials.
  338. for (var i = 0; i < renderers.Length; ++i)
  339. {
  340. renderers[i].Material = pickMaterial(this, drawables[i]);
  341. }
  342. // Initialize textures.
  343. for (var i = 0; i < renderers.Length; ++i)
  344. {
  345. renderers[i].MainTexture = pickTexture(this, drawables[i]);
  346. }
  347. if (model.Parts != null)
  348. {
  349. var parts = model.Parts;
  350. // Create and initialize partColorsEditors.
  351. for (int i = 0; i < parts.Length; i++)
  352. {
  353. var partColorsEditor = parts[i].gameObject.AddComponent<CubismPartColorsEditor>();
  354. partColorsEditor.TryInitialize(model);
  355. }
  356. }
  357. // Initialize drawables.
  358. if (HitAreas != null)
  359. {
  360. for (var i = 0; i < HitAreas.Length; i++)
  361. {
  362. for (var j = 0; j < drawables.Length; j++)
  363. {
  364. if (drawables[j].Id == HitAreas[i].Id)
  365. {
  366. // Add components for hit judgement to HitArea target Drawables.
  367. var hitDrawable = drawables[j].gameObject.AddComponent<CubismHitDrawable>();
  368. hitDrawable.Name = HitAreas[i].Name;
  369. drawables[j].gameObject.AddComponent<CubismRaycastable>();
  370. break;
  371. }
  372. }
  373. }
  374. }
  375. //Load from cdi3.json
  376. var DisplayInfo3JsonAsString = DisplayInfo3Json;
  377. var cdi3Json = CubismDisplayInfo3Json.LoadFrom(DisplayInfo3JsonAsString);
  378. // Initialize groups.
  379. var parameters = model.Parameters;
  380. for (var i = 0; i < parameters.Length; ++i)
  381. {
  382. if (IsParameterInGroup(parameters[i], "EyeBlink"))
  383. {
  384. if (model.gameObject.GetComponent<CubismEyeBlinkController>() == null)
  385. {
  386. model.gameObject.AddComponent<CubismEyeBlinkController>();
  387. }
  388. parameters[i].gameObject.AddComponent<CubismEyeBlinkParameter>();
  389. }
  390. // Set up mouth parameters.
  391. if (IsParameterInGroup(parameters[i], "LipSync"))
  392. {
  393. if (model.gameObject.GetComponent<CubismMouthController>() == null)
  394. {
  395. model.gameObject.AddComponent<CubismMouthController>();
  396. }
  397. parameters[i].gameObject.AddComponent<CubismMouthParameter>();
  398. }
  399. // Setting up the parameter name for display.
  400. if (cdi3Json != null)
  401. {
  402. var cubismDisplayInfoParameterName = parameters[i].gameObject.AddComponent<CubismDisplayInfoParameterName>();
  403. cubismDisplayInfoParameterName.Name = parameters[i].Id;
  404. for (int j = 0; j < cdi3Json.Parameters.Length; j++)
  405. {
  406. if (cdi3Json.Parameters[j].Id == parameters[i].Id)
  407. {
  408. cubismDisplayInfoParameterName.Name = cdi3Json.Parameters[j].Name;
  409. break;
  410. }
  411. }
  412. cubismDisplayInfoParameterName.DisplayName = string.Empty;
  413. }
  414. }
  415. if (cdi3Json != null)
  416. {
  417. // Setting up the part name for display.
  418. // Initialize groups.
  419. var parts = model.Parts;
  420. for (var i = 0; i < parts.Length; i++)
  421. {
  422. var cubismDisplayInfoPartNames = parts[i].gameObject.AddComponent<CubismDisplayInfoPartName>();
  423. cubismDisplayInfoPartNames.Name = parts[i].Id;
  424. for (int j = 0; j < cdi3Json.Parts.Length; j++)
  425. {
  426. if (cdi3Json.Parts[j].Id == parts[i].Id)
  427. {
  428. cubismDisplayInfoPartNames.Name = cdi3Json.Parts[j].Name;
  429. break;
  430. }
  431. }
  432. cubismDisplayInfoPartNames.DisplayName = string.Empty;
  433. }
  434. // Get combined parameter information
  435. var combinedParameters = cdi3Json.CombinedParameters;
  436. if (combinedParameters != null)
  437. {
  438. // Parameters are always combined in pairs of two.
  439. const int combinedParameterCount = 2;
  440. // Set up CubismDisplayInfoCombinedParameterInfo component.
  441. var combinedParameterInfo = model.gameObject.AddComponent<CubismDisplayInfoCombinedParameterInfo>();
  442. combinedParameterInfo.CombinedParameters = new CubismDisplayInfo3Json.CombinedParameter[combinedParameters.Length];
  443. for (var index = 0; index < combinedParameters.Length; index++)
  444. {
  445. // Skip if the combined parameter is invalid.
  446. if (combinedParameters[index].Ids == null || combinedParameters[index].Ids.Length != combinedParameterCount)
  447. {
  448. Debug.LogWarning($"The data contains invalid CombinedParameters in {model.Moc.name}.cdi3.json.");
  449. continue;
  450. }
  451. var combinedParameterIds = combinedParameters[index].Ids;
  452. // Set CombinedParameter.
  453. combinedParameterInfo.CombinedParameters[index] = new CubismDisplayInfo3Json.CombinedParameter
  454. {
  455. HorizontalParameterId = combinedParameterIds[0],
  456. VerticalParameterId = combinedParameterIds[1]
  457. };
  458. }
  459. }
  460. }
  461. // Add mask controller if required.
  462. for (var i = 0; i < drawables.Length; ++i)
  463. {
  464. if (!drawables[i].IsMasked)
  465. {
  466. continue;
  467. }
  468. // Add controller exactly once...
  469. model.gameObject.AddComponent<CubismMaskController>();
  470. break;
  471. }
  472. // Add original workflow component if is original workflow.
  473. if(shouldImportAsOriginalWorkflow)
  474. {
  475. // Add cubism update manager.
  476. var updateManager = model.gameObject.GetComponent<CubismUpdateController>();
  477. if(updateManager == null)
  478. {
  479. model.gameObject.AddComponent<CubismUpdateController>();
  480. }
  481. // Add parameter store.
  482. var parameterStore = model.gameObject.GetComponent<CubismParameterStore>();
  483. if(parameterStore == null)
  484. {
  485. parameterStore = model.gameObject.AddComponent<CubismParameterStore>();
  486. }
  487. // Add pose controller.
  488. var poseController = model.gameObject.GetComponent<CubismPoseController>();
  489. if(poseController == null)
  490. {
  491. poseController = model.gameObject.AddComponent<CubismPoseController>();
  492. }
  493. // Add expression controller.
  494. var expressionController = model.gameObject.GetComponent<CubismExpressionController>();
  495. if(expressionController == null)
  496. {
  497. expressionController = model.gameObject.AddComponent<CubismExpressionController>();
  498. }
  499. // Add fade controller.
  500. var motionFadeController = model.gameObject.GetComponent<CubismFadeController>();
  501. if(motionFadeController == null)
  502. {
  503. motionFadeController = model.gameObject.AddComponent<CubismFadeController>();
  504. }
  505. }
  506. // Initialize physics if JSON exists.
  507. var physics3JsonAsString = Physics3Json;
  508. if (!string.IsNullOrEmpty(physics3JsonAsString))
  509. {
  510. var physics3Json = CubismPhysics3Json.LoadFrom(physics3JsonAsString);
  511. var physicsController = model.gameObject.GetComponent<CubismPhysicsController>();
  512. if (physicsController == null)
  513. {
  514. physicsController = model.gameObject.AddComponent<CubismPhysicsController>();
  515. }
  516. physicsController.Initialize(physics3Json.ToRig());
  517. }
  518. var userData3JsonAsString = UserData3Json;
  519. if (!string.IsNullOrEmpty(userData3JsonAsString))
  520. {
  521. var userData3Json = CubismUserData3Json.LoadFrom(userData3JsonAsString);
  522. var drawableBodies = userData3Json.ToBodyArray(CubismUserDataTargetType.ArtMesh);
  523. for (var i = 0; i < drawables.Length; ++i)
  524. {
  525. var index = GetBodyIndexById(drawableBodies, drawables[i].Id);
  526. if (index >= 0)
  527. {
  528. var tag = drawables[i].gameObject.GetComponent<CubismUserDataTag>();
  529. if (tag == null)
  530. {
  531. tag = drawables[i].gameObject.AddComponent<CubismUserDataTag>();
  532. }
  533. tag.Initialize(drawableBodies[index]);
  534. }
  535. }
  536. }
  537. if (model.gameObject.GetComponent<Animator>() == null)
  538. {
  539. model.gameObject.AddComponent<Animator>();
  540. }
  541. // Make sure model is 'fresh'
  542. model.ForceUpdateNow();
  543. return model;
  544. }
  545. #region Helper Methods
  546. /// <summary>
  547. /// Type-safely loads an asset.
  548. /// </summary>
  549. /// <typeparam name="T">Asset type.</typeparam>
  550. /// <param name="referencedFile">Path to asset.</param>
  551. /// <returns>The asset on success; <see langword="null"/> otherwise.</returns>
  552. private T LoadReferencedAsset<T>(string referencedFile) where T : class
  553. {
  554. var assetPath = Path.GetDirectoryName(AssetPath) + "/" + referencedFile;
  555. return LoadAssetAtPath(typeof(T), assetPath) as T;
  556. }
  557. /// <summary>
  558. /// Builtin method for loading assets.
  559. /// </summary>
  560. /// <param name="assetType">Asset type.</param>
  561. /// <param name="assetPath">Path to asset.</param>
  562. /// <returns>The asset on success; <see langword="null"/> otherwise.</returns>
  563. private static object BuiltinLoadAssetAtPath(Type assetType, string assetPath)
  564. {
  565. // Explicitly deal with byte arrays.
  566. if (assetType == typeof(byte[]))
  567. {
  568. #if UNITY_EDITOR
  569. return File.ReadAllBytes(assetPath);
  570. #else
  571. var textAsset = Resources.Load(assetPath, typeof(TextAsset)) as TextAsset;
  572. return (textAsset != null)
  573. ? textAsset.bytes
  574. : null;
  575. #endif
  576. }
  577. else if (assetType == typeof(string))
  578. {
  579. #if UNITY_EDITOR
  580. return File.ReadAllText(assetPath);
  581. #else
  582. var textAsset = Resources.Load(assetPath, typeof(TextAsset)) as TextAsset;
  583. return (textAsset != null)
  584. ? textAsset.text
  585. : null;
  586. #endif
  587. }
  588. #if UNITY_EDITOR
  589. return AssetDatabase.LoadAssetAtPath(assetPath, assetType);
  590. #else
  591. return Resources.Load(assetPath, assetType);
  592. #endif
  593. }
  594. /// <summary>
  595. /// Checks whether the parameter is an eye blink parameter.
  596. /// </summary>
  597. /// <param name="parameter">Parameter to check.</param>
  598. /// <param name="groupName">Name of group to query for.</param>
  599. /// <returns><see langword="true"/> if parameter is an eye blink parameter; <see langword="false"/> otherwise.</returns>
  600. private bool IsParameterInGroup(CubismParameter parameter, string groupName)
  601. {
  602. // Return early if groups aren't available...
  603. if (Groups == null || Groups.Length == 0)
  604. {
  605. return false;
  606. }
  607. for (var i = 0; i < Groups.Length; ++i)
  608. {
  609. if (Groups[i].Name != groupName)
  610. {
  611. continue;
  612. }
  613. if(Groups[i].Ids != null)
  614. {
  615. for (var j = 0; j < Groups[i].Ids.Length; ++j)
  616. {
  617. if (Groups[i].Ids[j] == parameter.name)
  618. {
  619. return true;
  620. }
  621. }
  622. }
  623. }
  624. return false;
  625. }
  626. /// <summary>
  627. /// Get body index from body array by Id.
  628. /// </summary>
  629. /// <param name="bodies">Target body array.</param>
  630. /// <param name="id">Id for find.</param>
  631. /// <returns>Array index if Id found; -1 otherwise.</returns>
  632. private int GetBodyIndexById(CubismUserDataBody[] bodies, string id)
  633. {
  634. for (var i = 0; i < bodies.Length; ++i)
  635. {
  636. if (bodies[i].Id == id)
  637. {
  638. return i;
  639. }
  640. }
  641. return -1;
  642. }
  643. #endregion
  644. #region Json Helpers
  645. /// <summary>
  646. /// File references data.
  647. /// </summary>
  648. [Serializable]
  649. public struct SerializableFileReferences
  650. {
  651. /// <summary>
  652. /// Relative path to the moc3 asset.
  653. /// </summary>
  654. [SerializeField]
  655. public string Moc;
  656. /// <summary>
  657. /// Relative paths to texture assets.
  658. /// </summary>
  659. [SerializeField]
  660. public string[] Textures;
  661. /// <summary>
  662. /// Relative path to the pose3.json.
  663. /// </summary>
  664. [SerializeField]
  665. public string Pose;
  666. /// <summary>
  667. /// Relative path to the expression asset.
  668. /// </summary>
  669. [SerializeField]
  670. public SerializableExpression[] Expressions;
  671. /// <summary>
  672. /// Relative path to the pose motion3.json.
  673. /// </summary>
  674. [SerializeField]
  675. public SerializableMotions Motions;
  676. /// <summary>
  677. /// Relative path to the physics asset.
  678. /// </summary>
  679. [SerializeField]
  680. public string Physics;
  681. /// <summary>
  682. /// Relative path to the user data asset.
  683. /// </summary>
  684. [SerializeField]
  685. public string UserData;
  686. /// <summary>
  687. /// Relative path to the cdi3.json.
  688. /// </summary>
  689. [SerializeField]
  690. public string DisplayInfo;
  691. }
  692. /// <summary>
  693. /// Group data.
  694. /// </summary>
  695. [Serializable]
  696. public struct SerializableGroup
  697. {
  698. /// <summary>
  699. /// Target type.
  700. /// </summary>
  701. [SerializeField]
  702. public string Target;
  703. /// <summary>
  704. /// Group name.
  705. /// </summary>
  706. [SerializeField]
  707. public string Name;
  708. /// <summary>
  709. /// Referenced IDs.
  710. /// </summary>
  711. [SerializeField]
  712. public string[] Ids;
  713. }
  714. /// <summary>
  715. /// Expression data.
  716. /// </summary>
  717. [Serializable]
  718. public struct SerializableExpression
  719. {
  720. /// <summary>
  721. /// Expression Name.
  722. /// </summary>
  723. [SerializeField]
  724. public string Name;
  725. /// <summary>
  726. /// Expression File.
  727. /// </summary>
  728. [SerializeField]
  729. public string File;
  730. /// <summary>
  731. /// Expression FadeInTime.
  732. /// </summary>
  733. [SerializeField]
  734. public float FadeInTime;
  735. /// <summary>
  736. /// Expression FadeOutTime.
  737. /// </summary>
  738. [SerializeField]
  739. public float FadeOutTime;
  740. }
  741. /// <summary>
  742. /// Motion data.
  743. /// </summary>
  744. [Serializable]
  745. public struct SerializableMotions
  746. {
  747. /// <summary>
  748. /// Motion group names.
  749. /// </summary>
  750. [SerializeField]
  751. public string[] GroupNames;
  752. /// <summary>
  753. /// Motion groups.
  754. /// </summary>
  755. [SerializeField]
  756. public SerializableMotion[][] Motions;
  757. }
  758. /// <summary>
  759. /// Motion data.
  760. /// </summary>
  761. [Serializable]
  762. public struct SerializableMotion
  763. {
  764. /// <summary>
  765. /// File path.
  766. /// </summary>
  767. [SerializeField]
  768. public string File;
  769. /// <summary>
  770. /// Sound path.
  771. /// </summary>
  772. [SerializeField]
  773. public string Sound;
  774. /// <summary>
  775. /// Fade in time.
  776. /// </summary>
  777. [SerializeField]
  778. public float FadeInTime;
  779. /// <summary>
  780. /// Fade out time.
  781. /// </summary>
  782. [SerializeField]
  783. public float FadeOutTime;
  784. }
  785. /// <summary>
  786. /// Hit Area.
  787. /// </summary>
  788. [Serializable]
  789. public struct SerializableHitArea
  790. {
  791. /// <summary>
  792. /// Hit area name.
  793. /// </summary>
  794. [SerializeField]
  795. public string Name;
  796. /// <summary>
  797. /// Hit area id.
  798. /// </summary>
  799. [SerializeField]
  800. public string Id;
  801. }
  802. #endregion
  803. }
  804. }