ColliderCollisionConstraint.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. // Magica Cloth.
  2. // Copyright (c) MagicaSoft, 2020-2022.
  3. // https://magicasoft.jp
  4. using Unity.Burst;
  5. using Unity.Collections;
  6. using Unity.Jobs;
  7. using Unity.Mathematics;
  8. namespace MagicaCloth
  9. {
  10. /// <summary>
  11. /// コライダーコリジョン拘束
  12. /// </summary>
  13. public class ColliderCollisionConstraint : PhysicsManagerConstraint
  14. {
  15. public override void Create()
  16. {
  17. }
  18. public override void RemoveTeam(int teamId)
  19. {
  20. }
  21. public void ChangeParam(int teamId, bool useCollision)
  22. {
  23. Manager.Team.SetFlag(teamId, PhysicsManagerTeamData.Flag_Collision, useCollision);
  24. }
  25. public override void Release()
  26. {
  27. }
  28. //=========================================================================================
  29. public override JobHandle SolverConstraint(int runCount, float dtime, float updatePower, int iteration, JobHandle jobHandle)
  30. {
  31. if (Manager.Particle.ColliderCount <= 0)
  32. return jobHandle;
  33. // コリジョン拘束
  34. var job1 = new CollisionJob()
  35. {
  36. runCount = runCount,
  37. flagList = Manager.Particle.flagList.ToJobArray(),
  38. teamIdList = Manager.Particle.teamIdList.ToJobArray(),
  39. radiusList = Manager.Particle.radiusList.ToJobArray(),
  40. nextPosList = Manager.Particle.InNextPosList.ToJobArray(),
  41. nextRotList = Manager.Particle.InNextRotList.ToJobArray(),
  42. posList = Manager.Particle.posList.ToJobArray(),
  43. rotList = Manager.Particle.rotList.ToJobArray(),
  44. localPosList = Manager.Particle.localPosList.ToJobArray(),
  45. basePosList = Manager.Particle.basePosList.ToJobArray(),
  46. baseRotList = Manager.Particle.baseRotList.ToJobArray(),
  47. transformIndexList = Manager.Particle.transformIndexList.ToJobArray(),
  48. colliderList = Manager.Team.colliderList.ToJobArray(),
  49. boneSclList = Manager.Bone.boneSclList.ToJobArray(),
  50. teamDataList = Manager.Team.teamDataList.ToJobArray(),
  51. frictionList = Manager.Particle.frictionList.ToJobArray(),
  52. collisionLinkIdList = Manager.Particle.collisionLinkIdList.ToJobArray(),
  53. collisionNormalList = Manager.Particle.collisionNormalList.ToJobArray(),
  54. };
  55. jobHandle = job1.Schedule(Manager.Particle.Length, 64, jobHandle);
  56. return jobHandle;
  57. }
  58. //=========================================================================================
  59. /// <summary>
  60. /// コリジョン拘束ジョブ
  61. /// 移動パーティクルごとに計算
  62. /// </summary>
  63. [BurstCompile]
  64. struct CollisionJob : IJobParallelFor
  65. {
  66. public int runCount;
  67. [Unity.Collections.ReadOnly]
  68. public NativeArray<PhysicsManagerParticleData.ParticleFlag> flagList;
  69. [Unity.Collections.ReadOnly]
  70. public NativeArray<int> teamIdList;
  71. [Unity.Collections.ReadOnly]
  72. public NativeArray<float3> radiusList;
  73. [NativeDisableParallelForRestriction]
  74. public NativeArray<float3> nextPosList;
  75. [Unity.Collections.ReadOnly]
  76. public NativeArray<quaternion> nextRotList;
  77. [Unity.Collections.ReadOnly]
  78. public NativeArray<float3> posList;
  79. [Unity.Collections.ReadOnly]
  80. public NativeArray<quaternion> rotList;
  81. [Unity.Collections.ReadOnly]
  82. public NativeArray<float3> localPosList;
  83. [Unity.Collections.ReadOnly]
  84. public NativeArray<float3> basePosList;
  85. [Unity.Collections.ReadOnly]
  86. public NativeArray<quaternion> baseRotList;
  87. [Unity.Collections.ReadOnly]
  88. public NativeArray<int> transformIndexList;
  89. [Unity.Collections.ReadOnly]
  90. public NativeArray<int> colliderList;
  91. [Unity.Collections.ReadOnly]
  92. public NativeArray<float3> boneSclList;
  93. [Unity.Collections.ReadOnly]
  94. public NativeArray<PhysicsManagerTeamData.TeamData> teamDataList;
  95. public NativeArray<float> frictionList;
  96. [Unity.Collections.WriteOnly]
  97. public NativeArray<int> collisionLinkIdList;
  98. [Unity.Collections.WriteOnly]
  99. public NativeArray<float3> collisionNormalList;
  100. // パーティクルごと
  101. public void Execute(int index)
  102. {
  103. var flag = flagList[index];
  104. if (flag.IsValid() == false || flag.IsFixed() || flag.IsCollider())
  105. return;
  106. // チーム
  107. var team = teamIdList[index];
  108. var teamData = teamDataList[team];
  109. if (teamData.IsActive() == false)
  110. return;
  111. if (teamData.IsFlag(PhysicsManagerTeamData.Flag_Collision) == false)
  112. return;
  113. // 更新確認
  114. if (teamData.IsUpdate(runCount) == false)
  115. return;
  116. float3 nextpos = nextPosList[index];
  117. var radius = radiusList[index].x;
  118. //var basepos = basePosList[index];
  119. // チームスケール倍率
  120. radius *= teamData.scaleRatio;
  121. // チームごとに判定[グローバル(0)]->[自身のチーム(team)]
  122. int colliderTeam = 0;
  123. // コライダーとの距離
  124. float mindist = 100.0f;
  125. // 接触コライダー情報
  126. int collisionColliderId = 0;
  127. float3 collisionNormal = 0;
  128. float3 n = 0;
  129. for (int i = 0; i < 2; i++)
  130. {
  131. // チーム内のコライダーをループ
  132. var c = teamDataList[colliderTeam].colliderChunk;
  133. int dataIndex = c.startIndex;
  134. for (int j = 0; j < c.useLength; j++, dataIndex++)
  135. {
  136. int cindex = colliderList[dataIndex];
  137. var cflag = flagList[cindex];
  138. if (cflag.IsValid() == false)
  139. continue;
  140. float dist = 100.0f;
  141. if (cflag.IsFlag(PhysicsManagerParticleData.Flag_Plane))
  142. {
  143. // 平面コライダー判定
  144. dist = PlaneColliderDetection(ref nextpos, radius, cindex, out n);
  145. }
  146. else if (cflag.IsFlag(PhysicsManagerParticleData.Flag_CapsuleX))
  147. {
  148. // カプセルコライダー判定
  149. dist = CapsuleColliderDetection(ref nextpos, radius, cindex, new float3(1, 0, 0), out n);
  150. }
  151. else if (cflag.IsFlag(PhysicsManagerParticleData.Flag_CapsuleY))
  152. {
  153. // カプセルコライダー判定
  154. dist = CapsuleColliderDetection(ref nextpos, radius, cindex, new float3(0, 1, 0), out n);
  155. }
  156. else if (cflag.IsFlag(PhysicsManagerParticleData.Flag_CapsuleZ))
  157. {
  158. // カプセルコライダー判定
  159. dist = CapsuleColliderDetection(ref nextpos, radius, cindex, new float3(0, 0, 1), out n);
  160. }
  161. else if (cflag.IsFlag(PhysicsManagerParticleData.Flag_Box))
  162. {
  163. // ボックスコライダー判定
  164. // ★まだ未実装
  165. }
  166. else
  167. {
  168. // 球コライダー判定
  169. dist = SphereColliderDetection(ref nextpos, radius, cindex, out n);
  170. }
  171. // 押し出し(接触)あり
  172. if (dist < mindist && dist <= Define.Compute.CollisionFrictionRange)
  173. {
  174. collisionColliderId = cindex;
  175. collisionNormal = n;
  176. mindist = dist;
  177. }
  178. }
  179. // 自身のチームに切り替え
  180. if (team > 0)
  181. colliderTeam = team;
  182. else
  183. break;
  184. }
  185. // 摩擦係数(friction)計算
  186. if (collisionColliderId > 0)
  187. {
  188. // コライダーから一定距離内にいる
  189. // 摩擦係数計算(コライダーからの距離により変化.0.0~接地面1.0~深くめり込む場合は1.0を超える)
  190. //var friction = math.max(1.0f - mindist / Define.Compute.CollisionFrictionRange, 0.0f); // ★この実装では振動が酷くなるので却下!
  191. // コライダーからの距離により変化(0.0~接地面1.0)
  192. var friction = 1.0f - math.saturate(mindist / Define.Compute.CollisionFrictionRange);
  193. frictionList[index] = math.max(friction, frictionList[index]); // 大きい方
  194. }
  195. collisionLinkIdList[index] = collisionColliderId;
  196. collisionNormalList[index] = collisionNormal;
  197. // 書き戻し
  198. nextPosList[index] = nextpos;
  199. // コリジョンの速度影響は100%にしておく
  200. // コリジョン衝突による速度影響は非常に重要!
  201. // 速度影響を抑えると容易に突き抜けるようになってしまう
  202. }
  203. //=====================================================================================
  204. /// <summary>
  205. /// 球衝突判定
  206. /// </summary>
  207. /// <param name="nextpos"></param>
  208. /// <param name="pos"></param>
  209. /// <param name="radius"></param>
  210. /// <param name="cindex"></param>
  211. /// <param name="friction"></param>
  212. /// <returns></returns>
  213. float SphereColliderDetection(ref float3 nextpos, float radius, int cindex, out float3 normal)
  214. {
  215. var cpos = nextPosList[cindex];
  216. var cradius = radiusList[cindex];
  217. // スケール
  218. var tindex = transformIndexList[cindex];
  219. var cscl = boneSclList[tindex];
  220. cradius *= math.abs(cscl.x); // X軸のみを見る
  221. // 移動前のコライダーに対するローカル位置から移動後コライダーの押し出し平面を求める
  222. float3 c = 0, n = 0, v = 0;
  223. var coldpos = posList[cindex];
  224. v = nextpos - coldpos;
  225. n = math.normalize(v);
  226. c = cpos + n * (cradius.x + radius);
  227. // 衝突法線
  228. normal = n;
  229. // c = 平面位置
  230. // n = 平面方向
  231. // 平面衝突判定と押し出し
  232. return MathUtility.IntersectPointPlaneDist(c, n, nextpos, out nextpos);
  233. }
  234. /// <summary>
  235. /// カプセル衝突判定
  236. /// </summary>
  237. /// <param name="nextpos"></param>
  238. /// <param name="pos"></param>
  239. /// <param name="radius"></param>
  240. /// <param name="cindex"></param>
  241. /// <param name="dir"></param>
  242. /// <param name="friction"></param>
  243. /// <returns></returns>
  244. float CapsuleColliderDetection(ref float3 nextpos, float radius, int cindex, float3 dir, out float3 normal)
  245. {
  246. var cpos = nextPosList[cindex];
  247. var crot = nextRotList[cindex];
  248. // x = 長さ(片側)
  249. // y = 始点半径
  250. // z = 終点半径
  251. var cradius = radiusList[cindex];
  252. // スケール
  253. var tindex = transformIndexList[cindex];
  254. var cscl = boneSclList[tindex];
  255. float scl = math.dot(math.abs(cscl), dir); // dirの軸のスケールを使用する
  256. cradius *= scl;
  257. float3 c = 0, n = 0;
  258. var coldpos = posList[cindex];
  259. var coldrot = rotList[cindex];
  260. // カプセル始点と終点
  261. float3 l = math.mul(coldrot, dir * cradius.x);
  262. float3 spos = coldpos - l;
  263. float3 epos = coldpos + l;
  264. float sr = cradius.y;
  265. float er = cradius.z;
  266. // 移動前のコライダー位置から押し出し平面を割り出す
  267. float t = MathUtility.ClosestPtPointSegmentRatio(nextpos, spos, epos);
  268. float r = math.lerp(sr, er, t);
  269. float3 d = math.lerp(spos, epos, t);
  270. float3 v = nextpos - d;
  271. // 移動前コライダーのローカルベクトル
  272. var iq = math.inverse(coldrot);
  273. float3 lv = math.mul(iq, v);
  274. // 移動後コライダーに変換
  275. l = math.mul(crot, dir * cradius.x);
  276. spos = cpos - l;
  277. epos = cpos + l;
  278. d = math.lerp(spos, epos, t);
  279. v = math.mul(crot, lv);
  280. n = math.normalize(v);
  281. c = d + n * (r + radius);
  282. // 衝突法線
  283. normal = n;
  284. // c = 平面位置
  285. // n = 平面方向
  286. // 平面衝突判定と押し出し
  287. return MathUtility.IntersectPointPlaneDist(c, n, nextpos, out nextpos);
  288. }
  289. /// <summary>
  290. /// 平面衝突判定
  291. /// </summary>
  292. /// <param name="nextpos"></param>
  293. /// <param name="radius"></param>
  294. /// <param name="cindex"></param>
  295. float PlaneColliderDetection(ref float3 nextpos, float radius, int cindex, out float3 normal)
  296. {
  297. // 平面姿勢
  298. var cpos = nextPosList[cindex];
  299. var crot = nextRotList[cindex];
  300. // 平面法線
  301. float3 n = math.mul(crot, math.up());
  302. // パーティクル半径分オフセット
  303. cpos += n * radius;
  304. // 衝突法線
  305. normal = n;
  306. // c = 平面位置
  307. // n = 平面方向
  308. // 平面衝突判定と押し出し
  309. // 平面との距離を返す(押し出しの場合は0.0)
  310. return MathUtility.IntersectPointPlaneDist(cpos, n, nextpos, out nextpos);
  311. }
  312. }
  313. }
  314. }