CubismMotion3Json.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  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 System;
  8. using System.Collections.Generic;
  9. using Live2D.Cubism.Core;
  10. using Live2D.Cubism.Framework.MouthMovement;
  11. using Live2D.Cubism.Rendering;
  12. #if UNITY_EDITOR
  13. using UnityEditor;
  14. #endif
  15. using UnityEngine;
  16. namespace Live2D.Cubism.Framework.Json
  17. {
  18. /// <summary>
  19. /// Contains Cubism motion3.json data.
  20. /// </summary>
  21. [Serializable]
  22. // ReSharper disable once ClassCannotBeInstantiated
  23. public sealed class CubismMotion3Json
  24. {
  25. #region Load Methods
  26. /// <summary>
  27. /// Loads a motion3.json asset.
  28. /// </summary>
  29. /// <param name="motion3Json">motion3.json to deserialize.</param>
  30. /// <returns>Deserialized motion3.json on success; <see langword="null"/> otherwise.</returns>
  31. public static CubismMotion3Json LoadFrom(string motion3Json)
  32. {
  33. if (string.IsNullOrEmpty(motion3Json))
  34. {
  35. return null;
  36. }
  37. var cubismMotion3Json = JsonUtility.FromJson<CubismMotion3Json>(motion3Json);
  38. cubismMotion3Json.Meta.FadeInTime = -1.0f;
  39. cubismMotion3Json.Meta.FadeOutTime = -1.0f;
  40. for (var i = 0; i < cubismMotion3Json.Curves.Length; ++i)
  41. {
  42. cubismMotion3Json.Curves[i].FadeInTime = -1.0f;
  43. cubismMotion3Json.Curves[i].FadeOutTime = -1.0f;
  44. }
  45. JsonUtility.FromJsonOverwrite(motion3Json, cubismMotion3Json);
  46. return cubismMotion3Json;
  47. }
  48. /// <summary>
  49. /// Loads a motion3.json asset.
  50. /// </summary>
  51. /// <param name="motion3JsonAsset">motion3.json to deserialize.</param>
  52. /// <returns>Deserialized motion3.json on success; <see langword="null"/> otherwise.</returns>
  53. public static CubismMotion3Json LoadFrom(TextAsset motion3JsonAsset)
  54. {
  55. return (motion3JsonAsset == null)
  56. ? null
  57. : LoadFrom(motion3JsonAsset.text);
  58. }
  59. #endregion
  60. #region Json Data
  61. /// <summary>
  62. /// The model3.json format version.
  63. /// </summary>
  64. [SerializeField]
  65. public int Version;
  66. /// <summary>
  67. /// Motion meta info.
  68. /// </summary>
  69. [SerializeField]
  70. public SerializableMeta Meta;
  71. /// <summary>
  72. /// Curves.
  73. /// </summary>
  74. [SerializeField]
  75. public SerializableCurve[] Curves;
  76. /// <summary>
  77. /// User data.
  78. /// </summary>
  79. [SerializeField]
  80. public SerializableUserData[] UserData;
  81. #endregion
  82. #region Constructors
  83. /// <summary>
  84. /// Makes construction only possible through factories.
  85. /// </summary>
  86. private CubismMotion3Json()
  87. {
  88. }
  89. #endregion
  90. /// <summary>
  91. /// Converts motion curve segments into <see cref="Keyframe"/>s.
  92. /// </summary>
  93. /// <param name="segments">Data to convert.</param>
  94. /// <returns>Keyframes.</returns>
  95. public static Keyframe[] ConvertCurveSegmentsToKeyframes(float[] segments)
  96. {
  97. // Return early on invalid input.
  98. if (segments.Length < 1)
  99. {
  100. return new Keyframe[0];
  101. }
  102. // Initialize container for keyframes.
  103. var keyframes = new List<Keyframe> { new Keyframe(segments[0], segments[1]) };
  104. // Parse segments.
  105. for (var i = 2; i < segments.Length;)
  106. {
  107. Parsers[segments[i]](segments, keyframes, ref i);
  108. }
  109. // Return result.
  110. return keyframes.ToArray();
  111. }
  112. /// <summary>
  113. /// Converts stepped curves to liner curves.
  114. /// </summary>
  115. /// <param name="curve">Data to convert.</param>
  116. /// <returns>Animation curve.</returns>
  117. public static AnimationCurve ConvertSteppedCurveToLinerCurver(CubismMotion3Json.SerializableCurve curve, float poseFadeInTime)
  118. {
  119. poseFadeInTime = (poseFadeInTime < 0) ? 0.5f : poseFadeInTime;
  120. var segments = curve.Segments;
  121. var segmentsCount = 2;
  122. for(var index = 2; index < curve.Segments.Length; index += 3)
  123. {
  124. // if current segment type is stepped and
  125. // next segment type is stepped or next segment is last segment
  126. // then convert segment type to liner.
  127. var currentSegmentTypeIsStepped = (curve.Segments[index] == 2);
  128. var currentSegmentIsLast = (index == (curve.Segments.Length - 3));
  129. var nextSegmentTypeIsStepped = (currentSegmentIsLast) ? false : (curve.Segments[index + 3] == 2);
  130. var nextSegmentIsLast = (currentSegmentIsLast) ? false : ((index + 3) == (curve.Segments.Length - 3));
  131. if ( currentSegmentTypeIsStepped && (nextSegmentTypeIsStepped || nextSegmentIsLast) )
  132. {
  133. Array.Resize(ref segments, segments.Length + 3);
  134. segments[segmentsCount + 0] = 0;
  135. segments[segmentsCount + 1] = curve.Segments[index + 1];
  136. segments[segmentsCount + 2] = curve.Segments[index - 1];
  137. segments[segmentsCount + 3] = 0;
  138. segments[segmentsCount + 4] = curve.Segments[index + 1] + poseFadeInTime;
  139. segments[segmentsCount + 5] = curve.Segments[index + 2];
  140. segmentsCount += 6;
  141. }
  142. else if(curve.Segments[index] == 1)
  143. {
  144. segments[segmentsCount + 0] = curve.Segments[index + 0];
  145. segments[segmentsCount + 1] = curve.Segments[index + 1];
  146. segments[segmentsCount + 2] = curve.Segments[index + 2];
  147. segments[segmentsCount + 3] = curve.Segments[index + 3];
  148. segments[segmentsCount + 4] = curve.Segments[index + 4];
  149. segments[segmentsCount + 5] = curve.Segments[index + 5];
  150. segments[segmentsCount + 6] = curve.Segments[index + 6];
  151. index += 4;
  152. segmentsCount += 7;
  153. }
  154. else
  155. {
  156. segments[segmentsCount + 0] = curve.Segments[index + 0];
  157. segments[segmentsCount + 1] = curve.Segments[index + 1];
  158. segments[segmentsCount + 2] = curve.Segments[index + 2];
  159. segmentsCount += 3;
  160. }
  161. }
  162. return new AnimationCurve(ConvertCurveSegmentsToKeyframes(segments));
  163. }
  164. /// <summary>
  165. /// Instantiates an <see cref="AnimationClip"/>.
  166. /// </summary>
  167. /// <param name="shouldImportAsOriginalWorkflow">Should import as original workflow.</param>
  168. /// <param name="shouldClearAnimationCurves">Should clear animation clip curves.</param>
  169. /// <param name="isCallFormModelJson">Is function call form <see cref="CubismModel3Json"/>.</param>
  170. /// <param name="poseJson">pose3.json asset.</param>
  171. /// <returns>The instantiated clip on success; <see langword="null"/> otherwise.</returns>
  172. /// <remarks>
  173. /// Note this method generates <see cref="AnimationClip.legacy"/> clips when called at runtime.
  174. /// </remarks>
  175. public AnimationClip ToAnimationClip(bool shouldImportAsOriginalWorkflow = false, bool shouldClearAnimationCurves = false,
  176. bool isCallFormModelJson = false, CubismPose3Json poseJson = null)
  177. {
  178. // Check béziers restriction flag.
  179. if (!Meta.AreBeziersRestricted)
  180. {
  181. Debug.LogWarning("Béziers are not restricted and curves might be off. Please export motions from Cubism in restricted mode for perfect match.");
  182. }
  183. // Create animation clip.
  184. var animationClip = new AnimationClip
  185. {
  186. #if UNITY_EDITOR
  187. frameRate = Meta.Fps
  188. #else
  189. frameRate = Meta.Fps,
  190. legacy = true,
  191. wrapMode = (Meta.Loop)
  192. ? WrapMode.Loop
  193. : WrapMode.Default
  194. #endif
  195. };
  196. return ToAnimationClip(animationClip, shouldImportAsOriginalWorkflow, shouldClearAnimationCurves, isCallFormModelJson, poseJson);
  197. }
  198. /// <summary>
  199. /// Instantiates an <see cref="AnimationClip"/>.
  200. /// </summary>
  201. /// <param name="animationClip">Previous animation clip.</param>
  202. /// <param name="shouldImportAsOriginalWorkflow">Should import as original workflow.</param>
  203. /// <param name="shouldClearAnimationCurves">Should clear animation clip curves.</param>
  204. /// <param name="isCallFormModelJson">Is function call form <see cref="CubismModel3Json"/>.</param>
  205. /// <param name="poseJson">pose3.json asset.</param>
  206. /// <returns>The instantiated clip on success; <see langword="null"/> otherwise.</returns>
  207. /// <remarks>
  208. /// Note this method generates <see cref="AnimationClip.legacy"/> clips when called at runtime.
  209. /// </remarks>
  210. public AnimationClip ToAnimationClip(AnimationClip animationClip, bool shouldImportAsOriginalWorkflow = false, bool shouldClearAnimationCurves = false
  211. , bool isCallFormModelJson = false, CubismPose3Json poseJson = null)
  212. {
  213. // Clear curves.
  214. if (shouldClearAnimationCurves && (!shouldImportAsOriginalWorkflow || (isCallFormModelJson && shouldImportAsOriginalWorkflow)))
  215. {
  216. animationClip.ClearCurves();
  217. }
  218. // Convert curves.
  219. for (var i = 0; i < Curves.Length; ++i)
  220. {
  221. var curve = Curves[i];
  222. // If should import as original workflow mode, skip add part opacity curve when call not from model3.json.
  223. if (curve.Target == "PartOpacity" && shouldImportAsOriginalWorkflow && !isCallFormModelJson)
  224. {
  225. continue;
  226. }
  227. var relativePath = string.Empty;
  228. var type = default(Type);
  229. var propertyName = string.Empty;
  230. var animationCurve = new AnimationCurve(ConvertCurveSegmentsToKeyframes(curve.Segments));
  231. // Create model binding.
  232. if (curve.Target == "Model")
  233. {
  234. // Bind opacity.
  235. if (curve.Id == "Opacity")
  236. {
  237. relativePath = string.Empty;
  238. propertyName = "Opacity";
  239. type = typeof(CubismRenderController);
  240. }
  241. // Bind eye-blink.
  242. else if (curve.Id == "EyeBlink")
  243. {
  244. relativePath = string.Empty;
  245. propertyName = "EyeOpening";
  246. type = typeof(CubismEyeBlinkController);
  247. }
  248. // Bind lip-sync.
  249. else if (curve.Id == "LipSync")
  250. {
  251. relativePath = string.Empty;
  252. propertyName = "MouthOpening";
  253. type = typeof(CubismMouthController);
  254. }
  255. }
  256. // Create parameter binding.
  257. else if (curve.Target == "Parameter")
  258. {
  259. relativePath = "Parameters/" + curve.Id;
  260. propertyName = "Value";
  261. type = typeof(CubismParameter);
  262. }
  263. // Create part opacity binding.
  264. else if (curve.Target == "PartOpacity")
  265. {
  266. relativePath = "Parts/" + curve.Id;
  267. propertyName = "Opacity";
  268. type = typeof(CubismPart);
  269. // original workflow.
  270. if (shouldImportAsOriginalWorkflow && poseJson != null && poseJson.FadeInTime != 0.0f)
  271. {
  272. animationCurve = ConvertSteppedCurveToLinerCurver(curve, poseJson.FadeInTime);
  273. }
  274. }
  275. #if UNITY_EDITOR
  276. var curveBinding = new EditorCurveBinding
  277. {
  278. path = relativePath,
  279. propertyName = propertyName,
  280. type = type
  281. };
  282. AnimationUtility.SetEditorCurve(animationClip, curveBinding, animationCurve);
  283. #else
  284. animationClip.SetCurve(relativePath, type, propertyName, animationCurve);
  285. #endif
  286. }
  287. #if UNITY_EDITOR
  288. // Apply settings.
  289. var animationClipSettings = new AnimationClipSettings
  290. {
  291. loopTime = Meta.Loop,
  292. stopTime = Meta.Duration
  293. };
  294. AnimationUtility.SetAnimationClipSettings(animationClip, animationClipSettings);
  295. #endif
  296. #if UNITY_EDITOR
  297. // Add animation events from user data.
  298. if (UserData != null)
  299. {
  300. var animationEvents = new List<AnimationEvent>();
  301. for (var i = 0; i < UserData.Length; ++i)
  302. {
  303. var animationEvent = new AnimationEvent
  304. {
  305. time = UserData[i].Time,
  306. stringParameter = UserData[i].Value,
  307. };
  308. animationEvents.Add(animationEvent);
  309. }
  310. if (animationEvents.Count > 0)
  311. {
  312. AnimationUtility.SetAnimationEvents(animationClip, animationEvents.ToArray());
  313. }
  314. }
  315. #endif
  316. return animationClip;
  317. }
  318. #region Segment Parsing
  319. /// <summary>
  320. /// Offset to use for setting of keyframes.
  321. /// </summary>
  322. private const float OffsetGranularity = 0.01f;
  323. /// <summary>
  324. /// Handles parsing of a single segment.
  325. /// </summary>
  326. /// <param name="segments">Curve segments.</param>
  327. /// <param name="result">Buffer to append result to.</param>
  328. /// <param name="position">Offset of segment.</param>
  329. private delegate void SegmentParser(float[] segments, List<Keyframe> result, ref int position);
  330. /// <summary>
  331. /// Available segment parsers.
  332. /// </summary>
  333. // ReSharper disable once InconsistentNaming
  334. private static Dictionary<float, SegmentParser> Parsers = new Dictionary<float, SegmentParser>
  335. {
  336. {0f, ParseLinearSegment},
  337. {1f, ParseBezierSegment},
  338. {2f, ParseSteppedSegment},
  339. {3f, ParseInverseSteppedSegment}
  340. };
  341. /// <summary>
  342. /// Parses a linear segment.
  343. /// </summary>
  344. /// <param name="segments">Curve segments.</param>
  345. /// <param name="result">Buffer to append result to.</param>
  346. /// <param name="position">Offset of segment.</param>
  347. private static void ParseLinearSegment(float[] segments, List<Keyframe> result, ref int position)
  348. {
  349. // Compute slope.
  350. var length = (segments[position + 1] - result[result.Count - 1].time);
  351. var slope = (segments[position + 2] - result[result.Count - 1].value) / length;
  352. // Determine tangents.
  353. var outTangent = slope;
  354. var inTangent = outTangent;
  355. // Create keyframes.
  356. var keyframe = new Keyframe(
  357. result[result.Count - 1].time,
  358. result[result.Count - 1].value,
  359. result[result.Count - 1].inTangent,
  360. outTangent);
  361. result[result.Count - 1] = keyframe;
  362. keyframe = new Keyframe(
  363. segments[position + 1],
  364. segments[position + 2],
  365. inTangent,
  366. 0);
  367. result.Add(keyframe);
  368. // Update position.
  369. position += 3;
  370. }
  371. /// <summary>
  372. /// Parses a bezier segment.
  373. /// </summary>
  374. /// <param name="segments">Curve segments.</param>
  375. /// <param name="result">Buffer to append result to.</param>
  376. /// <param name="position">Offset of segment.</param>
  377. private static void ParseBezierSegment(float[] segments, List<Keyframe> result, ref int position)
  378. {
  379. // Compute tangents.
  380. var tangentLength = Mathf.Abs(result[result.Count - 1].time - segments[position + 5]) * 0.333333f;
  381. var outTangent = (segments[position + 2] - result[result.Count - 1].value) / tangentLength;
  382. var inTangent = (segments[position + 6] - segments[position + 4]) / tangentLength;
  383. // Create keyframes.
  384. var keyframe = new Keyframe(
  385. result[result.Count - 1].time,
  386. result[result.Count - 1].value,
  387. result[result.Count - 1].inTangent,
  388. outTangent);
  389. result[result.Count - 1] = keyframe;
  390. keyframe = new Keyframe(
  391. segments[position + 5],
  392. segments[position + 6],
  393. inTangent,
  394. 0);
  395. result.Add(keyframe);
  396. // Update position.
  397. position += 7;
  398. }
  399. /// <summary>
  400. /// Parses a stepped segment.
  401. /// </summary>
  402. /// <param name="segments">Curve segments.</param>
  403. /// <param name="result">Buffer to append result to.</param>
  404. /// <param name="position">Offset of segment.</param>
  405. private static void ParseSteppedSegment(float[] segments, List<Keyframe> result, ref int position)
  406. {
  407. // Create keyframe.
  408. result.Add(
  409. new Keyframe(segments[position + 1], segments[position + 2])
  410. {
  411. inTangent = float.PositiveInfinity
  412. });
  413. // Update position.
  414. position += 3;
  415. }
  416. /// <summary>
  417. /// Parses a inverse-stepped segment.
  418. /// </summary>
  419. /// <param name="segments">Curve segments.</param>
  420. /// <param name="result">Buffer to append result to.</param>
  421. /// <param name="position">Offset of segment.</param>
  422. private static void ParseInverseSteppedSegment(float[] segments, List<Keyframe> result, ref int position)
  423. {
  424. // Compute tangents.
  425. var keyframe = result[result.Count - 1];
  426. var tangent = (float)Math.Atan2(
  427. (segments[position + 2] - keyframe.value),
  428. (segments[position + 1] - keyframe.time));
  429. keyframe.outTangent = tangent;
  430. result[result.Count - 1] = keyframe;
  431. result.Add(
  432. new Keyframe(keyframe.time + OffsetGranularity, segments[position + 2])
  433. {
  434. inTangent = tangent,
  435. outTangent = 0
  436. });
  437. result.Add(
  438. new Keyframe(segments[position + 1], segments[position + 2])
  439. {
  440. inTangent = 0
  441. });
  442. // Update position.
  443. position += 3;
  444. }
  445. #endregion
  446. #region Json Object Types
  447. /// <summary>
  448. /// Motion meta info.
  449. /// </summary>
  450. [Serializable]
  451. public struct SerializableMeta
  452. {
  453. /// <summary>
  454. /// Duration in seconds.
  455. /// </summary>
  456. [SerializeField]
  457. public float Duration;
  458. /// <summary>
  459. /// Framerate in seconds.
  460. /// </summary>
  461. [SerializeField]
  462. public float Fps;
  463. /// <summary>
  464. /// True if motion is looping.
  465. /// </summary>
  466. [SerializeField]
  467. public bool Loop;
  468. /// <summary>
  469. /// Number of curves.
  470. /// </summary>
  471. [SerializeField]
  472. public int CurveCount;
  473. /// <summary>
  474. /// Total number of curve segments.
  475. /// </summary>
  476. [SerializeField]
  477. public int TotalSegmentCount;
  478. /// <summary>
  479. /// Total number of curve points.
  480. /// </summary>
  481. [SerializeField]
  482. public int TotalPointCount;
  483. /// <summary>
  484. /// True if beziers are restricted.
  485. /// </summary>
  486. [SerializeField]
  487. public bool AreBeziersRestricted;
  488. /// <summary>
  489. /// Total number of UserData.
  490. /// </summary>
  491. [SerializeField]
  492. public int UserDataCount;
  493. /// <summary>
  494. /// Total size of UserData in bytes.
  495. /// </summary>
  496. [SerializeField]
  497. public int TotalUserDataSize;
  498. /// <summary>
  499. /// [Optional] Time of the Fade-In for easing in seconds.
  500. /// </summary>
  501. [SerializeField]
  502. public float FadeInTime;
  503. /// <summary>
  504. /// [Optional] Time of the Fade-Out for easing in seconds.
  505. /// </summary>
  506. [SerializeField]
  507. public float FadeOutTime;
  508. };
  509. /// <summary>
  510. /// Single motion curve.
  511. /// </summary>
  512. [Serializable]
  513. public struct SerializableCurve
  514. {
  515. /// <summary>
  516. /// Target type.
  517. /// </summary>
  518. [SerializeField]
  519. public string Target;
  520. /// <summary>
  521. /// Id within target.
  522. /// </summary>
  523. [SerializeField]
  524. public string Id;
  525. /// <summary>
  526. /// Flattened curve segments.
  527. /// </summary>
  528. [SerializeField]
  529. public float[] Segments;
  530. /// <summary>
  531. /// [Optional] Time of the overall Fade-In for easing in seconds.
  532. /// </summary>
  533. [SerializeField]
  534. public float FadeInTime;
  535. /// <summary>
  536. /// [Optional] Time of the overall Fade-Out for easing in seconds.
  537. /// </summary>
  538. [SerializeField]
  539. public float FadeOutTime;
  540. };
  541. /// <summary>
  542. /// User data.
  543. /// </summary>
  544. [Serializable]
  545. public struct SerializableUserData
  546. {
  547. /// <summary>
  548. /// Time in seconds.
  549. /// </summary>
  550. [SerializeField]
  551. public float Time;
  552. /// <summary>
  553. /// Content of user data.
  554. /// </summary>
  555. [SerializeField]
  556. public string Value;
  557. }
  558. #endregion
  559. }
  560. }