// Magica Cloth.
// Copyright (c) MagicaSoft, 2020-2022.
// https://magicasoft.jp
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
namespace MagicaCloth
{
///
/// コライダーによるパーティクル押し出し拘束
///
public class ColliderExtrusionConstraint : PhysicsManagerConstraint
{
public override void Create()
{
}
public override void RemoveTeam(int teamId)
{
}
// public void ChangeParam(int teamId, bool useCollision)
// {
// Manager.Team.SetFlag(teamId, PhysicsManagerTeamData.Flag_Collision, useCollision);
// }
public override void Release()
{
}
//=========================================================================================
public override JobHandle SolverConstraint(int runCount, float dtime, float updatePower, int iteration, JobHandle jobHandle)
{
if (Manager.Particle.ColliderCount <= 0)
return jobHandle;
#if true
// コリジョン押し出し拘束
var job1 = new CollisionExtrusionJob()
{
runCount = runCount,
flagList = Manager.Particle.flagList.ToJobArray(),
teamIdList = Manager.Particle.teamIdList.ToJobArray(),
nextPosList = Manager.Particle.InNextPosList.ToJobArray(),
nextRotList = Manager.Particle.InNextRotList.ToJobArray(),
collisionLinkIdList = Manager.Particle.collisionLinkIdList.ToJobArray(),
posList = Manager.Particle.posList.ToJobArray(),
rotList = Manager.Particle.rotList.ToJobArray(),
frictionList = Manager.Particle.frictionList.ToJobArray(),
collisionNormalList = Manager.Particle.collisionNormalList.ToJobArray(),
teamDataList = Manager.Team.teamDataList.ToJobArray(),
};
jobHandle = job1.Schedule(Manager.Particle.Length, 64, jobHandle);
#endif
return jobHandle;
}
//=========================================================================================
///
/// コリジョン押し出し拘束ジョブ
/// 移動パーティクルごとに計算
///
[BurstCompile]
struct CollisionExtrusionJob : IJobParallelFor
{
public int runCount;
[Unity.Collections.ReadOnly]
public NativeArray flagList;
[Unity.Collections.ReadOnly]
public NativeArray teamIdList;
[NativeDisableParallelForRestriction]
public NativeArray nextPosList;
[Unity.Collections.ReadOnly]
public NativeArray nextRotList;
public NativeArray collisionLinkIdList;
[NativeDisableParallelForRestriction]
public NativeArray posList;
[Unity.Collections.ReadOnly]
public NativeArray rotList;
[Unity.Collections.ReadOnly]
public NativeArray frictionList;
[Unity.Collections.ReadOnly]
public NativeArray collisionNormalList;
[Unity.Collections.ReadOnly]
public NativeArray teamDataList;
// パーティクルごと
public void Execute(int index)
{
var flag = flagList[index];
if (flag.IsValid() == false || flag.IsFixed() || flag.IsCollider())
return;
// チーム
var team = teamIdList[index];
var teamData = teamDataList[team];
if (teamData.IsActive() == false)
return;
if (teamData.IsFlag(PhysicsManagerTeamData.Flag_Collision) == false)
return;
// 更新確認
if (teamData.IsUpdate(runCount) == false)
return;
// 接続コライダー
int cindex = collisionLinkIdList[index];
collisionLinkIdList[index] = 0; // リセット
if (cindex <= 0)
return;
var cflag = flagList[cindex];
if (cflag.IsValid() == false || cflag.IsCollider() == false)
return;
var friction = frictionList[index];
if (friction < Define.Compute.Epsilon)
return;
float3 nextpos = nextPosList[index];
//int vindex = index - teamData.particleChunk.startIndex;
//Debug.Log($"vindex:{vindex}");
// 移動前コライダー姿勢
var oldcpos = posList[cindex];
var oldcrot = rotList[cindex];
var v = nextpos - oldcpos; // nextposでないとダメ(oldPosList[index]ではまずい)
var ioldcrot = math.inverse(oldcrot);
var lpos = math.mul(ioldcrot, v);
// 移動後コライダー姿勢
var cpos = nextPosList[cindex];
var crot = nextRotList[cindex];
var fpos = math.mul(crot, lpos) + cpos;
// 押し出しベクトル
var ev = fpos - nextpos;
var elen = math.length(ev);
if (elen < 1e-06f)
{
// コライダーが動いていない
return;
}
// アルゴリズム変更(v1.9.2)
// 衝突面法線と押し出しベクトルの角度に応じて強さを変更
var cn = collisionNormalList[index];
var dot = math.dot(cn, ev / elen);
dot = math.pow(dot, 0.5f); // 角度(内積)に対して押し出し力を強めにする
float d = math.max(dot, 0.0f);
// 摩擦係数に応じて強さを変更
d *= math.saturate(friction);
// 押し出し
var opos = nextpos;
nextpos = math.lerp(nextpos, fpos, d);
nextPosList[index] = nextpos;
// 速度影響
var av = (nextpos - opos) * (1.0f - Define.Compute.ColliderExtrusionVelocityInfluence); // 跳ねを抑えるため少し抑える(※抑えすぎると突き抜けやすくなるので注意)
posList[index] = posList[index] + av;
}
}
}
}