// Magica Cloth.
// Copyright (c) MagicaSoft, 2020-2022.
// https://magicasoft.jp
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
namespace MagicaCloth
{
///
/// スプリング拘束
/// BasePosに戻る動作を行う
///
public class SpringConstraint : PhysicsManagerConstraint
{
///
/// グループごとの拘束データ
///
public struct GroupData
{
public int teamId;
public int active;
///
/// スプリング力
///
public float spring;
}
public FixedNativeList groupList;
//=========================================================================================
public override void Create()
{
groupList = new FixedNativeList();
}
public override void Release()
{
groupList.Dispose();
}
//=========================================================================================
public int AddGroup(int teamId, bool active, float spring)
{
var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
var gdata = new GroupData();
gdata.teamId = teamId;
gdata.active = active ? 1 : 0;
gdata.spring = spring;
int group = groupList.Add(gdata);
return group;
}
public override void RemoveTeam(int teamId)
{
var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
int group = teamData.springGroupIndex;
if (group < 0)
return;
// データ削除
groupList.Remove(group);
}
public void ChangeParam(int teamId, bool active, float spring)
{
var teamData = MagicaPhysicsManager.Instance.Team.teamDataList[teamId];
int group = teamData.springGroupIndex;
if (group < 0)
return;
var gdata = groupList[group];
gdata.active = active ? 1 : 0;
gdata.spring = spring;
groupList[group] = gdata;
}
//public int ActiveCount
//{
// get
// {
// int cnt = 0;
// for (int i = 0; i < groupList.Length; i++)
// if (groupList[i].active == 1)
// cnt++;
// return cnt;
// }
//}
//=========================================================================================
///
/// 拘束の解決
///
///
///
///
public override JobHandle SolverConstraint(int runCount, float dtime, float updatePower, int iteration, JobHandle jobHandle)
{
//if (ActiveCount == 0)
if (groupList.Count == 0)
return jobHandle;
// スプリング拘束(パーティクルごとに実行する)
var job1 = new SpringJob()
{
updatePower = updatePower,
runCount = runCount,
groupList = groupList.ToJobArray(),
teamDataList = Manager.Team.teamDataList.ToJobArray(),
teamIdList = Manager.Particle.teamIdList.ToJobArray(),
flagList = Manager.Particle.flagList.ToJobArray(),
basePosList = Manager.Particle.basePosList.ToJobArray(),
nextPosList = Manager.Particle.InNextPosList.ToJobArray()
};
jobHandle = job1.Schedule(Manager.Particle.Length, 64, jobHandle);
return jobHandle;
}
///
/// スプリング拘束ジョブ
/// パーティクルごとに計算
///
[BurstCompile]
struct SpringJob : IJobParallelFor
{
public float updatePower;
public int runCount;
[Unity.Collections.ReadOnly]
public NativeArray groupList;
// チーム
[Unity.Collections.ReadOnly]
public NativeArray teamDataList;
[Unity.Collections.ReadOnly]
public NativeArray teamIdList;
[Unity.Collections.ReadOnly]
public NativeArray flagList;
[Unity.Collections.ReadOnly]
public NativeArray basePosList;
public NativeArray nextPosList;
// パーティクルごと
public void Execute(int index)
{
var flag = flagList[index];
if (flag.IsValid() == false || flag.IsFixed())
return;
var team = teamDataList[teamIdList[index]];
if (team.IsActive() == false)
return;
if (team.springGroupIndex < 0)
return;
// 更新確認
if (team.IsUpdate(runCount) == false)
return;
// グループデータ
var gdata = groupList[team.springGroupIndex];
if (gdata.active == 0)
return;
var nextpos = nextPosList[index];
// baseposに戻る移動を行う
var basepos = basePosList[index];
float power = 1.0f - math.pow(1.0f - gdata.spring, updatePower);
nextpos = math.lerp(nextpos, basepos, power);
// 書き出し
nextPosList[index] = nextpos;
}
}
}
}