TriangleBendConstraint.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  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 TriangleBendConstraint : PhysicsManagerConstraint
  14. {
  15. /// <summary>
  16. /// 拘束データ
  17. /// todo:共有化可能
  18. /// </summary>
  19. [System.Serializable]
  20. public struct TriangleBendData
  21. {
  22. /// <summary>
  23. /// トライアングル形成パーティクルインデックスx4
  24. /// 2つの三角形、p2-p3が共通辺で、p0/p1が端の独立点
  25. /// p2 +
  26. /// /|\
  27. /// p0 + | + p1
  28. /// \|/
  29. /// p3 +
  30. ///
  31. /// A(p0-p2-p3) B(p1-p3-p2)
  32. ///
  33. /// ただしvindex3が-1の場合は次のように単純なトライアングルの固定位置復元となる
  34. /// v0 +
  35. /// / \
  36. /// v1 +---+ v2
  37. ///
  38. /// v3 = -1
  39. public int vindex0;
  40. public int vindex1;
  41. public int vindex2;
  42. public int vindex3;
  43. /// <summary>
  44. /// 復元角度(ラジアン)
  45. /// </summary>
  46. public float restAngle;
  47. /// <summary>
  48. /// 初期方向性 [Algorithm 2]
  49. /// </summary>
  50. public float direction;
  51. /// <summary>
  52. /// ベンド影響を取得するデプス値(0.0-1.0)
  53. /// </summary>
  54. public float depth;
  55. /// <summary>
  56. /// 書き込みバッファインデックス
  57. /// </summary>
  58. public int writeIndex0;
  59. public int writeIndex1;
  60. public int writeIndex2;
  61. public int writeIndex3;
  62. /// <summary>
  63. /// データが有効か判定する
  64. /// </summary>
  65. /// <returns></returns>
  66. public bool IsValid()
  67. {
  68. return vindex0 > 0 && vindex1 > 0;
  69. }
  70. /// <summary>
  71. /// データが固定位置復元かどうか
  72. /// </summary>
  73. /// <returns></returns>
  74. public bool IsPositionBend()
  75. {
  76. return vindex3 < 0;
  77. }
  78. /// <summary>
  79. /// データが厳密版か判定する
  80. /// </summary>
  81. /// <returns></returns>
  82. //public bool IsStrict()
  83. //{
  84. // return math.abs(direction) > 1e-06f;
  85. //}
  86. }
  87. FixedChunkNativeArray<TriangleBendData> dataList;
  88. /// <summary>
  89. /// データごとのグループインデックス
  90. /// </summary>
  91. FixedChunkNativeArray<short> groupIndexList;
  92. /// <summary>
  93. /// 内部パーティクルインデックスごとの書き込みバッファ参照
  94. /// </summary>
  95. FixedChunkNativeArray<ReferenceDataIndex> refDataList;
  96. /// <summary>
  97. /// 頂点計算結果書き込みバッファ
  98. /// </summary>
  99. FixedChunkNativeArray<float3> writeBuffer;
  100. /// <summary>
  101. /// グループごとの拘束データ
  102. /// </summary>
  103. public struct TriangleBendGroupData
  104. {
  105. public int teamId;
  106. public int active;
  107. /// <summary>
  108. /// アルゴリズム(ClothParams.Algorithmを参照)
  109. /// </summary>
  110. public int algorithm;
  111. /// <summary>
  112. /// 固定点を含むトライアングルの計算の有無
  113. /// </summary>
  114. //public int useIncludeFixed;
  115. /// <summary>
  116. /// 曲げの戻り効果量(0.0-1.0)
  117. /// </summary>
  118. public CurveParam stiffness;
  119. /// <summary>
  120. /// データチャンク
  121. /// </summary>
  122. public ChunkData dataChunk;
  123. /// <summary>
  124. /// グループデータチャンク
  125. /// </summary>
  126. public ChunkData groupIndexChunk;
  127. /// <summary>
  128. /// 内部インデックス用チャンク
  129. /// </summary>
  130. public ChunkData refDataChunk;
  131. /// <summary>
  132. /// 頂点計算結果書き込み用チャンク
  133. /// </summary>
  134. public ChunkData writeDataChunk;
  135. }
  136. FixedNativeList<TriangleBendGroupData> groupList;
  137. //=========================================================================================
  138. public override void Create()
  139. {
  140. dataList = new FixedChunkNativeArray<TriangleBendData>();
  141. groupIndexList = new FixedChunkNativeArray<short>();
  142. refDataList = new FixedChunkNativeArray<ReferenceDataIndex>();
  143. writeBuffer = new FixedChunkNativeArray<float3>();
  144. groupList = new FixedNativeList<TriangleBendGroupData>();
  145. }
  146. public override void Release()
  147. {
  148. dataList.Dispose();
  149. groupIndexList.Dispose();
  150. refDataList.Dispose();
  151. writeBuffer.Dispose();
  152. groupList.Dispose();
  153. }
  154. //=========================================================================================
  155. public int AddGroup(
  156. int teamId, bool active,
  157. ClothParams.Algorithm algorithm,
  158. BezierParam stiffness,
  159. //bool useIncludeFixed,
  160. TriangleBendData[] dataArray, ReferenceDataIndex[] refDataArray, int writeBufferCount)
  161. {
  162. if (dataArray == null || dataArray.Length == 0 || refDataArray == null || refDataArray.Length == 0 || writeBufferCount == 0)
  163. return -1;
  164. var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
  165. // グループデータ作成
  166. var gdata = new TriangleBendGroupData();
  167. gdata.teamId = teamId;
  168. gdata.active = active ? 1 : 0;
  169. gdata.algorithm = (int)algorithm;
  170. //gdata.useIncludeFixed = useIncludeFixed ? 1 : 0;
  171. gdata.stiffness.Setup(stiffness);
  172. gdata.dataChunk = dataList.AddChunk(dataArray.Length);
  173. gdata.groupIndexChunk = groupIndexList.AddChunk(dataArray.Length);
  174. gdata.refDataChunk = refDataList.AddChunk(refDataArray.Length);
  175. gdata.writeDataChunk = writeBuffer.AddChunk(writeBufferCount);
  176. // チャンクデータコピー
  177. dataList.ToJobArray().CopyFromFast(gdata.dataChunk.startIndex, dataArray);
  178. refDataList.ToJobArray().CopyFromFast(gdata.refDataChunk.startIndex, refDataArray);
  179. int group = groupList.Add(gdata);
  180. // データごとのグループインデックス
  181. groupIndexList.Fill(gdata.groupIndexChunk, (short)group);
  182. return group;
  183. }
  184. public override void RemoveTeam(int teamId)
  185. {
  186. var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
  187. int group = teamData.triangleBendGroupIndex;
  188. if (group < 0)
  189. return;
  190. var cdata = groupList[group];
  191. // チャンクデータ削除
  192. dataList.RemoveChunk(cdata.dataChunk);
  193. refDataList.RemoveChunk(cdata.refDataChunk);
  194. writeBuffer.RemoveChunk(cdata.writeDataChunk);
  195. groupIndexList.RemoveChunk(cdata.groupIndexChunk);
  196. // データ削除
  197. groupList.Remove(group);
  198. }
  199. public void ChangeParam(int teamId, bool active, BezierParam stiffness/*, bool useIncludeFixed*/)
  200. {
  201. var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
  202. int group = teamData.triangleBendGroupIndex;
  203. if (group < 0)
  204. return;
  205. var gdata = groupList[group];
  206. gdata.active = active ? 1 : 0;
  207. //gdata.useIncludeFixed = useIncludeFixed ? 1 : 0;
  208. gdata.stiffness.Setup(stiffness);
  209. groupList[group] = gdata;
  210. }
  211. //=========================================================================================
  212. /// <summary>
  213. /// 拘束の解決
  214. /// </summary>
  215. /// <param name="dtime"></param>
  216. /// <param name="jobHandle"></param>
  217. /// <returns></returns>
  218. public override JobHandle SolverConstraint(int runCount, float dtime, float updatePower, int iteration, JobHandle jobHandle)
  219. {
  220. if (groupList.Count == 0)
  221. return jobHandle;
  222. // ステップ1:ベンドの計算
  223. var job = new TriangleBendCalcJob()
  224. {
  225. updatePower = updatePower,
  226. runCount = runCount,
  227. triangleBendGroupDataList = groupList.ToJobArray(),
  228. triangleBendList = dataList.ToJobArray(),
  229. groupIndexList = groupIndexList.ToJobArray(),
  230. teamDataList = Manager.Team.teamDataList.ToJobArray(),
  231. nextPosList = Manager.Particle.InNextPosList.ToJobArray(),
  232. basePosList = Manager.Particle.basePosList.ToJobArray(),
  233. writeBuffer = writeBuffer.ToJobArray(),
  234. };
  235. jobHandle = job.Schedule(dataList.Length, 64, jobHandle);
  236. // ステップ2:ベンド結果の集計
  237. var job2 = new TriangleBendSumJob()
  238. {
  239. runCount = runCount,
  240. triangleBendGroupDataList = groupList.ToJobArray(),
  241. refDataList = refDataList.ToJobArray(),
  242. writeBuffer = writeBuffer.ToJobArray(),
  243. teamDataList = Manager.Team.teamDataList.ToJobArray(),
  244. teamIdList = Manager.Particle.teamIdList.ToJobArray(),
  245. flagList = Manager.Particle.flagList.ToJobArray(),
  246. inoutNextPosList = Manager.Particle.InNextPosList.ToJobArray(),
  247. posList = Manager.Particle.posList.ToJobArray(),
  248. };
  249. jobHandle = job2.Schedule(Manager.Particle.Length, 64, jobHandle);
  250. return jobHandle;
  251. }
  252. [BurstCompile]
  253. struct TriangleBendCalcJob : IJobParallelFor
  254. {
  255. public float updatePower;
  256. public int runCount;
  257. [Unity.Collections.ReadOnly]
  258. public NativeArray<TriangleBendGroupData> triangleBendGroupDataList;
  259. [Unity.Collections.ReadOnly]
  260. public NativeArray<TriangleBendData> triangleBendList;
  261. [Unity.Collections.ReadOnly]
  262. public NativeArray<short> groupIndexList;
  263. [Unity.Collections.ReadOnly]
  264. public NativeArray<PhysicsManagerTeamData.TeamData> teamDataList;
  265. [Unity.Collections.ReadOnly]
  266. public NativeArray<float3> nextPosList;
  267. [Unity.Collections.ReadOnly]
  268. public NativeArray<float3> basePosList;
  269. [Unity.Collections.WriteOnly]
  270. [NativeDisableParallelForRestriction]
  271. public NativeArray<float3> writeBuffer;
  272. // ベンドデータごと
  273. public void Execute(int index)
  274. {
  275. var data = triangleBendList[index];
  276. if (data.IsValid() == false)
  277. return;
  278. int gindex = groupIndexList[index];
  279. var gdata = triangleBendGroupDataList[gindex];
  280. if (gdata.teamId == 0 || gdata.active == 0)
  281. return;
  282. var tdata = teamDataList[gdata.teamId];
  283. if (tdata.IsActive() == false)
  284. return;
  285. // 更新確認
  286. if (tdata.IsUpdate(runCount) == false)
  287. return;
  288. int pstart = tdata.particleChunk.startIndex;
  289. float3 corr0 = 0;
  290. float3 corr1 = 0;
  291. float3 corr2 = 0;
  292. float3 corr3 = 0;
  293. int pindex0 = data.vindex0 + pstart;
  294. int pindex1 = data.vindex1 + pstart;
  295. int pindex2 = data.vindex2 + pstart;
  296. int pindex3 = data.IsPositionBend() ? -1 : (data.vindex3 + pstart);
  297. float3 nextpos0 = nextPosList[pindex0];
  298. float3 nextpos1 = nextPosList[pindex1];
  299. float3 nextpos2 = nextPosList[pindex2];
  300. float3 nextpos3 = data.IsPositionBend() ? 0 : nextPosList[pindex3];
  301. // 厳密正
  302. //bool isStrict = data.IsStrict();
  303. bool isStrict = gdata.algorithm == 1;
  304. // 復元率
  305. float stiffness = gdata.stiffness.Evaluate(data.depth);
  306. stiffness = (1.0f - math.pow(1.0f - stiffness, updatePower));
  307. // 復元方法判定
  308. if (data.IsPositionBend() == false)
  309. {
  310. // トライアングルベンド
  311. float3 e = nextpos3 - nextpos2;
  312. float elen = math.length(e);
  313. if (elen > 1e-06f)
  314. {
  315. float invElen = 1.0f / elen;
  316. float3 n1 = math.cross(nextpos2 - nextpos0, nextpos3 - nextpos0);
  317. float n1_lsq = math.lengthsq(n1);
  318. float3 n2 = math.cross(nextpos3 - nextpos1, nextpos2 - nextpos1);
  319. float n2_lsq = math.lengthsq(n2);
  320. if (n1_lsq > 0 && n2_lsq > 0) // v1.12.0
  321. {
  322. n1 /= n1_lsq;
  323. n2 /= n2_lsq;
  324. float3 d0 = elen * n1;
  325. float3 d1 = elen * n2;
  326. float3 d2 = math.dot(nextpos0 - nextpos3, e) * invElen * n1 + math.dot(nextpos1 - nextpos3, e) * invElen * n2;
  327. float3 d3 = math.dot(nextpos2 - nextpos0, e) * invElen * n1 + math.dot(nextpos2 - nextpos1, e) * invElen * n2;
  328. n1 = math.normalize(n1);
  329. n2 = math.normalize(n2);
  330. float dot = math.dot(n1, n2);
  331. dot = math.clamp(dot, -1.0f, 1.0f);
  332. float phi = math.acos(dot);
  333. float lambda =
  334. math.lengthsq(d0) +
  335. math.lengthsq(d1) +
  336. math.lengthsq(d2) +
  337. math.lengthsq(d3);
  338. // 方向性
  339. float direction = math.dot(math.cross(n1, n2), e);
  340. // Strictでは方向を考慮した角度で計算
  341. phi = math.select(phi, phi * math.sign(direction), isStrict);
  342. // 安定性
  343. float rest = math.abs(phi - data.restAngle);
  344. //if (stiffness > 0.5f && rest > 1.5f)
  345. // stiffness = 0.5f;
  346. // 角度による安定化
  347. if (isStrict)
  348. {
  349. // 復元角度が大きいほどstiffnessが強くなる
  350. float ratio = math.max(math.pow(math.saturate(rest / math.PI), 0.5f), 0.1f);
  351. stiffness *= ratio;
  352. }
  353. lambda = (phi - data.restAngle) / lambda * stiffness;
  354. // 旧来処理
  355. lambda = math.select(lambda * math.sign(direction), lambda, isStrict);
  356. corr0 = lambda * d0;
  357. corr1 = lambda * d1;
  358. corr2 = lambda * d2;
  359. corr3 = lambda * d3;
  360. }
  361. }
  362. }
  363. // v1.11.0では一旦オミット
  364. //else
  365. //{
  366. // // 固定頂点を含む特殊復元
  367. // if (gdata.useIncludeFixed == 1)
  368. // {
  369. // // 単純にベース位置に復元させる
  370. // stiffness *= 0.2f; // 調整
  371. // float3 basepos0 = basePosList[pindex0];
  372. // float3 basepos1 = basePosList[pindex1];
  373. // float3 basepos2 = basePosList[pindex2];
  374. // corr0 = (basepos0 - nextpos0) * stiffness;
  375. // corr1 = (basepos1 - nextpos1) * stiffness;
  376. // corr2 = (basepos2 - nextpos2) * stiffness;
  377. // // todo:Interlockに切り替わった場合はここで処理を抜ける
  378. // }
  379. //}
  380. // 作業バッファへ格納
  381. int wstart = gdata.writeDataChunk.startIndex;
  382. int windex0 = data.writeIndex0 + wstart;
  383. int windex1 = data.writeIndex1 + wstart;
  384. int windex2 = data.writeIndex2 + wstart;
  385. writeBuffer[windex0] = corr0;
  386. writeBuffer[windex1] = corr1;
  387. writeBuffer[windex2] = corr2;
  388. if (data.IsPositionBend() == false)
  389. {
  390. int windex3 = data.writeIndex3 + wstart;
  391. writeBuffer[windex3] = corr3;
  392. }
  393. }
  394. }
  395. [BurstCompile]
  396. struct TriangleBendSumJob : IJobParallelFor
  397. {
  398. public int runCount;
  399. [Unity.Collections.ReadOnly]
  400. public NativeArray<TriangleBendGroupData> triangleBendGroupDataList;
  401. [Unity.Collections.ReadOnly]
  402. public NativeArray<ReferenceDataIndex> refDataList;
  403. [Unity.Collections.ReadOnly]
  404. public NativeArray<float3> writeBuffer;
  405. // チーム
  406. [Unity.Collections.ReadOnly]
  407. public NativeArray<PhysicsManagerTeamData.TeamData> teamDataList;
  408. [Unity.Collections.ReadOnly]
  409. public NativeArray<int> teamIdList;
  410. [Unity.Collections.ReadOnly]
  411. public NativeArray<PhysicsManagerParticleData.ParticleFlag> flagList;
  412. public NativeArray<float3> inoutNextPosList;
  413. public NativeArray<float3> posList;
  414. // パーティクルごと
  415. public void Execute(int pindex)
  416. {
  417. var flag = flagList[pindex];
  418. if (flag.IsValid() == false || flag.IsFixed())
  419. return;
  420. // チーム
  421. var team = teamDataList[teamIdList[pindex]];
  422. if (team.IsActive() == false)
  423. return;
  424. if (team.triangleBendGroupIndex < 0)
  425. return;
  426. // 更新確認
  427. if (team.IsUpdate(runCount) == false)
  428. return;
  429. // グループデータ
  430. var gdata = triangleBendGroupDataList[team.triangleBendGroupIndex];
  431. if (gdata.active == 0)
  432. return;
  433. // 集計
  434. int start = team.particleChunk.startIndex;
  435. int index = pindex - start;
  436. var refdata = refDataList[gdata.refDataChunk.startIndex + index];
  437. if (refdata.count > 0)
  438. {
  439. float3 corr = 0;
  440. var bindex = gdata.writeDataChunk.startIndex + refdata.startIndex;
  441. for (int i = 0; i < refdata.count; i++)
  442. {
  443. corr += writeBuffer[bindex];
  444. bindex++;
  445. }
  446. corr /= refdata.count;
  447. // 加算
  448. inoutNextPosList[pindex] = inoutNextPosList[pindex] + corr;
  449. // 速度影響(Strictに合わせる)
  450. var av = corr * (1.0f - Define.Compute.TriangleBendVelocityInfluence); // 実験結果より(0.5)
  451. posList[pindex] = posList[pindex] + av;
  452. }
  453. }
  454. }
  455. }
  456. }