VolumeConstraint.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. // Magica Cloth.
  2. // Copyright (c) MagicaSoft, 2020-2022.
  3. // https://magicasoft.jp
  4. // どうも入れないほうが良さげ
  5. //#define normalizeStretch
  6. //#define normalizeShear // どうも安定しない
  7. using Unity.Burst;
  8. using Unity.Collections;
  9. using Unity.Jobs;
  10. using Unity.Mathematics;
  11. namespace MagicaCloth
  12. {
  13. /// <summary>
  14. /// ボリューム拘束
  15. /// </summary>
  16. public class VolumeConstraint : PhysicsManagerConstraint
  17. {
  18. /// <summary>
  19. /// 拘束データ
  20. /// todo:共有化可能
  21. /// </summary>
  22. [System.Serializable]
  23. public struct VolumeData
  24. {
  25. /// <summary>
  26. /// ボリューム形成パーティクルインデックスx4
  27. /// </summary>
  28. public int vindex0;
  29. public int vindex1;
  30. public int vindex2;
  31. public int vindex3;
  32. /// <summary>
  33. /// ボリューム行列
  34. /// </summary>
  35. public float3x3 ivMat;
  36. /// <summary>
  37. /// ベンド影響を取得するデプス値(0.0-1.0)
  38. /// </summary>
  39. public float depth;
  40. /// <summary>
  41. /// 方向性拘束(0-1-2)トライアングルに対しての(3)の方向
  42. /// (0=拘束なし,1=正方向,-1=負方向)
  43. /// </summary>
  44. public int direction;
  45. /// <summary>
  46. /// 書き込みバッファインデックス
  47. /// </summary>
  48. public int writeIndex0;
  49. public int writeIndex1;
  50. public int writeIndex2;
  51. public int writeIndex3;
  52. /// <summary>
  53. /// データが有効か判定する
  54. /// </summary>
  55. /// <returns></returns>
  56. public bool IsValid()
  57. {
  58. return vindex0 > 0 && vindex1 > 0;
  59. }
  60. }
  61. FixedChunkNativeArray<VolumeData> dataList;
  62. /// <summary>
  63. /// データごとのグループインデックス
  64. /// </summary>
  65. FixedChunkNativeArray<short> groupIndexList;
  66. /// <summary>
  67. /// 内部パーティクルインデックスごとの書き込みバッファ参照
  68. /// </summary>
  69. FixedChunkNativeArray<ReferenceDataIndex> refDataList;
  70. /// <summary>
  71. /// 頂点計算結果書き込みバッファ
  72. /// </summary>
  73. FixedChunkNativeArray<float3> writeBuffer;
  74. /// <summary>
  75. /// グループごとの拘束データ
  76. /// </summary>
  77. public struct GroupData
  78. {
  79. public int teamId;
  80. public int active;
  81. /// <summary>
  82. /// 伸縮率(0.0-1.0)
  83. /// </summary>
  84. public CurveParam stretchStiffness;
  85. /// <summary>
  86. /// せん断率(0.0-1.0)
  87. /// </summary>
  88. public CurveParam shearStiffness;
  89. /// <summary>
  90. /// データチャンク
  91. /// </summary>
  92. public ChunkData dataChunk;
  93. /// <summary>
  94. /// グループデータチャンク
  95. /// </summary>
  96. public ChunkData groupIndexChunk;
  97. /// <summary>
  98. /// 内部インデックス用チャンク
  99. /// </summary>
  100. public ChunkData refDataChunk;
  101. /// <summary>
  102. /// 頂点計算結果書き込み用チャンク
  103. /// </summary>
  104. public ChunkData writeDataChunk;
  105. }
  106. FixedNativeList<GroupData> groupList;
  107. //=========================================================================================
  108. public override void Create()
  109. {
  110. dataList = new FixedChunkNativeArray<VolumeData>();
  111. groupIndexList = new FixedChunkNativeArray<short>();
  112. refDataList = new FixedChunkNativeArray<ReferenceDataIndex>();
  113. writeBuffer = new FixedChunkNativeArray<float3>();
  114. groupList = new FixedNativeList<GroupData>();
  115. }
  116. public override void Release()
  117. {
  118. dataList.Dispose();
  119. groupIndexList.Dispose();
  120. refDataList.Dispose();
  121. writeBuffer.Dispose();
  122. groupList.Dispose();
  123. }
  124. //=========================================================================================
  125. public int AddGroup(int teamId, bool active, BezierParam stretchStiffness, BezierParam shearStiffness, VolumeData[] dataArray, ReferenceDataIndex[] refDataArray, int writeBufferCount)
  126. {
  127. if (dataArray == null || dataArray.Length == 0 || refDataArray == null || refDataArray.Length == 0 || writeBufferCount == 0)
  128. return -1;
  129. var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
  130. // グループデータ作成
  131. var gdata = new GroupData();
  132. gdata.teamId = teamId;
  133. gdata.active = active ? 1 : 0;
  134. gdata.stretchStiffness.Setup(stretchStiffness);
  135. gdata.shearStiffness.Setup(shearStiffness);
  136. gdata.dataChunk = dataList.AddChunk(dataArray.Length);
  137. gdata.groupIndexChunk = groupIndexList.AddChunk(dataArray.Length);
  138. gdata.refDataChunk = refDataList.AddChunk(refDataArray.Length);
  139. gdata.writeDataChunk = writeBuffer.AddChunk(writeBufferCount);
  140. // チャンクデータコピー
  141. dataList.ToJobArray().CopyFromFast(gdata.dataChunk.startIndex, dataArray);
  142. refDataList.ToJobArray().CopyFromFast(gdata.refDataChunk.startIndex, refDataArray);
  143. int group = groupList.Add(gdata);
  144. // データごとのグループインデックス
  145. groupIndexList.Fill(gdata.groupIndexChunk, (short)group);
  146. return group;
  147. }
  148. public override void RemoveTeam(int teamId)
  149. {
  150. var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
  151. int group = teamData.volumeGroupIndex;
  152. if (group < 0)
  153. return;
  154. var cdata = groupList[group];
  155. // チャンクデータ削除
  156. dataList.RemoveChunk(cdata.dataChunk);
  157. refDataList.RemoveChunk(cdata.refDataChunk);
  158. writeBuffer.RemoveChunk(cdata.writeDataChunk);
  159. groupIndexList.RemoveChunk(cdata.groupIndexChunk);
  160. // データ削除
  161. groupList.Remove(group);
  162. }
  163. public void ChangeParam(int teamId, bool active, BezierParam stretchStiffness, BezierParam shearStiffness)
  164. {
  165. var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
  166. int group = teamData.volumeGroupIndex;
  167. if (group < 0)
  168. return;
  169. var gdata = groupList[group];
  170. gdata.active = active ? 1 : 0;
  171. gdata.stretchStiffness.Setup(stretchStiffness);
  172. gdata.shearStiffness.Setup(shearStiffness);
  173. groupList[group] = gdata;
  174. }
  175. //public int ActiveCount
  176. //{
  177. // get
  178. // {
  179. // int cnt = 0;
  180. // for (int i = 0; i < groupList.Length; i++)
  181. // if (groupList[i].active == 1)
  182. // cnt++;
  183. // return cnt;
  184. // }
  185. //}
  186. //=========================================================================================
  187. /// <summary>
  188. /// 拘束の更新回数
  189. /// </summary>
  190. /// <returns></returns>
  191. public override int GetIterationCount()
  192. {
  193. return base.GetIterationCount();
  194. }
  195. /// <summary>
  196. /// 拘束の解決
  197. /// </summary>
  198. /// <param name="dtime"></param>
  199. /// <param name="jobHandle"></param>
  200. /// <returns></returns>
  201. public override JobHandle SolverConstraint(int runCount, float dtime, float updatePower, int iteration, JobHandle jobHandle)
  202. {
  203. if (groupList.Count == 0)
  204. return jobHandle;
  205. // ステップ1:ベンドの計算
  206. var job = new VolumeCalcJob()
  207. {
  208. runCount = runCount,
  209. updatePower = updatePower,
  210. groupDataList = groupList.ToJobArray(),
  211. dataList = dataList.ToJobArray(),
  212. groupIndexList = groupIndexList.ToJobArray(),
  213. teamDataList = Manager.Team.teamDataList.ToJobArray(),
  214. //flagList = Manager.Particle.flagList.ToJobArray(),
  215. nextPosList = Manager.Particle.InNextPosList.ToJobArray(),
  216. writeBuffer = writeBuffer.ToJobArray(),
  217. };
  218. jobHandle = job.Schedule(dataList.Length, 64, jobHandle);
  219. // ステップ2:ベンド結果の集計
  220. var job2 = new VolumeSumJob()
  221. {
  222. runCount = runCount,
  223. groupDataList = groupList.ToJobArray(),
  224. refDataList = refDataList.ToJobArray(),
  225. writeBuffer = writeBuffer.ToJobArray(),
  226. teamDataList = Manager.Team.teamDataList.ToJobArray(),
  227. teamIdList = Manager.Particle.teamIdList.ToJobArray(),
  228. flagList = Manager.Particle.flagList.ToJobArray(),
  229. inoutNextPosList = Manager.Particle.InNextPosList.ToJobArray(),
  230. };
  231. jobHandle = job2.Schedule(Manager.Particle.Length, 64, jobHandle);
  232. return jobHandle;
  233. }
  234. [BurstCompile]
  235. struct VolumeCalcJob : IJobParallelFor
  236. {
  237. public float updatePower;
  238. public int runCount;
  239. [Unity.Collections.ReadOnly]
  240. public NativeArray<GroupData> groupDataList;
  241. [Unity.Collections.ReadOnly]
  242. public NativeArray<VolumeData> dataList;
  243. [Unity.Collections.ReadOnly]
  244. public NativeArray<short> groupIndexList;
  245. [Unity.Collections.ReadOnly]
  246. public NativeArray<PhysicsManagerTeamData.TeamData> teamDataList;
  247. //[Unity.Collections.ReadOnly]
  248. //public NativeArray<PhysicsManagerParticleData.ParticleFlag> flagList;
  249. [Unity.Collections.ReadOnly]
  250. public NativeArray<float3> nextPosList;
  251. [Unity.Collections.WriteOnly]
  252. [NativeDisableParallelForRestriction]
  253. public NativeArray<float3> writeBuffer;
  254. // ベンドデータごと
  255. public void Execute(int index)
  256. {
  257. var data = dataList[index];
  258. if (data.IsValid() == false)
  259. return;
  260. int gindex = groupIndexList[index];
  261. var gdata = groupDataList[gindex];
  262. if (gdata.teamId == 0 || gdata.active == 0)
  263. return;
  264. var tdata = teamDataList[gdata.teamId];
  265. if (tdata.IsActive() == false)
  266. return;
  267. // 更新確認
  268. if (tdata.IsUpdate(runCount) == false)
  269. return;
  270. int pstart = tdata.particleChunk.startIndex;
  271. float3 corr0 = 0;
  272. float3 corr1 = 0;
  273. float3 corr2 = 0;
  274. float3 corr3 = 0;
  275. int pindex0 = data.vindex0 + pstart;
  276. int pindex1 = data.vindex1 + pstart;
  277. int pindex2 = data.vindex2 + pstart;
  278. int pindex3 = data.vindex3 + pstart;
  279. float3 nextpos0 = nextPosList[pindex0];
  280. float3 nextpos1 = nextPosList[pindex1];
  281. float3 nextpos2 = nextPosList[pindex2];
  282. float3 nextpos3 = nextPosList[pindex3];
  283. // 復元率
  284. float stretchStiffness = (1.0f - math.pow(1.0f - gdata.stretchStiffness.Evaluate(data.depth), updatePower));
  285. float shearStiffness = (1.0f - math.pow(1.0f - gdata.shearStiffness.Evaluate(data.depth), updatePower));
  286. // 方向性拘束
  287. float3 add3 = 0;
  288. #if false
  289. if (data.direction != 0)
  290. {
  291. var v1 = nextpos1 - nextpos0;
  292. var v2 = nextpos2 - nextpos0;
  293. //var v3 = nextpos3 - nextpos0;
  294. var n = math.normalize(math.cross(v1, v2));
  295. n *= data.direction; // 方向
  296. var n0 = nextpos0 + n * 0.005f; // 厚み
  297. //var n0 = nextpos0 + n * 0.001f; // 厚み
  298. var v3 = nextpos3 - n0;
  299. float d = math.dot(n, v3);
  300. if (d < 0.0f)
  301. {
  302. //float3 add = n * -d;
  303. float3 add = n * (-d * stretchStiffness);
  304. //add3 = add;
  305. //nextpos3 += add3;
  306. //corr3 += add;
  307. add *= 0.5f;
  308. corr0 -= add;
  309. corr1 -= add;
  310. corr2 -= add;
  311. corr3 += add;
  312. }
  313. }
  314. #endif
  315. // ボリューム拘束
  316. float3x3 ivMat = data.ivMat;
  317. //float3[] c = new float3[3];
  318. float3x3 c = 0;
  319. c[0] = ivMat.c0;
  320. c[1] = ivMat.c1;
  321. c[2] = ivMat.c2;
  322. for (int i = 0; i < 3; i++)
  323. {
  324. for (int j = 0; j <= i; j++)
  325. {
  326. float3x3 P;
  327. P.c0 = (nextpos1 + corr1) - (nextpos0 + corr0); // Gauss - Seidel
  328. P.c1 = (nextpos2 + corr2) - (nextpos0 + corr0);
  329. P.c2 = (nextpos3 + corr3) - (nextpos0 + corr0);
  330. float3 fi = math.mul(P, c[i]);
  331. float3 fj = math.mul(P, c[j]);
  332. //float3 fi = math.mul(P, ivMat[i]);
  333. //float3 fj = math.mul(P, ivMat[j]);
  334. float Sij = math.dot(fi, fj);
  335. #if normalizeShear
  336. float wi = 0, wj = 0, s1 = 0, s3 = 0;
  337. //if (normalizeShear && i != j)
  338. if (i != j)
  339. {
  340. wi = math.length(fi);
  341. wj = math.length(fj);
  342. s1 = 1.0f / (wi * wj);
  343. s3 = s1 * s1 * s1;
  344. }
  345. #endif
  346. //float3[] d = new float3[4];
  347. //d[0] = 0;
  348. //for (int k = 0; k < 3; k++)
  349. //{
  350. // d[k + 1] = fj * ivMat[i][k] + fi * ivMat[j][k];
  351. // //if (normalizeShear && i != j)
  352. // if (i != j)
  353. // {
  354. // d[k + 1] = s1 * d[k + 1] - Sij * s3 * (wj * wj * fi * ivMat[i][k] + wi * wi * fj * ivMat[j][k]);
  355. // }
  356. // d[0] -= d[k + 1];
  357. //}
  358. float3x4 d = 0;
  359. d[0] = 0;
  360. for (int k = 0; k < 3; k++)
  361. {
  362. d[k + 1] = fj * ivMat[i][k] + fi * ivMat[j][k];
  363. #if normalizeShear
  364. //if (normalizeShear && i != j)
  365. if (i != j)
  366. {
  367. d[k + 1] = s1 * d[k + 1] - Sij * s3 * (wj * wj * fi * ivMat[i][k] + wi * wi * fj * ivMat[j][k]);
  368. }
  369. #endif
  370. d[0] -= d[k + 1];
  371. }
  372. #if normalizeShear
  373. //if (normalizeShear && i != j)
  374. if (i != j)
  375. Sij *= s1;
  376. #endif
  377. //float lambda =
  378. // invMass0 * math.lengthsq(d[0]) +
  379. // invMass1 * math.lengthsq(d[1]) +
  380. // invMass2 * math.lengthsq(d[2]) +
  381. // invMass3 * math.lengthsq(d[3]);
  382. float lambda =
  383. math.lengthsq(d[0]) +
  384. math.lengthsq(d[1]) +
  385. math.lengthsq(d[2]) +
  386. math.lengthsq(d[3]);
  387. if (math.abs(lambda) < 1e-6f) // foo: threshold should be scale dependent
  388. continue;
  389. if (i == j)
  390. { // diagonal, stretch
  391. #if normalizeStretch
  392. float s = math.sqrt(Sij);
  393. //lambda = 2.0f * s * (s - 1.0f) / lambda * stretchStiffness[i];
  394. lambda = 2.0f * s * (s - 1.0f) / lambda * stretchStiffness;
  395. #else
  396. //lambda = (Sij - 1.0f) / lambda * stretchStiffness[i];
  397. lambda = (Sij - 1.0f) / lambda * stretchStiffness;
  398. #endif
  399. }
  400. else
  401. { // off diagonal, shear
  402. //lambda = Sij / lambda * shearStiffness[i + j - 1];
  403. lambda = Sij / lambda * shearStiffness;
  404. }
  405. //corr0 -= lambda * invMass0 * d[0];
  406. //corr1 -= lambda * invMass1 * d[1];
  407. //corr2 -= lambda * invMass2 * d[2];
  408. //corr3 -= lambda * invMass3 * d[3];
  409. corr0 -= lambda * d[0];
  410. corr1 -= lambda * d[1];
  411. corr2 -= lambda * d[2];
  412. corr3 -= lambda * d[3];
  413. }
  414. }
  415. // 作業バッファへ格納
  416. int wstart = gdata.writeDataChunk.startIndex;
  417. int windex0 = data.writeIndex0 + wstart;
  418. int windex1 = data.writeIndex1 + wstart;
  419. int windex2 = data.writeIndex2 + wstart;
  420. int windex3 = data.writeIndex3 + wstart;
  421. writeBuffer[windex0] = corr0;
  422. writeBuffer[windex1] = corr1;
  423. writeBuffer[windex2] = corr2;
  424. writeBuffer[windex3] = corr3 + add3;
  425. }
  426. }
  427. [BurstCompile]
  428. struct VolumeSumJob : IJobParallelFor
  429. {
  430. public int runCount;
  431. [Unity.Collections.ReadOnly]
  432. public NativeArray<GroupData> groupDataList;
  433. [Unity.Collections.ReadOnly]
  434. public NativeArray<ReferenceDataIndex> refDataList;
  435. [Unity.Collections.ReadOnly]
  436. public NativeArray<float3> writeBuffer;
  437. // チーム
  438. [Unity.Collections.ReadOnly]
  439. public NativeArray<PhysicsManagerTeamData.TeamData> teamDataList;
  440. [Unity.Collections.ReadOnly]
  441. public NativeArray<int> teamIdList;
  442. [Unity.Collections.ReadOnly]
  443. public NativeArray<PhysicsManagerParticleData.ParticleFlag> flagList;
  444. public NativeArray<float3> inoutNextPosList;
  445. // パーティクルごと
  446. public void Execute(int pindex)
  447. {
  448. var flag = flagList[pindex];
  449. if (flag.IsValid() == false || flag.IsFixed())
  450. return;
  451. // チーム
  452. var team = teamDataList[teamIdList[pindex]];
  453. if (team.IsActive() == false)
  454. return;
  455. if (team.volumeGroupIndex < 0)
  456. return;
  457. // 更新確認
  458. if (team.IsUpdate(runCount) == false)
  459. return;
  460. // グループデータ
  461. var gdata = groupDataList[team.volumeGroupIndex];
  462. if (gdata.active == 0)
  463. return;
  464. // 集計
  465. int start = team.particleChunk.startIndex;
  466. int index = pindex - start;
  467. var refdata = refDataList[gdata.refDataChunk.startIndex + index];
  468. if (refdata.count > 0)
  469. {
  470. float3 corr = 0;
  471. var bindex = gdata.writeDataChunk.startIndex + refdata.startIndex;
  472. for (int i = 0; i < refdata.count; i++)
  473. {
  474. corr += writeBuffer[bindex];
  475. bindex++;
  476. }
  477. corr /= refdata.count;
  478. // 加算
  479. inoutNextPosList[pindex] = inoutNextPosList[pindex] + corr;
  480. }
  481. }
  482. }
  483. }
  484. }