ClothEditor.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. // Magica Cloth.
  2. // Copyright (c) MagicaSoft, 2020-2022.
  3. // https://magicasoft.jp
  4. using System.Collections.Generic;
  5. using UnityEditor;
  6. using UnityEngine;
  7. namespace MagicaCloth
  8. {
  9. /// <summary>
  10. /// クロス用のエディタ拡張
  11. /// </summary>
  12. public abstract class ClothEditor : Editor
  13. {
  14. /// <summary>
  15. /// ポイントセレクタークラス
  16. /// </summary>
  17. PointSelector pointSelector = new PointSelector();
  18. /// <summary>
  19. /// 現在編集中の選択データ
  20. /// </summary>
  21. List<int> selectorData = new List<int>();
  22. /// <summary>
  23. /// アクティブなエディタメッシュインターフェース
  24. /// </summary>
  25. IEditorMesh editorMesh;
  26. //=========================================================================================
  27. protected virtual void OnEnable()
  28. {
  29. pointSelector.EnableEdit();
  30. }
  31. protected virtual void OnDisable()
  32. {
  33. pointSelector.DisableEdit(this);
  34. }
  35. /// <summary>
  36. /// 選択データの初期化
  37. /// 配列はすでに頂点数分が確保されゼロクリアされています。
  38. /// すでに選択データがある場合はここでselectorDataにデータをセットしてください。
  39. /// </summary>
  40. /// <param name="selectorData"></param>
  41. protected virtual void OnResetSelector(List<int> selectorData) { }
  42. /// <summary>
  43. /// 選択データの決定
  44. /// </summary>
  45. /// <param name="selectorData"></param>
  46. protected virtual void OnFinishSelector(List<int> selectorData) { }
  47. /// <summary>
  48. /// ポイント選択GUIの表示と制御
  49. /// </summary>
  50. /// <param name="clothData"></param>
  51. /// <param name="editorMesh"></param>
  52. protected void DrawInspectorGUI(IEditorMesh editorMesh)
  53. {
  54. this.editorMesh = editorMesh;
  55. if (editorMesh == null)
  56. return;
  57. pointSelector.DrawInspectorGUI(this, StartEdit, EndEdit);
  58. }
  59. /// <summary>
  60. /// 共有選択データを初期化する
  61. /// </summary>
  62. protected void InitSelectorData()
  63. {
  64. // メッシュデータ
  65. List<Vector3> wposList;
  66. List<Vector3> wnorList;
  67. List<Vector3> wtanList;
  68. int meshVertexCount = editorMesh.GetEditorPositionNormalTangent(out wposList, out wnorList, out wtanList);
  69. // 選択データ初期化
  70. selectorData.Clear();
  71. for (int i = 0; i < meshVertexCount; i++)
  72. selectorData.Add(0); // Invalid
  73. // 基本設定
  74. OnResetSelector(selectorData);
  75. // 共有データ作成
  76. OnFinishSelector(selectorData);
  77. }
  78. //=============================================================================================
  79. /// <summary>
  80. /// 作成を実行できるか判定する
  81. /// </summary>
  82. /// <returns></returns>
  83. protected abstract bool CheckCreate();
  84. //=============================================================================================
  85. /// <summary>
  86. /// ポイント選択開始
  87. /// </summary>
  88. /// <param name="pointSelector"></param>
  89. void StartEdit(PointSelector pointSelector)
  90. {
  91. // 毎回初期化する
  92. // 各ポイントのタイプ情報を設定
  93. pointSelector.AddPointType("Move Point", Color.green, SelectionData.Move);
  94. pointSelector.AddPointType("Fixed Point", Color.red, SelectionData.Fixed);
  95. pointSelector.AddPointType("Invalid Point", Color.gray, SelectionData.Invalid);
  96. // メッシュデータ
  97. List<Vector3> wposList;
  98. List<Vector3> wnorList;
  99. List<Vector3> wtanList;
  100. int meshVertexCount = editorMesh.GetEditorPositionNormalTangent(out wposList, out wnorList, out wtanList);
  101. // 選択データ初期化
  102. selectorData.Clear();
  103. for (int i = 0; i < meshVertexCount; i++)
  104. selectorData.Add(0); // Invalid
  105. OnResetSelector(selectorData);
  106. if (meshVertexCount == 0)
  107. return;
  108. // 各ポイントデータをセレクタークラスへ流し込む
  109. for (int i = 0; i < meshVertexCount; i++)
  110. {
  111. pointSelector.AddPoint(wposList[i], i, selectorData[i]);
  112. }
  113. }
  114. /// <summary>
  115. /// ポイント選択終了
  116. /// </summary>
  117. /// <param name="pointSelector"></param>
  118. void EndEdit(PointSelector pointSelector)
  119. {
  120. // 現在のポイント内容をデータに反映
  121. var pointList = pointSelector.GetPointList();
  122. foreach (var p in pointList)
  123. {
  124. selectorData[p.index] = p.value;
  125. }
  126. // 確定
  127. OnFinishSelector(selectorData);
  128. }
  129. /// <summary>
  130. /// 新規選択クラスを作成して返す
  131. /// </summary>
  132. /// <param name="obj"></param>
  133. /// <param name="property"></param>
  134. /// <returns></returns>
  135. protected SelectionData CreateSelection(MonoBehaviour obj, string property)
  136. {
  137. string dataname = "SelectionData_" + obj.name;
  138. var selection = ShareDataObject.CreateShareData<SelectionData>(dataname);
  139. return selection;
  140. }
  141. /// <summary>
  142. /// 選択クラスをプロパティに保存する
  143. /// </summary>
  144. /// <param name="obj"></param>
  145. /// <param name="property"></param>
  146. /// <param name="selectionData"></param>
  147. protected void ApplySelection(MonoBehaviour obj, string property, SelectionData selectionData)
  148. {
  149. var so = new SerializedObject(obj);
  150. var sel = so.FindProperty(property);
  151. sel.objectReferenceValue = selectionData;
  152. so.ApplyModifiedProperties();
  153. }
  154. //=========================================================================================
  155. /// <summary>
  156. /// チーム項目インスペクタ
  157. /// </summary>
  158. protected void TeamBasicInspector()
  159. {
  160. BaseCloth scr = target as BaseCloth;
  161. EditorGUILayout.Space();
  162. EditorGUILayout.Space();
  163. EditorGUILayout.PropertyField(serializedObject.FindProperty("updateMode"));
  164. EditorGUILayout.Slider(serializedObject.FindProperty("userBlendWeight"), 0.0f, 1.0f, "Blend Weight");
  165. }
  166. protected void CullingInspector()
  167. {
  168. BaseCloth scr = target as BaseCloth;
  169. EditorGUILayout.Space();
  170. EditorGUILayout.Space();
  171. EditorGUILayout.LabelField("Culling", EditorStyles.boldLabel);
  172. EditorGUILayout.PropertyField(serializedObject.FindProperty("cullingMode"));
  173. if (scr is MagicaBoneCloth || scr is MagicaBoneSpring)
  174. {
  175. if (scr.CullingMode != PhysicsTeam.TeamCullingMode.Off)
  176. {
  177. // warning
  178. if (scr.GetCullRenderListCount() == 0)
  179. {
  180. EditorGUILayout.HelpBox("If you want to cull, you need to register the renderer that makes the display decision here.\nIf not registered, culling will not be performed.", MessageType.Warning);
  181. }
  182. //EditorGUILayout.PropertyField(serializedObject.FindProperty("cullRendererList"));
  183. EditorInspectorUtility.DrawObjectList<Renderer>(
  184. serializedObject.FindProperty("cullRendererList"),
  185. scr.gameObject,
  186. true, true,
  187. SearchBoneClothRenderer,
  188. "Auto Select"
  189. );
  190. }
  191. }
  192. }
  193. /// <summary>
  194. /// BoneCloth/Springのボーンの対象となっているレンダラーを検索する
  195. /// </summary>
  196. /// <returns></returns>
  197. private Renderer[] SearchBoneClothRenderer()
  198. {
  199. BaseCloth scr = target as BaseCloth;
  200. if (scr is MagicaBoneCloth || scr is MagicaBoneSpring)
  201. {
  202. var rendererList = new List<Renderer>();
  203. var skinRendererSet = new HashSet<SkinnedMeshRenderer>();
  204. // search all bone
  205. var boneSet = new HashSet<Transform>();
  206. var property = serializedObject.FindProperty("clothTarget.rootList");
  207. for (int i = 0; i < property.arraySize; i++)
  208. {
  209. var boneRoot = property.GetArrayElementAtIndex(i).objectReferenceValue as Transform;
  210. if (boneRoot)
  211. {
  212. // all transform
  213. var tlist = boneRoot.GetComponentsInChildren<Transform>();
  214. if (tlist != null)
  215. {
  216. foreach (var t in tlist)
  217. boneSet.Add(t);
  218. }
  219. // mesh renderer
  220. var rlist = boneRoot.GetComponentsInChildren<MeshRenderer>();
  221. if (rlist != null)
  222. rendererList.AddRange(rlist);
  223. // skin renderer
  224. Transform root = boneRoot;
  225. while (root.parent)
  226. {
  227. if (root.GetComponent<Animator>() != null || root.GetComponent<Animation>() != null)
  228. break;
  229. root = root.parent;
  230. }
  231. var srlist = root.GetComponentsInChildren<SkinnedMeshRenderer>();
  232. if (srlist != null)
  233. {
  234. foreach (var skin in srlist)
  235. skinRendererSet.Add(skin);
  236. }
  237. }
  238. }
  239. //foreach (var t in boneSet)
  240. // Debug.Log(t);
  241. // skinrenderer
  242. foreach (var skin in skinRendererSet)
  243. {
  244. //Debug.Log(skin);
  245. var useBoneList = MeshUtility.GetUseBoneTransformList(skin.bones, skin.sharedMesh);
  246. foreach (var bone in useBoneList)
  247. {
  248. if (boneSet.Contains(bone))
  249. {
  250. rendererList.Add(skin);
  251. break;
  252. }
  253. }
  254. }
  255. return rendererList.ToArray();
  256. }
  257. else
  258. return null;
  259. }
  260. /// <summary>
  261. /// コライダー設定インスペクタ
  262. /// </summary>
  263. protected void ColliderInspector()
  264. {
  265. PhysicsTeam scr = target as PhysicsTeam;
  266. EditorGUILayout.Space();
  267. EditorGUILayout.Space();
  268. EditorGUILayout.LabelField("Collider", EditorStyles.boldLabel);
  269. EditorGUILayout.PropertyField(serializedObject.FindProperty("teamData.mergeAvatarCollider"));
  270. EditorInspectorUtility.DrawObjectList<ColliderComponent>(
  271. serializedObject.FindProperty("teamData.colliderList"),
  272. scr.gameObject,
  273. true, true,
  274. () => scr.gameObject.transform.root.GetComponentsInChildren<ColliderComponent>()
  275. );
  276. }
  277. /// <summary>
  278. /// スキニング設定インスペクタ
  279. /// </summary>
  280. protected void SkinningInspector()
  281. {
  282. PhysicsTeam scr = target as PhysicsTeam;
  283. var mode = serializedObject.FindProperty("skinningMode");
  284. //var boneList = serializedObject.FindProperty("teamData.skinningBoneList");
  285. EditorGUILayout.Space();
  286. EditorGUILayout.LabelField("Skinning", EditorStyles.boldLabel);
  287. EditorGUILayout.PropertyField(mode, new GUIContent("Skinning Mode"), true);
  288. //if (scr.SkinningMode == PhysicsTeam.TeamSkinningMode.GenerateFromBones)
  289. //{
  290. // var updateFixed = serializedObject.FindProperty("skinningUpdateFixed");
  291. // EditorGUILayout.PropertyField(updateFixed, new GUIContent("Update Fixed"), true);
  292. //}
  293. //EditorGUILayout.PropertyField(boneList, new GUIContent("Skinning Bone List"), true);
  294. }
  295. /// <summary>
  296. /// 古いパラメータを最新アルゴリズム用にコンバートする
  297. /// </summary>
  298. protected void ConvertToLatestAlgorithmParameters()
  299. {
  300. BaseCloth cloth = target as BaseCloth;
  301. Debug.Log($"[{cloth.name}] Convert Parameters.");
  302. Undo.RecordObject(cloth, "Convert Parameters");
  303. cloth.Params.ConvertToLatestAlgorithmParameter();
  304. serializedObject.ApplyModifiedProperties();
  305. EditorUtility.SetDirty(cloth);
  306. }
  307. }
  308. }