ClampDistanceConstraint.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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 ClampDistanceConstraint : PhysicsManagerConstraint
  14. {
  15. /// <summary>
  16. /// 最大最小距離拘束データ
  17. /// todo:共有化可能
  18. /// </summary>
  19. [System.Serializable]
  20. public struct ClampDistanceData
  21. {
  22. /// <summary>
  23. /// 計算頂点インデックス
  24. /// </summary>
  25. public ushort vertexIndex;
  26. /// <summary>
  27. /// ターゲット頂点インデックス
  28. /// </summary>
  29. public ushort targetVertexIndex;
  30. /// <summary>
  31. /// パーティクル距離(v1.7.0)
  32. /// </summary>
  33. public float length;
  34. /// <summary>
  35. /// データが有効か判定する
  36. /// </summary>
  37. /// <returns></returns>
  38. public bool IsValid()
  39. {
  40. return vertexIndex > 0 || targetVertexIndex > 0;
  41. }
  42. }
  43. FixedChunkNativeArray<ClampDistanceData> dataList;
  44. /// <summary>
  45. /// 頂点インデックスごとの書き込みバッファ参照
  46. /// </summary>
  47. FixedChunkNativeArray<ReferenceDataIndex> refDataList;
  48. /// <summary>
  49. /// グループごとの拘束データ
  50. /// </summary>
  51. public struct GroupData
  52. {
  53. public int teamId;
  54. public int active;
  55. /// <summary>
  56. /// 最小距離割合
  57. /// </summary>
  58. public float minRatio;
  59. /// <summary>
  60. /// 最大距離割合
  61. /// </summary>
  62. public float maxRatio;
  63. /// <summary>
  64. /// 速度影響
  65. /// </summary>
  66. public float velocityInfluence;
  67. public ChunkData dataChunk;
  68. public ChunkData refChunk;
  69. }
  70. public FixedNativeList<GroupData> groupList;
  71. //=========================================================================================
  72. public override void Create()
  73. {
  74. dataList = new FixedChunkNativeArray<ClampDistanceData>();
  75. refDataList = new FixedChunkNativeArray<ReferenceDataIndex>();
  76. groupList = new FixedNativeList<GroupData>();
  77. }
  78. public override void Release()
  79. {
  80. dataList.Dispose();
  81. refDataList.Dispose();
  82. groupList.Dispose();
  83. }
  84. //=========================================================================================
  85. public int AddGroup(int teamId, bool active, float minRatio, float maxRatio, float velocityInfluence, ClampDistanceData[] dataArray, ReferenceDataIndex[] refDataArray)
  86. {
  87. if (dataArray == null || dataArray.Length == 0 || refDataArray == null || refDataArray.Length == 0)
  88. return -1;
  89. var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
  90. var gdata = new GroupData();
  91. gdata.teamId = teamId;
  92. gdata.active = active ? 1 : 0;
  93. gdata.minRatio = minRatio;
  94. gdata.maxRatio = maxRatio;
  95. gdata.velocityInfluence = velocityInfluence;
  96. gdata.dataChunk = dataList.AddChunk(dataArray.Length);
  97. gdata.refChunk = refDataList.AddChunk(refDataArray.Length);
  98. // チャンクデータコピー
  99. dataList.ToJobArray().CopyFromFast(gdata.dataChunk.startIndex, dataArray);
  100. refDataList.ToJobArray().CopyFromFast(gdata.refChunk.startIndex, refDataArray);
  101. int group = groupList.Add(gdata);
  102. return group;
  103. }
  104. public override void RemoveTeam(int teamId)
  105. {
  106. var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
  107. int group = teamData.clampDistanceGroupIndex;
  108. if (group < 0)
  109. return;
  110. var cdata = groupList[group];
  111. // チャンクデータ削除
  112. dataList.RemoveChunk(cdata.dataChunk);
  113. refDataList.RemoveChunk(cdata.refChunk);
  114. // データ削除
  115. groupList.Remove(group);
  116. }
  117. public void ChangeParam(int teamId, bool active, float minRatio, float maxRatio, float velocityInfluence)
  118. {
  119. var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
  120. int group = teamData.clampDistanceGroupIndex;
  121. if (group < 0)
  122. return;
  123. var gdata = groupList[group];
  124. gdata.active = active ? 1 : 0;
  125. gdata.minRatio = minRatio;
  126. gdata.maxRatio = maxRatio;
  127. gdata.velocityInfluence = velocityInfluence;
  128. groupList[group] = gdata;
  129. }
  130. //=========================================================================================
  131. /// <summary>
  132. /// 拘束の解決
  133. /// </summary>
  134. /// <param name="dtime"></param>
  135. /// <param name="jobHandle"></param>
  136. /// <returns></returns>
  137. public override JobHandle SolverConstraint(int runCount, float dtime, float updatePower, int iteration, JobHandle jobHandle)
  138. {
  139. if (groupList.Count == 0)
  140. return jobHandle;
  141. // 最大最小距離拘束(パーティクルごとに実行する)
  142. var job1 = new ClampDistanceJob()
  143. {
  144. runCount = runCount,
  145. clampDistanceList = dataList.ToJobArray(),
  146. groupList = groupList.ToJobArray(),
  147. refDataList = refDataList.ToJobArray(),
  148. teamDataList = Manager.Team.teamDataList.ToJobArray(),
  149. teamIdList = Manager.Particle.teamIdList.ToJobArray(),
  150. flagList = Manager.Particle.flagList.ToJobArray(),
  151. nextPosList = Manager.Particle.InNextPosList.ToJobArray(),
  152. basePosList = Manager.Particle.basePosList.ToJobArray(),
  153. posList = Manager.Particle.posList.ToJobArray(),
  154. frictionList = Manager.Particle.frictionList.ToJobArray(),
  155. };
  156. jobHandle = job1.Schedule(Manager.Particle.Length, 64, jobHandle);
  157. return jobHandle;
  158. }
  159. /// <summary>
  160. /// 最大最小距離拘束ジョブ
  161. /// パーティクルごとに計算
  162. /// </summary>
  163. [BurstCompile]
  164. struct ClampDistanceJob : IJobParallelFor
  165. {
  166. public int runCount;
  167. [Unity.Collections.ReadOnly]
  168. public NativeArray<ClampDistanceData> clampDistanceList;
  169. [Unity.Collections.ReadOnly]
  170. public NativeArray<GroupData> groupList;
  171. [Unity.Collections.ReadOnly]
  172. public NativeArray<ReferenceDataIndex> refDataList;
  173. // チーム
  174. [Unity.Collections.ReadOnly]
  175. public NativeArray<PhysicsManagerTeamData.TeamData> teamDataList;
  176. [Unity.Collections.ReadOnly]
  177. public NativeArray<int> teamIdList;
  178. [Unity.Collections.ReadOnly]
  179. public NativeArray<PhysicsManagerParticleData.ParticleFlag> flagList;
  180. [NativeDisableParallelForRestriction]
  181. public NativeArray<float3> nextPosList;
  182. [Unity.Collections.ReadOnly]
  183. public NativeArray<float3> basePosList;
  184. public NativeArray<float3> posList;
  185. [Unity.Collections.ReadOnly]
  186. public NativeArray<float> frictionList;
  187. // パーティクルごと
  188. public void Execute(int index)
  189. {
  190. // 頂点フラグ
  191. var flag = flagList[index];
  192. if (flag.IsValid() == false || flag.IsFixed())
  193. return;
  194. // チーム
  195. var team = teamDataList[teamIdList[index]];
  196. if (team.IsActive() == false || team.clampDistanceGroupIndex < 0)
  197. return;
  198. // 更新確認
  199. if (team.IsUpdate(runCount) == false)
  200. return;
  201. int pstart = team.particleChunk.startIndex;
  202. int vindex = index - pstart;
  203. // クロスごとの拘束データ
  204. var gdata = groupList[team.clampDistanceGroupIndex];
  205. if (gdata.active == 0)
  206. return;
  207. // アニメーションされた姿勢の使用
  208. bool useAnimatedPose = team.IsFlag(PhysicsManagerTeamData.Flag_AnimatedPose);
  209. var nextpos = nextPosList[index];
  210. var basepos = basePosList[index];
  211. // 参照データ情報
  212. var refdata = refDataList[gdata.refChunk.startIndex + vindex];
  213. if (refdata.count > 0)
  214. {
  215. int dataIndex = gdata.dataChunk.startIndex + refdata.startIndex;
  216. ClampDistanceData data = clampDistanceList[dataIndex];
  217. if (data.IsValid() == false)
  218. return;
  219. // ターゲット
  220. int pindex2 = pstart + data.targetVertexIndex;
  221. float3 nextpos2 = nextPosList[pindex2];
  222. // 現在のベクトル
  223. float3 v = nextpos - nextpos2;
  224. // 復元長さ
  225. float length = data.length; // v1.7.0
  226. length *= team.scaleRatio; // チームスケール倍率
  227. if (useAnimatedPose)
  228. {
  229. // アニメーションされた距離を使用
  230. //length = math.distance(basepos, basePosList[pindex2]); // 現在のオリジナル距離
  231. //length = math.max(math.distance(basepos, basePosList[pindex2]), length); // 長い方を採用する
  232. length = (math.distance(basepos, basePosList[pindex2]) + length) * 0.5f; // 平均
  233. }
  234. // ベクトル長クランプ
  235. v = MathUtility.ClampVector(v, length * gdata.minRatio, length * gdata.maxRatio);
  236. // 位置
  237. var opos = nextpos;
  238. nextpos = nextpos2 + v;
  239. // 摩擦係数から移動率を算出
  240. float friction = frictionList[index];
  241. float moveratio = math.saturate(1.0f - friction * Define.Compute.FrictionMoveRatio);
  242. nextpos = math.lerp(opos, nextpos, moveratio);
  243. // 書き出し
  244. nextPosList[index] = nextpos;
  245. // 速度影響
  246. var av = (nextpos - opos) * (1.0f - gdata.velocityInfluence);
  247. posList[index] = posList[index] + av;
  248. }
  249. }
  250. }
  251. }
  252. }