ClampRotationConstraint.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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. /// 回転クランプ拘束[Algorithm 1]
  12. /// </summary>
  13. public class ClampRotationConstraint : PhysicsManagerConstraint
  14. {
  15. /// <summary>
  16. /// 拘束データ
  17. /// </summary>
  18. [System.Serializable]
  19. public struct ClampRotationData
  20. {
  21. /// <summary>
  22. /// 計算頂点インデックス
  23. /// </summary>
  24. public int vertexIndex;
  25. /// <summary>
  26. /// 親頂点インデックス
  27. /// </summary>
  28. public int parentVertexIndex;
  29. /// <summary>
  30. /// 親から自身への本来のローカル方向(単位ベクトル)(v1.7.0)
  31. /// </summary>
  32. public float3 localPos;
  33. /// <summary>
  34. /// 親から自身への本来のローカル回転(v1.7.0)
  35. /// </summary>
  36. public quaternion localRot;
  37. /// <summary>
  38. /// データが有効か判定する
  39. /// </summary>
  40. /// <returns></returns>
  41. public bool IsValid()
  42. {
  43. return vertexIndex > 0 || parentVertexIndex > 0;
  44. }
  45. }
  46. //=========================================================================================
  47. // Algorithm 1
  48. //=========================================================================================
  49. FixedChunkNativeArray<ClampRotationData> dataList;
  50. [System.Serializable]
  51. public struct ClampRotationRootInfo
  52. {
  53. public ushort startIndex;
  54. public ushort dataLength;
  55. }
  56. FixedChunkNativeArray<ClampRotationRootInfo> rootInfoList;
  57. /// <summary>
  58. /// グループごとの拘束データ
  59. /// </summary>
  60. public struct GroupData
  61. {
  62. public int teamId;
  63. public int active;
  64. /// <summary>
  65. /// 最大角度
  66. /// </summary>
  67. public CurveParam maxAngle;
  68. /// <summary>
  69. /// 速度影響
  70. /// </summary>
  71. public float velocityInfluence;
  72. public ChunkData dataChunk;
  73. public ChunkData rootInfoChunk;
  74. }
  75. public FixedNativeList<GroupData> groupList;
  76. /// <summary>
  77. /// ルートごとのチームインデックス
  78. /// </summary>
  79. FixedChunkNativeArray<int> rootTeamList;
  80. /// <summary>
  81. /// 拘束データごとの作業バッファ
  82. /// </summary>
  83. FixedChunkNativeArray<float> lengthBuffer;
  84. //=========================================================================================
  85. public override void Create()
  86. {
  87. dataList = new FixedChunkNativeArray<ClampRotationData>();
  88. rootInfoList = new FixedChunkNativeArray<ClampRotationRootInfo>();
  89. groupList = new FixedNativeList<GroupData>();
  90. rootTeamList = new FixedChunkNativeArray<int>();
  91. lengthBuffer = new FixedChunkNativeArray<float>();
  92. }
  93. public override void Release()
  94. {
  95. dataList.Dispose();
  96. rootInfoList.Dispose();
  97. groupList.Dispose();
  98. rootTeamList.Dispose();
  99. lengthBuffer.Dispose();
  100. }
  101. //=========================================================================================
  102. public int AddGroup(
  103. int teamId,
  104. bool active,
  105. BezierParam maxAngle,
  106. float velocityInfluence,
  107. ClampRotationData[] dataArray,
  108. ClampRotationRootInfo[] rootInfoArray
  109. )
  110. {
  111. if (dataArray == null || dataArray.Length == 0 || rootInfoArray == null || rootInfoArray.Length == 0)
  112. return -1;
  113. //var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
  114. var gdata = new GroupData();
  115. gdata.teamId = teamId;
  116. gdata.active = active ? 1 : 0;
  117. gdata.maxAngle.Setup(maxAngle);
  118. gdata.velocityInfluence = velocityInfluence;
  119. gdata.dataChunk = dataList.AddChunk(dataArray.Length);
  120. gdata.rootInfoChunk = rootInfoList.AddChunk(rootInfoArray.Length);
  121. // チャンクデータコピー
  122. dataList.ToJobArray().CopyFromFast(gdata.dataChunk.startIndex, dataArray);
  123. rootInfoList.ToJobArray().CopyFromFast(gdata.rootInfoChunk.startIndex, rootInfoArray);
  124. int group = groupList.Add(gdata);
  125. // ルートごとのチームインデックス
  126. var c = rootTeamList.AddChunk(rootInfoArray.Length);
  127. rootTeamList.Fill(c, teamId);
  128. // 作業バッファ
  129. lengthBuffer.AddChunk(dataArray.Length);
  130. return group;
  131. }
  132. public override void RemoveTeam(int teamId)
  133. {
  134. var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
  135. // Algorithm 1
  136. int group1 = teamData.clampRotationGroupIndex;
  137. if (group1 >= 0)
  138. {
  139. var cdata = groupList[group1];
  140. // チャンクデータ削除
  141. dataList.RemoveChunk(cdata.dataChunk);
  142. rootInfoList.RemoveChunk(cdata.rootInfoChunk);
  143. rootTeamList.RemoveChunk(cdata.rootInfoChunk);
  144. lengthBuffer.RemoveChunk(cdata.dataChunk);
  145. // データ削除
  146. groupList.Remove(group1);
  147. }
  148. }
  149. public void ChangeParam(int teamId, bool active, BezierParam maxAngle, float velocityInfluence)
  150. {
  151. var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
  152. int group = teamData.clampRotationGroupIndex;
  153. if (group < 0)
  154. return;
  155. var gdata = groupList[group];
  156. gdata.active = active ? 1 : 0;
  157. gdata.maxAngle.Setup(maxAngle);
  158. gdata.velocityInfluence = velocityInfluence;
  159. groupList[group] = gdata;
  160. }
  161. //=========================================================================================
  162. /// <summary>
  163. /// 拘束の解決
  164. /// </summary>
  165. /// <param name="dtime"></param>
  166. /// <param name="jobHandle"></param>
  167. /// <returns></returns>
  168. public override JobHandle SolverConstraint(int runCount, float dtime, float updatePower, int iteration, JobHandle jobHandle)
  169. {
  170. //=======================================================
  171. // Algorithm 1
  172. //=======================================================
  173. if (groupList.Count > 0)
  174. {
  175. // 回転拘束(ルートラインごと)
  176. var job1 = new ClampRotationJob()
  177. {
  178. runCount = runCount,
  179. maxMoveLength = dtime * Define.Compute.ClampRotationMaxVelocity, // 最大1.0m/s
  180. dataList = dataList.ToJobArray(),
  181. rootInfoList = rootInfoList.ToJobArray(),
  182. rootTeamList = rootTeamList.ToJobArray(),
  183. groupList = groupList.ToJobArray(),
  184. teamDataList = Manager.Team.teamDataList.ToJobArray(),
  185. flagList = Manager.Particle.flagList.ToJobArray(),
  186. //basePosList = Manager.Particle.basePosList.ToJobArray(),
  187. //baseRotList = Manager.Particle.baseRotList.ToJobArray(),
  188. depthList = Manager.Particle.depthList.ToJobArray(),
  189. frictionList = Manager.Particle.frictionList.ToJobArray(),
  190. nextPosList = Manager.Particle.InNextPosList.ToJobArray(),
  191. nextRotList = Manager.Particle.InNextRotList.ToJobArray(),
  192. posList = Manager.Particle.posList.ToJobArray(),
  193. lengthBuffer = lengthBuffer.ToJobArray(),
  194. };
  195. jobHandle = job1.Schedule(rootTeamList.Length, 8, jobHandle);
  196. }
  197. return jobHandle;
  198. }
  199. //=========================================================================================
  200. // Algorithm 1
  201. //=========================================================================================
  202. /// <summary>
  203. /// 回転クランプ拘束ジョブ
  204. /// </summary>
  205. [BurstCompile]
  206. struct ClampRotationJob : IJobParallelFor
  207. {
  208. public int runCount;
  209. public float maxMoveLength;
  210. [Unity.Collections.ReadOnly]
  211. public NativeArray<ClampRotationData> dataList;
  212. [Unity.Collections.ReadOnly]
  213. public NativeArray<ClampRotationRootInfo> rootInfoList;
  214. [Unity.Collections.ReadOnly]
  215. public NativeArray<int> rootTeamList;
  216. [Unity.Collections.ReadOnly]
  217. public NativeArray<GroupData> groupList;
  218. // チーム
  219. [Unity.Collections.ReadOnly]
  220. public NativeArray<PhysicsManagerTeamData.TeamData> teamDataList;
  221. [Unity.Collections.ReadOnly]
  222. public NativeArray<float> depthList;
  223. [Unity.Collections.ReadOnly]
  224. public NativeArray<PhysicsManagerParticleData.ParticleFlag> flagList;
  225. //[Unity.Collections.ReadOnly]
  226. //public NativeArray<float3> basePosList;
  227. //[Unity.Collections.ReadOnly]
  228. //public NativeArray<quaternion> baseRotList;
  229. [Unity.Collections.ReadOnly]
  230. public NativeArray<float> frictionList;
  231. [NativeDisableParallelForRestriction]
  232. public NativeArray<float3> nextPosList;
  233. [NativeDisableParallelForRestriction]
  234. public NativeArray<quaternion> nextRotList;
  235. [NativeDisableParallelForRestriction]
  236. public NativeArray<float3> posList;
  237. [NativeDisableParallelForRestriction]
  238. public NativeArray<float> lengthBuffer;
  239. // ルートラインごと
  240. public void Execute(int rootIndex)
  241. {
  242. // チーム
  243. int teamIndex = rootTeamList[rootIndex];
  244. if (teamIndex == 0)
  245. return;
  246. var team = teamDataList[teamIndex];
  247. if (team.IsActive() == false || team.clampRotationGroupIndex < 0)
  248. return;
  249. // 更新確認
  250. if (team.IsUpdate(runCount) == false)
  251. return;
  252. // グループデータ
  253. var gdata = groupList[team.clampRotationGroupIndex];
  254. if (gdata.active == 0)
  255. return;
  256. // データ
  257. var rootInfo = rootInfoList[rootIndex];
  258. int dataIndex = rootInfo.startIndex + gdata.dataChunk.startIndex;
  259. int dataCount = rootInfo.dataLength;
  260. int pstart = team.particleChunk.startIndex;
  261. // (1)現在の親からのベクトル長を保持する
  262. for (int i = 0; i < dataCount; i++)
  263. {
  264. var data = dataList[dataIndex + i];
  265. int pindex = data.parentVertexIndex;
  266. if (pindex < 0)
  267. continue;
  268. var index = data.vertexIndex;
  269. index += pstart;
  270. pindex += pstart;
  271. var npos = nextPosList[index];
  272. var ppos = nextPosList[pindex];
  273. // 現在ベクトル長
  274. float vlen = math.distance(npos, ppos);
  275. lengthBuffer[dataIndex + i] = vlen;
  276. }
  277. // (2)回転角度制限
  278. for (int i = 0; i < dataCount; i++)
  279. {
  280. var data = dataList[dataIndex + i];
  281. int pindex = data.parentVertexIndex;
  282. if (pindex < 0)
  283. continue;
  284. var index = data.vertexIndex;
  285. index += pstart;
  286. pindex += pstart;
  287. var flag = flagList[index];
  288. if (flag.IsValid() == false)
  289. continue;
  290. var npos = nextPosList[index];
  291. var nrot = nextRotList[index];
  292. var opos = npos;
  293. var ppos = nextPosList[pindex];
  294. var prot = nextRotList[pindex];
  295. float depth = depthList[index];
  296. //float stiffness = gdata.stiffness.Evaluate(depth);
  297. // 本来のローカルpos/rotを算出する
  298. //var bpos = basePosList[index];
  299. //var brot = baseRotList[index];
  300. //var pbpos = basePosList[pindex];
  301. //var pbrot = baseRotList[pindex];
  302. //float3 bv = math.normalize(bpos - pbpos);
  303. //var ipbrot = math.inverse(pbrot);
  304. //float3 localPos = math.mul(ipbrot, bv);
  305. //quaternion localRot = math.mul(ipbrot, brot);
  306. // 本来の方向ベクトル
  307. //float3 tv = math.mul(prot, localPos);
  308. //float3 tv = math.mul(prot, data.localPos); // v1.7.0
  309. float3 tv = math.mul(prot, data.localPos * team.scaleDirection); // マイナススケール対応(v1.7.6)
  310. // ベクトル長
  311. float vlen = math.distance(npos, ppos); // 最新の距離(※これは伸びる場合があるが、一番安定している)
  312. float blen = lengthBuffer[dataIndex + i]; // 計算前の距離
  313. vlen = math.clamp(vlen, 0.0f, blen * 1.2f);
  314. // 現在ベクトル
  315. float3 v = math.normalize(npos - ppos);
  316. // ベクトル角度クランプ
  317. float maxAngle = gdata.maxAngle.Evaluate(depth);
  318. maxAngle = math.radians(maxAngle);
  319. float angle = math.acos(math.dot(v, tv));
  320. if (flag.IsFixed() == false)
  321. {
  322. if (angle > maxAngle)
  323. {
  324. MathUtility.ClampAngle(v, tv, maxAngle, out v);
  325. }
  326. var mv = (ppos + v * vlen) - npos;
  327. // 最大速度クランプ
  328. mv = MathUtility.ClampVector(mv, 0.0f, maxMoveLength);
  329. var fpos = npos + mv;
  330. // 摩擦係数から移動率を算出
  331. float friction = frictionList[index];
  332. float moveratio = math.saturate(1.0f - friction * Define.Compute.FrictionMoveRatio);
  333. // 摩擦係数による移動制限(衝突しているパーティクルは動きづらい)
  334. npos = math.lerp(npos, fpos, moveratio);
  335. nextPosList[index] = npos;
  336. // 現在ベクトル更新(v1.8.0)
  337. v = math.normalize(npos - ppos);
  338. // 速度影響
  339. var av = (npos - opos) * (1.0f - gdata.velocityInfluence);
  340. posList[index] = posList[index] + av;
  341. }
  342. // 回転補正
  343. nrot = math.mul(prot, new quaternion(data.localRot.value * team.quaternionScale)); // マイナススケール対応(v1.7.6)
  344. var q = MathUtility.FromToRotation(tv, v);
  345. nrot = math.mul(q, nrot);
  346. nextRotList[index] = nrot;
  347. }
  348. }
  349. }
  350. }
  351. }