// Magica Cloth.
// Copyright (c) MagicaSoft, 2020-2022.
// https://magicasoft.jp
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
namespace MagicaCloth
{
///
/// 最大最小距離拘束
/// ルートではなく自身の親から正確に計算する
/// ※実験の結果一長一短のため今は不採用とする(1.8.0)
///
public class ClampDistance2Constraint : PhysicsManagerConstraint
{
///
/// 拘束データ
///
[System.Serializable]
public struct ClampDistance2Data
{
///
/// 計算頂点インデックス
///
public int vertexIndex;
///
/// 親頂点インデックス
///
public int parentVertexIndex;
///
/// オリジナル距離
///
public float length;
}
FixedChunkNativeArray dataList;
[System.Serializable]
public struct ClampDistance2RootInfo
{
public ushort startIndex;
public ushort dataLength;
}
FixedChunkNativeArray rootInfoList;
///
/// グループごとの拘束データ
///
public struct GroupData
{
public int teamId;
public int active;
///
/// 最小距離割合
///
public float minRatio;
///
/// 最大距離割合
///
public float maxRatio;
///
/// 速度影響
///
public float velocityInfluence;
public ChunkData dataChunk;
public ChunkData rootInfoChunk;
}
public FixedNativeList groupList;
///
/// ルートごとのチームインデックス
///
FixedChunkNativeArray rootTeamList;
///
/// 拘束データごとの作業バッファ
///
//FixedChunkNativeArray lengthBuffer;
//=========================================================================================
public override void Create()
{
dataList = new FixedChunkNativeArray();
rootInfoList = new FixedChunkNativeArray();
groupList = new FixedNativeList();
rootTeamList = new FixedChunkNativeArray();
}
public override void Release()
{
dataList.Dispose();
rootInfoList.Dispose();
groupList.Dispose();
rootTeamList.Dispose();
}
//=========================================================================================
public int AddGroup(
int teamId,
bool active,
float minRatio,
float maxRatio,
float velocityInfluence,
ClampDistance2Data[] dataArray,
ClampDistance2RootInfo[] rootInfoArray
)
{
if (dataArray == null || dataArray.Length == 0 || rootInfoArray == null || rootInfoArray.Length == 0)
return -1;
var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
var gdata = new GroupData();
gdata.teamId = teamId;
gdata.active = active ? 1 : 0;
gdata.minRatio = minRatio;
gdata.maxRatio = maxRatio;
gdata.velocityInfluence = velocityInfluence;
gdata.dataChunk = dataList.AddChunk(dataArray.Length);
gdata.rootInfoChunk = rootInfoList.AddChunk(rootInfoArray.Length);
// チャンクデータコピー
dataList.ToJobArray().CopyFromFast(gdata.dataChunk.startIndex, dataArray);
rootInfoList.ToJobArray().CopyFromFast(gdata.rootInfoChunk.startIndex, rootInfoArray);
int group = groupList.Add(gdata);
// ルートごとのチームインデックス
var c = rootTeamList.AddChunk(rootInfoArray.Length);
rootTeamList.Fill(c, teamId);
return group;
}
public override void RemoveTeam(int teamId)
{
var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
int group = teamData.clampDistance2GroupIndex;
if (group < 0)
return;
var cdata = groupList[group];
// チャンクデータ削除
dataList.RemoveChunk(cdata.dataChunk);
rootInfoList.RemoveChunk(cdata.rootInfoChunk);
rootTeamList.RemoveChunk(cdata.rootInfoChunk);
// データ削除
groupList.Remove(group);
}
public void ChangeParam(
int teamId,
bool active,
float minRatio,
float maxRatio,
float velocityInfluence
)
{
var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
int group = teamData.clampDistance2GroupIndex;
if (group < 0)
return;
var gdata = groupList[group];
gdata.active = active ? 1 : 0;
gdata.minRatio = minRatio;
gdata.maxRatio = maxRatio;
gdata.velocityInfluence = velocityInfluence;
groupList[group] = gdata;
}
//=========================================================================================
///
/// 拘束の解決
///
///
///
///
public override JobHandle SolverConstraint(int runCount, float dtime, float updatePower, int iteration, JobHandle jobHandle)
{
if (groupList.Count == 0)
return jobHandle;
// 最大距離拘束(ルートラインごと)
var job1 = new ClampDistance2Job()
{
runCount = runCount,
dataList = dataList.ToJobArray(),
rootInfoList = rootInfoList.ToJobArray(),
rootTeamList = rootTeamList.ToJobArray(),
groupList = groupList.ToJobArray(),
teamDataList = Manager.Team.teamDataList.ToJobArray(),
flagList = Manager.Particle.flagList.ToJobArray(),
frictionList = Manager.Particle.frictionList.ToJobArray(),
nextPosList = Manager.Particle.InNextPosList.ToJobArray(),
posList = Manager.Particle.posList.ToJobArray(),
};
jobHandle = job1.Schedule(rootTeamList.Length, 8, jobHandle);
return jobHandle;
}
///
/// 最大距離拘束ジョブ
///
[BurstCompile]
struct ClampDistance2Job : IJobParallelFor
{
public int runCount;
[Unity.Collections.ReadOnly]
public NativeArray dataList;
[Unity.Collections.ReadOnly]
public NativeArray rootInfoList;
[Unity.Collections.ReadOnly]
public NativeArray rootTeamList;
[Unity.Collections.ReadOnly]
public NativeArray groupList;
// チーム
[Unity.Collections.ReadOnly]
public NativeArray teamDataList;
[Unity.Collections.ReadOnly]
public NativeArray flagList;
[Unity.Collections.ReadOnly]
public NativeArray frictionList;
[NativeDisableParallelForRestriction]
public NativeArray nextPosList;
[NativeDisableParallelForRestriction]
public NativeArray posList;
// ルートラインごと
public void Execute(int rootIndex)
{
// チーム
int teamIndex = rootTeamList[rootIndex];
if (teamIndex == 0)
return;
var team = teamDataList[teamIndex];
if (team.IsActive() == false || team.clampDistance2GroupIndex < 0)
return;
// 更新確認
if (team.IsUpdate(runCount) == false)
return;
// グループデータ
var gdata = groupList[team.clampDistance2GroupIndex];
if (gdata.active == 0)
return;
// データ
var rootInfo = rootInfoList[rootIndex];
int dataIndex = rootInfo.startIndex + gdata.dataChunk.startIndex;
int dataCount = rootInfo.dataLength;
int pstart = team.particleChunk.startIndex;
for (int i = 0; i < dataCount; i++)
{
var data = dataList[dataIndex + i];
int pindex = data.parentVertexIndex;
if (pindex < 0)
continue;
var index = data.vertexIndex;
index += pstart;
pindex += pstart;
var flag = flagList[index];
if (flag.IsValid() == false || flag.IsFixed())
continue;
var npos = nextPosList[index];
var opos = npos;
var ppos = nextPosList[pindex];
// 現在のベクトル
var v = npos - ppos;
// 長さクランプ
var len = data.length * team.scaleRatio;
v = MathUtility.ClampVector(v, len * gdata.minRatio, len * gdata.maxRatio);
npos = ppos + v;
// 格納
nextPosList[index] = npos;
// 速度影響
var av = (npos - opos) * (1.0f - gdata.velocityInfluence);
posList[index] = posList[index] + av;
}
}
}
}
}