MagicaCapsuleCollider.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. // Magica Cloth.
  2. // Copyright (c) MagicaSoft, 2020-2022.
  3. // https://magicasoft.jp
  4. using Unity.Mathematics;
  5. using UnityEngine;
  6. namespace MagicaCloth
  7. {
  8. /// <summary>
  9. /// カプセルコライダー
  10. /// </summary>
  11. [HelpURL("https://magicasoft.jp/magica-cloth-capsule-collider/")]
  12. [AddComponentMenu("MagicaCloth/MagicaCapsuleCollider")]
  13. public class MagicaCapsuleCollider : ColliderComponent
  14. {
  15. // 軸
  16. public enum Axis
  17. {
  18. X,
  19. Y,
  20. Z,
  21. }
  22. [SerializeField]
  23. private Axis axis = Axis.X;
  24. [SerializeField]
  25. [Range(0, 1)]
  26. private float length = 0.2f;
  27. [SerializeField]
  28. [Range(0.0f, 0.5f)]
  29. private float startRadius = 0.1f;
  30. [SerializeField]
  31. [Range(0.0f, 0.5f)]
  32. private float endRadius = 0.1f;
  33. //=========================================================================================
  34. public override ComponentType GetComponentType()
  35. {
  36. return ComponentType.CapsuleCollider;
  37. }
  38. private void OnValidate()
  39. {
  40. if (Application.isPlaying)
  41. DataUpdate();
  42. }
  43. /// <summary>
  44. /// パーティクルのデータ更新処理
  45. /// </summary>
  46. internal override void DataUpdate()
  47. {
  48. base.DataUpdate();
  49. foreach (var c in particleDict.Values)
  50. {
  51. for (int i = 0; i < c.dataLength; i++)
  52. {
  53. int pindex = c.startIndex + i;
  54. // カプセルデータ
  55. float3 radius = new float3(length, startRadius, endRadius);
  56. MagicaPhysicsManager.Instance.Particle.SetRadius(pindex, radius);
  57. // localPos
  58. MagicaPhysicsManager.Instance.Particle.SetLocalPos(pindex, Center);
  59. // カプセルフラグ再設定
  60. var flag = MagicaPhysicsManager.Instance.Particle.flagList[pindex];
  61. flag.SetFlag(PhysicsManagerParticleData.Flag_CapsuleX, false);
  62. flag.SetFlag(PhysicsManagerParticleData.Flag_CapsuleY, false);
  63. flag.SetFlag(PhysicsManagerParticleData.Flag_CapsuleZ, false);
  64. flag.SetFlag(GetCapsuleFlag(), true);
  65. MagicaPhysicsManager.Instance.Particle.flagList[pindex] = flag;
  66. }
  67. }
  68. }
  69. /// <summary>
  70. /// データハッシュ計算
  71. /// </summary>
  72. /// <returns></returns>
  73. public override int GetDataHash()
  74. {
  75. int hash = base.GetDataHash();
  76. hash += axis.GetDataHash();
  77. hash += length.GetDataHash();
  78. hash += startRadius.GetDataHash();
  79. hash += endRadius.GetDataHash();
  80. return hash;
  81. }
  82. //=========================================================================================
  83. public Axis AxisMode
  84. {
  85. get
  86. {
  87. return axis;
  88. }
  89. set
  90. {
  91. axis = value;
  92. ReserveDataUpdate();
  93. }
  94. }
  95. public float Length
  96. {
  97. get
  98. {
  99. return length;
  100. }
  101. set
  102. {
  103. length = value;
  104. ReserveDataUpdate();
  105. }
  106. }
  107. public float StartRadius
  108. {
  109. get
  110. {
  111. return startRadius;
  112. }
  113. set
  114. {
  115. startRadius = value;
  116. ReserveDataUpdate();
  117. }
  118. }
  119. public float EndRadius
  120. {
  121. get
  122. {
  123. return endRadius;
  124. }
  125. set
  126. {
  127. endRadius = value;
  128. ReserveDataUpdate();
  129. }
  130. }
  131. protected override ChunkData CreateColliderParticleReal(int teamId)
  132. {
  133. uint flag = 0;
  134. flag |= PhysicsManagerParticleData.Flag_Kinematic;
  135. flag |= PhysicsManagerParticleData.Flag_Collider;
  136. flag |= GetCapsuleFlag();
  137. flag |= PhysicsManagerParticleData.Flag_Transform_Read_Base;
  138. flag |= PhysicsManagerParticleData.Flag_Step_Update;
  139. flag |= PhysicsManagerParticleData.Flag_Reset_Position;
  140. flag |= PhysicsManagerParticleData.Flag_Transform_Read_Local;
  141. //flag |= PhysicsManagerParticleData.Flag_Transform_Read_Scl; // 現在スケールは見ていない
  142. // radiusにカプセルのデータを入れる
  143. float3 radius = new float3(length, startRadius, endRadius);
  144. var c = CreateParticle(
  145. flag,
  146. teamId, // team
  147. 0.0f, // depth
  148. radius,
  149. Center
  150. );
  151. if (c.IsValid())
  152. MagicaPhysicsManager.Instance.Team.AddCollider(teamId, c.startIndex);
  153. return c;
  154. }
  155. /// <summary>
  156. /// 設定軸に対応するカプセルフラグを返す
  157. /// </summary>
  158. /// <returns></returns>
  159. uint GetCapsuleFlag()
  160. {
  161. if (axis == Axis.X)
  162. return PhysicsManagerParticleData.Flag_CapsuleX;
  163. else if (axis == Axis.Y)
  164. return PhysicsManagerParticleData.Flag_CapsuleY;
  165. else
  166. return PhysicsManagerParticleData.Flag_CapsuleZ;
  167. }
  168. /// <summary>
  169. /// カプセルのローカル方向を返す
  170. /// </summary>
  171. /// <returns></returns>
  172. public Vector3 GetLocalDir()
  173. {
  174. if (axis == Axis.X)
  175. return Vector3.right;
  176. else if (axis == Axis.Y)
  177. return Vector3.up;
  178. else
  179. return Vector3.forward;
  180. }
  181. /// <summary>
  182. /// カプセルのローカル上方向を返す
  183. /// </summary>
  184. /// <returns></returns>
  185. public Vector3 GetLocalUp()
  186. {
  187. if (axis == Axis.X)
  188. return Vector3.up;
  189. else if (axis == Axis.Y)
  190. return Vector3.forward;
  191. else
  192. return Vector3.up;
  193. }
  194. /// <summary>
  195. /// カプセルのスケール値を取得
  196. /// 方向軸のスケール値を採用する
  197. /// </summary>
  198. /// <returns></returns>
  199. public float GetScale()
  200. {
  201. var scl = transform.lossyScale;
  202. if (axis == Axis.X)
  203. return scl.x;
  204. else if (axis == Axis.Y)
  205. return scl.y;
  206. else
  207. return scl.z;
  208. }
  209. /// <summary>
  210. /// 指定座標に最も近い衝突点pと、中心軸からのpへの方向dirを返す。
  211. /// ※エディタ計算用
  212. /// </summary>
  213. /// <param name="pos"></param>
  214. /// <param name="p"></param>
  215. /// <param name="dir"></param>
  216. public override bool CalcNearPoint(Vector3 pos, out Vector3 p, out Vector3 dir, out Vector3 d, bool skinning)
  217. {
  218. dir = Vector3.zero;
  219. var ldir = GetLocalDir();
  220. var l = ldir * Length;
  221. //var tpos = transform.position;
  222. var tpos = transform.TransformPoint(Center);
  223. var trot = transform.rotation;
  224. float scl = GetScale();
  225. l *= scl;
  226. var spos = trot * -l + tpos;
  227. var epos = trot * l + tpos;
  228. #if true
  229. // 半径分長さ拡張
  230. if (skinning == false)
  231. {
  232. const float ratio = 0.5f;
  233. spos = trot * (-l - ldir * StartRadius * scl * ratio) + tpos;
  234. epos = trot * (l + ldir * EndRadius * scl * ratio) + tpos;
  235. }
  236. #endif
  237. float t = MathUtility.ClosestPtPointSegmentRatio(pos, spos, epos);
  238. #if true
  239. // 蓋の部分は無効とする
  240. if (skinning == false)
  241. {
  242. if (t < 0.0001f || t > 0.9999f)
  243. {
  244. p = Vector3.zero;
  245. d = Vector3.zero;
  246. return false;
  247. }
  248. }
  249. #endif
  250. float cr = Mathf.Lerp(StartRadius * scl, EndRadius * scl, t);
  251. d = spos + (epos - spos) * t; // 中心軸位置
  252. var v = pos - d;
  253. float vlen = v.magnitude;
  254. if (vlen < cr)
  255. {
  256. // 衝突している
  257. p = pos;
  258. if (vlen > 0.0f)
  259. dir = v.normalized;
  260. }
  261. else
  262. {
  263. dir = v.normalized;
  264. p = d + dir * cr;
  265. }
  266. return true;
  267. }
  268. }
  269. }