123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254 |
- // Magica Cloth.
- // Copyright (c) MagicaSoft, 2020-2022.
- // https://magicasoft.jp
- using System.Collections.Generic;
- using Unity.Burst;
- using Unity.Collections;
- using Unity.Jobs;
- using Unity.Mathematics;
- using UnityEngine.Jobs;
- using UnityEngine.Profiling;
- namespace MagicaCloth
- {
- /// <summary>
- /// 計算処理
- /// </summary>
- public class PhysicsManagerCompute : PhysicsManagerAccess
- {
- /// <summary>
- /// 拘束判定繰り返し回数
- /// </summary>
- //[Header("拘束全体の反復回数")]
- //[Range(1, 8)]
- //public int solverIteration = 2;
- private int solverIteration = 1;
- /// <summary>
- /// 拘束条件
- /// </summary>
- List<PhysicsManagerConstraint> constraints = new List<PhysicsManagerConstraint>();
- public ClampPositionConstraint ClampPosition { get; private set; }
- public ClampDistanceConstraint ClampDistance { get; private set; }
- //public ClampDistance2Constraint ClampDistance2 { get; private set; }
- public ClampRotationConstraint ClampRotation { get; private set; }
- public SpringConstraint Spring { get; private set; }
- public RestoreDistanceConstraint RestoreDistance { get; private set; }
- public RestoreRotationConstraint RestoreRotation { get; private set; }
- public TriangleBendConstraint TriangleBend { get; private set; }
- public ColliderCollisionConstraint Collision { get; private set; }
- public PenetrationConstraint Penetration { get; private set; }
- public ColliderExtrusionConstraint ColliderExtrusion { get; private set; }
- public TwistConstraint Twist { get; private set; }
- public CompositeRotationConstraint CompositeRotation { get; private set; }
- //public ColliderAfterCollisionConstraint AfterCollision { get; private set; }
- //public EdgeCollisionConstraint EdgeCollision { get; private set; }
- //public VolumeConstraint Volume { get; private set; }
- /// <summary>
- /// ワーカーリスト
- /// </summary>
- List<PhysicsManagerWorker> workers = new List<PhysicsManagerWorker>();
- public RenderMeshWorker RenderMeshWorker { get; private set; }
- public VirtualMeshWorker VirtualMeshWorker { get; private set; }
- public MeshParticleWorker MeshParticleWorker { get; private set; }
- public SpringMeshWorker SpringMeshWorker { get; private set; }
- public AdjustRotationWorker AdjustRotationWorker { get; private set; }
- public LineWorker LineWorker { get; private set; }
- public TriangleWorker TriangleWorker { get; private set; }
- public BaseSkinningWorker BaseSkinningWorker { get; private set; }
- /// <summary>
- /// マスタージョブハンドル
- /// すべてのジョブはこのハンドルに連結される
- /// </summary>
- JobHandle jobHandle;
- private bool runMasterJob = false;
- private int swapIndex = 0;
- /// <summary>
- /// プロファイラ用
- /// </summary>
- public CustomSampler SamplerCalcMesh { get; set; }
- public CustomSampler SamplerWriteMesh { get; set; }
- //=========================================================================================
- /// <summary>
- /// 初期設定
- /// </summary>
- public override void Create()
- {
- // 拘束の作成
- // ※この並び順が実行順番となります。
- // コリジョン
- ColliderExtrusion = new ColliderExtrusionConstraint();
- constraints.Add(ColliderExtrusion);
- Penetration = new PenetrationConstraint();
- constraints.Add(Penetration);
- Collision = new ColliderCollisionConstraint();
- constraints.Add(Collision);
- // 移動制限
- ClampDistance = new ClampDistanceConstraint();
- constraints.Add(ClampDistance);
- // 主なクロスシミュレーション
- Spring = new SpringConstraint();
- constraints.Add(Spring);
- Twist = new TwistConstraint();
- constraints.Add(Twist);
- RestoreDistance = new RestoreDistanceConstraint();
- constraints.Add(RestoreDistance);
- RestoreRotation = new RestoreRotationConstraint();
- constraints.Add(RestoreRotation);
- CompositeRotation = new CompositeRotationConstraint();
- constraints.Add(CompositeRotation);
- // 形状維持
- TriangleBend = new TriangleBendConstraint();
- constraints.Add(TriangleBend);
- //Volume = new VolumeConstraint();
- //constraints.Add(Volume);
- // 移動制限2
- ClampPosition = new ClampPositionConstraint();
- constraints.Add(ClampPosition);
- ClampRotation = new ClampRotationConstraint();
- constraints.Add(ClampRotation);
- foreach (var con in constraints)
- con.Init(manager);
- // ワーカーの作成
- // ※この並び順は変更してはいけません。
- RenderMeshWorker = new RenderMeshWorker();
- workers.Add(RenderMeshWorker);
- VirtualMeshWorker = new VirtualMeshWorker();
- workers.Add(VirtualMeshWorker);
- MeshParticleWorker = new MeshParticleWorker();
- workers.Add(MeshParticleWorker);
- SpringMeshWorker = new SpringMeshWorker();
- workers.Add(SpringMeshWorker);
- AdjustRotationWorker = new AdjustRotationWorker();
- workers.Add(AdjustRotationWorker);
- LineWorker = new LineWorker();
- workers.Add(LineWorker);
- TriangleWorker = new TriangleWorker();
- workers.Add(TriangleWorker);
- BaseSkinningWorker = new BaseSkinningWorker();
- workers.Add(BaseSkinningWorker);
- foreach (var worker in workers)
- worker.Init(manager);
- // プロファイラ用
- SamplerCalcMesh = CustomSampler.Create("CalcMesh");
- SamplerWriteMesh = CustomSampler.Create("WriteMesh");
- }
- /// <summary>
- /// 破棄
- /// </summary>
- public override void Dispose()
- {
- if (constraints != null)
- {
- foreach (var con in constraints)
- con.Release();
- }
- if (workers != null)
- {
- foreach (var worker in workers)
- worker.Release();
- }
- }
- /// <summary>
- /// 各コンストレイント/ワーカーから指定グループのデータを削除する
- /// </summary>
- /// <param name="teamId"></param>
- public void RemoveTeam(int teamId)
- {
- if (MagicaPhysicsManager.Instance.Team.IsValidData(teamId) == false)
- return;
- if (constraints != null)
- {
- foreach (var con in constraints)
- con.RemoveTeam(teamId);
- }
- if (workers != null)
- {
- foreach (var worker in workers)
- worker.RemoveGroup(teamId);
- }
- }
- //=========================================================================================
- /// <summary>
- /// ボーン姿勢を元の位置に復元する
- /// </summary>
- internal void UpdateRestoreBone(PhysicsTeam.TeamUpdateMode updateMode)
- {
- // 活動チームが1つ以上ある場合のみ更新
- if (Team.ActiveTeamCount > 0)
- {
- // トランスフォーム姿勢のリセット
- Bone.ResetBoneFromTransform(updateMode == PhysicsTeam.TeamUpdateMode.UnityPhysics);
- }
- }
- /// <summary>
- /// ボーン姿勢を読み込む
- /// </summary>
- internal void UpdateReadBone()
- {
- // 活動チームが1つ以上ある場合のみ更新
- if (Team.ActiveTeamCount > 0)
- {
- // トランスフォーム姿勢の読み込み
- Bone.ReadBoneFromTransform();
- }
- }
- /// <summary>
- /// メインスレッドで行うチームデータ更新処理
- /// </summary>
- internal void UpdateTeamAlways()
- {
- // 常に実行するチームデータ更新
- Team.PreUpdateTeamAlways();
- }
- /// <summary>
- /// クロスシミュレーション計算開始
- /// </summary>
- /// <param name="update"></param>
- internal void UpdateStartSimulation(UpdateTimeManager update)
- {
- // マネージャ非アクティブ時にはシミュレーション計算を完全に停止させる
- if (MagicaPhysicsManager.Instance.IsActive == false)
- return;
- // 時間
- float deltaTime = update.DeltaTime;
- float physicsDeltaTime = update.PhysicsDeltaTime;
- float updatePower = update.UpdatePower;
- float updateDeltaTime = update.UpdateIntervalTime;
- int ups = update.UpdatePerSecond;
- // 活動チームが1つ以上ある場合のみ更新
- if (Team.ActiveTeamCount > 0)
- {
- // 今回フレームの更新回数
- int updateCount = Team.CalcMaxUpdateCount(ups, deltaTime, physicsDeltaTime, updateDeltaTime);
- //Debug.Log($"updateCount:{updateCount} dtime:{deltaTime} pdtime:{physicsDeltaTime} fixedCount:{update.FixedUpdateCount}");
- // 風更新
- //Wind.UpdateWind();
- // チームデータ更新、更新回数確定、ワールド移動影響、テレポート
- Team.PreUpdateTeamData(deltaTime, physicsDeltaTime, updateDeltaTime, ups, updateCount);
- // ワーカー処理
- WarmupWorker();
- // ボーン姿勢をパーティクルにコピーする
- Particle.UpdateBoneToParticle();
- // 物理更新前ワーカー処理
- //MasterJob = RenderMeshWorker.PreUpdate(MasterJob); // 何もなし
- MasterJob = VirtualMeshWorker.PreUpdate(MasterJob); // 仮想メッシュをスキニングしワールド姿勢を求める
- MasterJob = MeshParticleWorker.PreUpdate(MasterJob); // 仮想メッシュ頂点姿勢を連動パーティクルにコピーする
- //MasterJob = SpringMeshWorker.PreUpdate(MasterJob); // 何もなし
- //MasterJob = AdjustRotationWorker.PreUpdate(MasterJob); // 何もなし
- //MasterJob = LineWorker.PreUpdate(MasterJob); // 何もなし
- MasterJob = BaseSkinningWorker.PreUpdate(MasterJob); // ベーススキニングによりbasePos/baseRotをスキニング
- // パーティクルのリセット判定
- Particle.UpdateResetParticle();
- // 物理更新
- for (int i = 0, cnt = updateCount; i < cnt; i++)
- {
- UpdatePhysics(updateCount, i, updatePower, updateDeltaTime);
- }
- // 物理演算後処理
- PostUpdatePhysics(updateDeltaTime);
- // 物理更新後ワーカー処理
- MasterJob = TriangleWorker.PostUpdate(MasterJob); // トライアングル回転調整
- MasterJob = LineWorker.PostUpdate(MasterJob); // ラインの回転調整
- MasterJob = AdjustRotationWorker.PostUpdate(MasterJob); // パーティクル回転調整(Adjust Rotation)
- Particle.UpdateParticleToBone(); // パーティクル姿勢をボーン姿勢に書き戻す(ここに挟まないと駄目)
- MasterJob = SpringMeshWorker.PostUpdate(MasterJob); // メッシュスプリング
- MasterJob = MeshParticleWorker.PostUpdate(MasterJob); // パーティクル姿勢を仮想メッシュに書き出す
- MasterJob = VirtualMeshWorker.PostUpdate(MasterJob); // 仮想メッシュ座標書き込み(仮想メッシュトライアングル法線計算)
- MasterJob = RenderMeshWorker.PostUpdate(MasterJob); // レンダーメッシュ座標書き込み(仮想メッシュからレンダーメッシュ座標計算)
- // 書き込みボーン姿勢をローカル姿勢に変換する
- Bone.ConvertWorldToLocal();
- // チームデータ後処理
- Team.PostUpdateTeamData();
- }
- }
- /// <summary>
- /// クロスシミュレーション完了待ち
- /// </summary>
- internal void UpdateCompleteSimulation()
- {
- // マスタージョブ完了待機
- CompleteJob();
- runMasterJob = true;
- #if UNITY_2021_2_OR_NEWER
- // 高速書き込みバッファの作業終了
- Mesh.FinishVertexBuffer();
- #endif
- //Debug.Log($"runMasterJob = true! F:{Time.frameCount}");
- }
- /// <summary>
- /// ボーン姿勢をトランスフォームに書き込む
- /// </summary>
- internal void UpdateWriteBone()
- {
- // ボーン姿勢をトランスフォームに書き出す
- Bone.WriteBoneToTransform(manager.IsDelay ? 1 : 0);
- }
- /// <summary>
- /// メッシュ書き込みの事前判定
- /// </summary>
- internal void MeshCalculation()
- {
- // プロファイラ計測開始
- SamplerCalcMesh.Begin();
- Mesh.ClearWritingList();
- if (Mesh.VirtualMeshCount > 0 && runMasterJob)
- {
- Mesh.MeshCalculation(manager.IsDelay ? 1 : 0);
- }
- // プロファイラ計測終了
- SamplerCalcMesh.End();
- }
- /// <summary>
- /// メッシュ姿勢をメッシュに書き込む
- /// </summary>
- internal void NormalWritingMesh()
- {
- // プロファイラ計測開始
- SamplerWriteMesh.Begin();
- // メッシュへの頂点書き戻し
- if (Mesh.VirtualMeshCount > 0 && runMasterJob)
- {
- Mesh.NormalWriting(manager.IsDelay ? 1 : 0);
- #if UNITY_2021_2_OR_NEWER
- Mesh.FasterWriting(manager.IsDelay ? 1 : 0);
- #endif
- }
- // プロファイラ計測終了
- SamplerWriteMesh.End();
- }
- /// <summary>
- /// 遅延実行時のボーン読み込みと前回のボーン結果の書き込み
- /// </summary>
- internal void UpdateReadWriteBone()
- {
- // 活動チームが1つ以上ある場合のみ更新
- if (Team.ActiveTeamCount > 0)
- {
- // トランスフォーム姿勢の読み込み
- Bone.ReadBoneFromTransform();
- if (runMasterJob)
- {
- // ボーン姿勢をトランスフォームに書き出す
- Bone.WriteBoneToTransform(manager.IsDelay ? 1 : 0);
- }
- }
- }
- /// <summary>
- /// 遅延実行時のみボーンの計算結果を書き込みバッファにコピーする
- /// </summary>
- internal void UpdateSyncBuffer()
- {
- Bone.writeBoneIndexList.SyncBuffer();
- Bone.writeBonePosList.SyncBuffer();
- Bone.writeBoneRotList.SyncBuffer();
- Bone.boneFlagList.SyncBuffer();
- InitJob();
- Bone.CopyBoneBuffer();
- CompleteJob();
- }
- /// <summary>
- /// 遅延実行時のみメッシュの計算結果をスワップする
- /// </summary>
- internal void UpdateSwapBuffer()
- {
- Mesh.renderPosList.SwapBuffer();
- Mesh.renderNormalList.SwapBuffer();
- Mesh.renderTangentList.SwapBuffer();
- Mesh.renderBoneWeightList.SwapBuffer();
- #if UNITY_2021_2_OR_NEWER
- // 高速書き込み用コンピュートバッファをスワップ
- Mesh.renderPosBuffer.Swap();
- Mesh.renderNormalBuffer.Swap();
- #endif
- swapIndex ^= 1;
- // 遅延実行計算済みフラグを立てる
- Mesh.SetDelayedCalculatedFlag();
- }
- //=========================================================================================
- public JobHandle MasterJob
- {
- get
- {
- return jobHandle;
- }
- set
- {
- jobHandle = value;
- }
- }
- /// <summary>
- /// マスタージョブハンドル初期化
- /// </summary>
- public void InitJob()
- {
- jobHandle = default(JobHandle);
- }
- public void ScheduleJob()
- {
- JobHandle.ScheduleBatchedJobs();
- }
- /// <summary>
- /// マスタージョブハンドル完了待機
- /// </summary>
- public void CompleteJob()
- {
- jobHandle.Complete();
- jobHandle = default(JobHandle);
- }
- /// <summary>
- /// 遅延実行時のダブルバッファのフロントインデックス
- /// </summary>
- public int SwapIndex
- {
- get
- {
- return swapIndex;
- }
- }
- //=========================================================================================
- /// <summary>
- /// 物理エンジン更新ループ処理
- /// これは1フレームにステップ回数分呼び出される
- /// 場合によっては1回も呼ばれないフレームも発生するので注意!
- /// </summary>
- /// <param name="updateCount"></param>
- /// <param name="runCount"></param>
- /// <param name="dtime"></param>
- void UpdatePhysics(int updateCount, int runCount, float updatePower, float updateDeltaTime)
- {
- if (Particle.Count == 0)
- return;
- // フォース影響+速度更新
- var job1 = new ForceAndVelocityJob()
- {
- updateDeltaTime = updateDeltaTime,
- updatePower = updatePower,
- runCount = runCount,
- teamDataList = Team.teamDataList.ToJobArray(),
- teamMassList = Team.teamMassList.ToJobArray(),
- teamGravityList = Team.teamGravityList.ToJobArray(),
- teamDragList = Team.teamDragList.ToJobArray(),
- teamDepthInfluenceList = Team.teamDepthInfluenceList.ToJobArray(),
- teamWindInfoList = Team.teamWindInfoList.ToJobArray(),
- //teamMaxVelocityList = Team.teamMaxVelocityList.ToJobArray(),
- //teamDirectionalDampingList = Team.teamDirectionalDampingList.ToJobArray(),
- flagList = Particle.flagList.ToJobArray(),
- teamIdList = Particle.teamIdList.ToJobArray(),
- depthList = Particle.depthList.ToJobArray(),
- snapBasePosList = Particle.snapBasePosList.ToJobArray(),
- snapBaseRotList = Particle.snapBaseRotList.ToJobArray(),
- basePosList = Particle.basePosList.ToJobArray(),
- baseRotList = Particle.baseRotList.ToJobArray(),
- oldBasePosList = Particle.oldBasePosList.ToJobArray(),
- oldBaseRotList = Particle.oldBaseRotList.ToJobArray(),
- nextPosList = Particle.InNextPosList.ToJobArray(),
- nextRotList = Particle.InNextRotList.ToJobArray(),
- oldPosList = Particle.oldPosList.ToJobArray(),
- oldRotList = Particle.oldRotList.ToJobArray(),
- frictionList = Particle.frictionList.ToJobArray(),
- //oldSlowPosList = Particle.oldSlowPosList.ToJobArray(),
- posList = Particle.posList.ToJobArray(),
- rotList = Particle.rotList.ToJobArray(),
- velocityList = Particle.velocityList.ToJobArray(),
- //boneRotList = Bone.boneRotList.ToJobArray(),
- // wind
- windDataList = Wind.windDataList.ToJobArray(),
- // bone
- bonePosList = Bone.bonePosList.ToJobArray(),
- boneRotList = Bone.boneRotList.ToJobArray(),
- };
- jobHandle = job1.Schedule(Particle.Length, 64, jobHandle);
- // 拘束条件解決
- if (constraints != null)
- {
- // 拘束解決反復数分ループ
- for (int i = 0; i < solverIteration; i++)
- {
- foreach (var con in constraints)
- {
- if (con != null /*&& con.enabled*/)
- {
- // 拘束ごとの反復回数
- for (int j = 0; j < con.GetIterationCount(); j++)
- {
- jobHandle = con.SolverConstraint(runCount, updateDeltaTime, updatePower, j, jobHandle);
- }
- }
- }
- }
- }
- // 座標確定
- var job2 = new FixPositionJob()
- {
- updatePower = updatePower,
- updateDeltaTime = updateDeltaTime,
- runCount = runCount,
- teamDataList = Team.teamDataList.ToJobArray(),
- teamMaxVelocityList = Team.teamMaxVelocityList.ToJobArray(),
- flagList = Particle.flagList.ToJobArray(),
- teamIdList = Particle.teamIdList.ToJobArray(),
- depthList = Particle.depthList.ToJobArray(),
- nextPosList = Particle.InNextPosList.ToJobArray(),
- nextRotList = Particle.InNextRotList.ToJobArray(),
- //basePosList = Particle.basePosList.ToJobArray(),
- //baseRotList = Particle.baseRotList.ToJobArray(),
- oldPosList = Particle.oldPosList.ToJobArray(),
- oldRotList = Particle.oldRotList.ToJobArray(),
- frictionList = Particle.frictionList.ToJobArray(),
- velocityList = Particle.velocityList.ToJobArray(),
- rotList = Particle.rotList.ToJobArray(),
- posList = Particle.posList.ToJobArray(),
- localPosList = Particle.localPosList.ToJobArray(),
- collisionNormalList = Particle.collisionNormalList.ToJobArray(),
- staticFrictionList = Particle.staticFrictionList.ToJobArray(),
- };
- jobHandle = job2.Schedule(Particle.Length, 64, jobHandle);
- }
- [BurstCompile]
- struct ForceAndVelocityJob : IJobParallelFor
- {
- public float updateDeltaTime;
- public float updatePower;
- public int runCount;
- // team
- [Unity.Collections.ReadOnly]
- public NativeArray<PhysicsManagerTeamData.TeamData> teamDataList;
- [Unity.Collections.ReadOnly]
- public NativeArray<CurveParam> teamMassList;
- [Unity.Collections.ReadOnly]
- public NativeArray<CurveParam> teamGravityList;
- [Unity.Collections.ReadOnly]
- public NativeArray<CurveParam> teamDragList;
- [Unity.Collections.ReadOnly]
- public NativeArray<CurveParam> teamDepthInfluenceList;
- [Unity.Collections.ReadOnly]
- public NativeArray<PhysicsManagerTeamData.WindInfo> teamWindInfoList;
- //[Unity.Collections.ReadOnly]
- //public NativeArray<CurveParam> teamMaxVelocityList;
- //[Unity.Collections.ReadOnly]
- //public NativeArray<CurveParam> teamDirectionalDampingList;
- // particle
- public NativeArray<PhysicsManagerParticleData.ParticleFlag> flagList;
- [Unity.Collections.ReadOnly]
- public NativeArray<int> teamIdList;
- [Unity.Collections.ReadOnly]
- public NativeArray<float> depthList;
- [Unity.Collections.ReadOnly]
- public NativeArray<float3> snapBasePosList;
- [Unity.Collections.ReadOnly]
- public NativeArray<quaternion> snapBaseRotList;
- [Unity.Collections.WriteOnly]
- public NativeArray<float3> basePosList;
- [Unity.Collections.WriteOnly]
- public NativeArray<quaternion> baseRotList;
- [Unity.Collections.ReadOnly]
- public NativeArray<float3> oldBasePosList;
- [Unity.Collections.ReadOnly]
- public NativeArray<quaternion> oldBaseRotList;
- public NativeArray<float3> nextPosList;
- public NativeArray<quaternion> nextRotList;
- public NativeArray<float> frictionList;
- [Unity.Collections.WriteOnly]
- public NativeArray<float3> posList;
- [Unity.Collections.WriteOnly]
- public NativeArray<quaternion> rotList;
- [Unity.Collections.ReadOnly]
- public NativeArray<float3> oldPosList;
- [Unity.Collections.ReadOnly]
- public NativeArray<quaternion> oldRotList;
- [Unity.Collections.ReadOnly]
- public NativeArray<float3> velocityList;
- // wind
- [Unity.Collections.ReadOnly]
- public NativeArray<PhysicsManagerWindData.WindData> windDataList;
- // bone
- [Unity.Collections.ReadOnly]
- public NativeArray<float3> bonePosList;
- [Unity.Collections.ReadOnly]
- public NativeArray<quaternion> boneRotList;
- // パーティクルごと
- public void Execute(int index)
- {
- var flag = flagList[index];
- if (flag.IsValid() == false)
- return;
- // チームデータ
- int teamId = teamIdList[index];
- var teamData = teamDataList[teamId];
- // ここからは更新がある場合のみ実行(グローバルチームは除く)
- if (teamId != 0 && teamData.IsUpdate(runCount) == false)
- return;
- var oldpos = oldPosList[index];
- var oldrot = oldRotList[index];
- float3 nextPos = oldpos;
- quaternion nextRot = oldrot;
- var friction = frictionList[index];
- // 基準姿勢のステップ補間(v1.11.1)
- var oldBasePos = oldBasePosList[index];
- var oldBaseRot = oldBaseRotList[index];
- var snapBasePos = snapBasePosList[index];
- var snapBaseRot = snapBaseRotList[index];
- float stime = teamData.startTime + updateDeltaTime * runCount;
- float oldtime = teamData.startTime - updateDeltaTime;
- float interval = teamData.time - oldtime;
- float step = interval >= 1e-06f ? math.saturate((stime - oldtime) / interval) : 0.0f;
- float3 basePos = math.lerp(oldBasePos, snapBasePos, step);
- quaternion baseRot = math.slerp(oldBaseRot, snapBaseRot, step);
- baseRot = math.normalize(baseRot); // 必要
- basePosList[index] = basePos;
- baseRotList[index] = baseRot;
- if (flag.IsFixed())
- {
- // キネマティックパーティクル
- nextPos = basePos;
- nextRot = baseRot;
- // nextPos/nextRotが1ステップ前の姿勢
- var oldNextPos = nextPosList[index];
- var oldNextRot = nextRotList[index];
- // 前回の姿勢をoldpos/rotとしてposList/rotListに格納する
- if (flag.IsCollider() && teamId == 0)
- {
- // グローバルコライダー
- // 移動量と回転量に制限をかける(1.7.5)
- // 制限をかけないと高速移動/回転時に遠く離れたパーティクルが押し出されてしまう問題が発生する。
- oldpos = MathUtility.ClampDistance(nextPos, oldNextPos, Define.Compute.GlobalColliderMaxMoveDistance);
- oldrot = MathUtility.ClampAngle(nextRot, oldNextRot, math.radians(Define.Compute.GlobalColliderMaxRotationAngle));
- }
- else
- {
- oldpos = oldNextPos;
- oldrot = oldNextRot;
- }
- #if false
- // nextPos/nextRotが1ステップ前の姿勢
- var oldNextPos = nextPosList[index];
- var oldNextRot = nextRotList[index];
- // oldpos/rotが前フレームの最終計算姿勢
- // oldpos/rot から BasePos/Rot に step で補間して現在姿勢とする
- float stime = teamData.startTime + updateDeltaTime * runCount;
- float oldtime = teamData.startTime - updateDeltaTime;
- float interval = teamData.time - oldtime;
- float step = interval >= 1e-06f ? math.saturate((stime - oldtime) / interval) : 0.0f;
- nextPos = math.lerp(oldpos, basePosList[index], step);
- nextRot = math.slerp(oldrot, baseRotList[index], step);
- nextRot = math.normalize(nextRot);
- // 前回の姿勢をoldpos/rotとしてposList/rotListに格納する
- if (flag.IsCollider() && teamId == 0)
- {
- // グローバルコライダー
- // 移動量と回転量に制限をかける(1.7.5)
- // 制限をかけないと高速移動/回転時に遠く離れたパーティクルが押し出されてしまう問題が発生する。
- oldpos = MathUtility.ClampDistance(nextPos, oldNextPos, Define.Compute.GlobalColliderMaxMoveDistance);
- oldrot = MathUtility.ClampAngle(nextRot, oldNextRot, math.radians(Define.Compute.GlobalColliderMaxRotationAngle));
- }
- else
- {
- oldpos = oldNextPos;
- oldrot = oldNextRot;
- }
- #endif
- // debug
- //nextPos = basePosList[index];
- //nextRot = baseRotList[index];
- }
- else
- {
- // 動的パーティクル
- var depth = depthList[index];
- //var maxVelocity = teamMaxVelocityList[teamId].Evaluate(depth);
- var drag = teamDragList[teamId].Evaluate(depth);
- var gravity = teamGravityList[teamId].Evaluate(depth);
- var gravityDirection = teamData.gravityDirection;
- var mass = teamMassList[teamId].Evaluate(depth);
- var depthInfluence = teamDepthInfluenceList[teamId].Evaluate(depth);
- var velocity = velocityList[index];
- // チームスケール倍率
- //maxVelocity *= teamData.scaleRatio;
- // massは主に伸縮を中心に調整されるので、フォース適用時は少し調整する
- //mass = (mass - 1.0f) * teamData.forceMassInfluence + 1.0f;
- // 安定化用の速度ウエイト
- velocity *= teamData.velocityWeight;
- // 最大速度
- //velocity = MathUtility.ClampVector(velocity, 0.0f, maxVelocity);
- // 空気抵抗(90ups基準)
- // 重力に影響させたくないので先に計算する(※通常はforce適用後に行うのが一般的)
- velocity *= math.pow(1.0f - drag, updatePower);
- // フォース
- // フォースは空気抵抗を無視して加算する
- float3 force = 0;
- // 重力(質量に関係なく一定)
- // (最後に質量で割るためここでは質量をかける)
- force += gravityDirection * (gravity * mass);
- // 外部フォース
- if (runCount == 0)
- {
- float3 exForce = 0;
- switch (teamData.forceMode)
- {
- case PhysicsManagerTeamData.ForceMode.VelocityAdd:
- exForce += teamData.impactForce;
- break;
- case PhysicsManagerTeamData.ForceMode.VelocityAddWithoutMass:
- exForce += teamData.impactForce * mass;
- break;
- case PhysicsManagerTeamData.ForceMode.VelocityChange:
- exForce += teamData.impactForce;
- velocity = 0;
- break;
- case PhysicsManagerTeamData.ForceMode.VelocityChangeWithoutMass:
- exForce += teamData.impactForce * mass;
- velocity = 0;
- break;
- }
- // 外力
- exForce += teamData.externalForce;
- // 風(重量に関係なく一定)
- if (teamData.IsFlag(PhysicsManagerTeamData.Flag_Wind))
- exForce += Wind(teamId, teamData, snapBasePos) * mass;
- // 外力深さ影響率
- exForce *= depthInfluence;
- force += exForce;
- }
- // 外力チームスケール倍率
- force *= teamData.scaleRatio;
- // 速度計算(質量で割る)
- velocity += (force / mass) * updateDeltaTime;
- // 速度を理想位置に反映させる
- nextPos = oldpos + velocity * updateDeltaTime;
- }
- // 予定座標更新 ==============================================================
- // 摩擦減衰
- friction = friction * Define.Compute.FrictionDampingRate;
- frictionList[index] = friction;
- //frictionList[index] = 0;
- // 移動前の姿勢
- posList[index] = oldpos;
- rotList[index] = oldrot;
- // 予測位置
- nextPosList[index] = nextPos;
- nextRotList[index] = nextRot;
- }
- /// <summary>
- /// 風の計算
- /// </summary>
- /// <param name="teamId"></param>
- /// <param name="teamData"></param>
- /// <param name="pos"></param>
- /// <returns></returns>
- float3 Wind(int teamId, in PhysicsManagerTeamData.TeamData teamData, in float3 pos)
- {
- var windInfo = teamWindInfoList[teamId];
- // ノイズ起点
- // ここをずらすと他のパーティクルと非同期になっていく
- float sync = math.lerp(3.0f, 0.1f, teamData.forceWindSynchronization);
- var noiseBasePos = new float2(pos.x, pos.z) * sync;
- float3 externalForce = 0;
- for (int i = 0; i < 4; i++)
- {
- int windId = windInfo.windDataIndexList[i];
- if (windId < 0)
- continue;
- var windData = windDataList[windId];
- float3 windForce = PhysicsManagerWindData.CalcWindForce(
- teamData.time,
- noiseBasePos,
- windInfo.windDirectionList[i],
- windInfo.windMainList[i],
- windData.turbulence,
- windData.frequency,
- teamData.forceWindRandomScale
- );
- externalForce += windForce;
- }
- // チームの風の影響率
- externalForce *= teamData.forceWindInfluence;
- return externalForce;
- }
- }
- [BurstCompile]
- struct FixPositionJob : IJobParallelFor
- {
- public float updatePower;
- public float updateDeltaTime;
- public int runCount;
- // チーム
- [Unity.Collections.ReadOnly]
- public NativeArray<PhysicsManagerTeamData.TeamData> teamDataList;
- [Unity.Collections.ReadOnly]
- public NativeArray<CurveParam> teamMaxVelocityList;
- // パーティクルごと
- [Unity.Collections.ReadOnly]
- public NativeArray<PhysicsManagerParticleData.ParticleFlag> flagList;
- [Unity.Collections.ReadOnly]
- public NativeArray<int> teamIdList;
- [Unity.Collections.ReadOnly]
- public NativeArray<float> depthList;
- [Unity.Collections.ReadOnly]
- public NativeArray<float3> nextPosList;
- [Unity.Collections.ReadOnly]
- public NativeArray<quaternion> nextRotList;
- [Unity.Collections.ReadOnly]
- public NativeArray<float> frictionList;
- //[Unity.Collections.ReadOnly]
- //public NativeArray<float3> basePosList;
- //[Unity.Collections.ReadOnly]
- //public NativeArray<quaternion> baseRotList;
- public NativeArray<float3> velocityList;
- [Unity.Collections.WriteOnly]
- public NativeArray<quaternion> rotList;
- public NativeArray<float3> oldPosList;
- public NativeArray<quaternion> oldRotList;
- public NativeArray<float3> posList;
- [Unity.Collections.WriteOnly]
- public NativeArray<float3> localPosList;
- [Unity.Collections.ReadOnly]
- public NativeArray<float3> collisionNormalList;
- public NativeArray<float> staticFrictionList;
- // パーティクルごと
- public void Execute(int index)
- {
- var flag = flagList[index];
- if (flag.IsValid() == false)
- return;
- // チームデータ
- int teamId = teamIdList[index];
- var teamData = teamDataList[teamId];
- // ここからは更新がある場合のみ実行
- if (teamData.IsUpdate(runCount) == false)
- return;
- // 速度更新(m/s)
- if (flag.IsFixed() == false)
- {
- // 移動パーティクルのみ
- var nextPos = nextPosList[index];
- var nextRot = nextRotList[index];
- nextRot = math.normalize(nextRot); // 回転蓄積で精度が落ちていくので正規化しておく
- float3 velocity = 0;
- // posListには移動影響を考慮した最終座標が入っている
- var pos = posList[index];
- var oldpos = oldPosList[index];
- // コライダー接触情報
- float friction = frictionList[index];
- var cn = collisionNormalList[index];
- bool isCollision = math.lengthsq(cn) > Define.Compute.Epsilon; // 接触の有無
- #if true
- // 静止摩擦
- float staticFriction = staticFrictionList[index];
- if (isCollision && friction > 0.0f)
- {
- // 接線方向の移動速度から計算する
- var v = nextPos - oldpos;
- v = v - MathUtility.Project(v, cn);
- float tangentVelocity = math.length(v) / updateDeltaTime; // 接線方向の移動速度
- float stopVelocity = teamData.staticFriction * teamData.scaleRatio; // 静止速度
- if (tangentVelocity < stopVelocity)
- {
- staticFriction = math.saturate(staticFriction + 0.02f * updatePower); // 係数増加
- }
- else
- {
- // 接線速度に応じて係数を減少
- var vel = tangentVelocity - stopVelocity;
- var value = math.max(vel / 0.2f, 0.05f) * updatePower;
- staticFriction = math.saturate(staticFriction - value);
- }
- // 現在の静止摩擦係数を使い接線方向の移動にブレーキをかける
- v *= staticFriction;
- nextPos -= v;
- pos -= v;
- }
- else
- {
- staticFriction = math.saturate(staticFriction - 0.05f * updatePower); // 係数減少
- }
- staticFrictionList[index] = staticFriction;
- #endif
- // 速度更新(m/s)
- velocity = (nextPos - pos) / updateDeltaTime;
- velocity *= teamData.velocityWeight; // 安定化用の速度ウエイト
- #if true
- // 動摩擦による速度減衰(衝突面との角度が大きいほど減衰が強くなる)
- if (friction > Define.Compute.Epsilon && isCollision && math.lengthsq(velocity) >= Define.Compute.Epsilon)
- {
- var dot = math.dot(cn, math.normalize(velocity));
- dot = 0.5f + 0.5f * dot; // 1.0(front) - 0.5(side) - 0.0(back)
- dot *= dot; // サイドを強めに
- dot = 1.0f - dot; // 0.0(front) - 0.75(side) - 1.0(back)
- velocity -= velocity * (dot * math.saturate(friction * teamData.dynamicFriction * 1.5f)); // 以前と同程度になるように補正
- }
- #else
- // 摩擦による速度減衰(旧)
- friction *= teamData.friction; // チームごとの摩擦係数
- velocity *= math.pow(1.0f - math.saturate(friction), updatePower);
- #endif
- // 最大速度
- var depth = depthList[index];
- var maxVelocity = teamMaxVelocityList[teamId].Evaluate(depth);
- maxVelocity *= teamData.scaleRatio; // チームスケール
- velocity = MathUtility.ClampVector(velocity, 0.0f, maxVelocity);
- // 実際の移動速度(localPosに格納)
- var realVelocity = (nextPos - oldpos) / updateDeltaTime;
- realVelocity = MathUtility.ClampVector(realVelocity, 0.0f, maxVelocity); // 最大速度は考慮する
- localPosList[index] = realVelocity;
- // 書き戻し
- velocityList[index] = velocity;
- oldPosList[index] = nextPos;
- oldRotList[index] = nextRot;
- }
- }
- }
- //=========================================================================================
- /// <summary>
- /// 物理演算後処理
- /// </summary>
- /// <param name="updateDeltaTime"></param>
- void PostUpdatePhysics(float updateDeltaTime)
- {
- if (Particle.Count == 0)
- return;
- var job = new PostUpdatePhysicsJob()
- {
- updateDeltaTime = updateDeltaTime,
- teamDataList = Team.teamDataList.ToJobArray(),
- flagList = Particle.flagList.ToJobArray(),
- teamIdList = Particle.teamIdList.ToJobArray(),
- snapBasePosList = Particle.snapBasePosList.ToJobArray(),
- snapBaseRotList = Particle.snapBaseRotList.ToJobArray(),
- basePosList = Particle.basePosList.ToJobArray(),
- baseRotList = Particle.baseRotList.ToJobArray(),
- oldBasePosList = Particle.oldBasePosList.ToJobArray(),
- oldBaseRotList = Particle.oldBaseRotList.ToJobArray(),
- oldPosList = Particle.oldPosList.ToJobArray(),
- oldRotList = Particle.oldRotList.ToJobArray(),
- velocityList = Particle.velocityList.ToJobArray(),
- localPosList = Particle.localPosList.ToJobArray(),
- posList = Particle.posList.ToJobArray(),
- rotList = Particle.rotList.ToJobArray(),
- nextPosList = Particle.InNextPosList.ToJobArray(),
- nextRotList = Particle.InNextRotList.ToJobArray(),
- oldSlowPosList = Particle.oldSlowPosList.ToJobArray(),
- };
- jobHandle = job.Schedule(Particle.Length, 64, jobHandle);
- }
- [BurstCompile]
- struct PostUpdatePhysicsJob : IJobParallelFor
- {
- public float updateDeltaTime;
- // チーム
- [Unity.Collections.ReadOnly]
- public NativeArray<PhysicsManagerTeamData.TeamData> teamDataList;
- // パーティクルごと
- [Unity.Collections.ReadOnly]
- public NativeArray<PhysicsManagerParticleData.ParticleFlag> flagList;
- [Unity.Collections.ReadOnly]
- public NativeArray<int> teamIdList;
- // パーティクルごと
- [Unity.Collections.ReadOnly]
- public NativeArray<float3> snapBasePosList;
- [Unity.Collections.ReadOnly]
- public NativeArray<quaternion> snapBaseRotList;
- [Unity.Collections.ReadOnly]
- public NativeArray<float3> basePosList;
- [Unity.Collections.ReadOnly]
- public NativeArray<quaternion> baseRotList;
- [Unity.Collections.WriteOnly]
- public NativeArray<float3> oldBasePosList;
- [Unity.Collections.WriteOnly]
- public NativeArray<quaternion> oldBaseRotList;
- [Unity.Collections.ReadOnly]
- public NativeArray<float3> velocityList;
- [Unity.Collections.ReadOnly]
- public NativeArray<float3> localPosList;
- public NativeArray<float3> oldPosList;
- public NativeArray<quaternion> oldRotList;
- [Unity.Collections.WriteOnly]
- public NativeArray<float3> posList;
- [Unity.Collections.WriteOnly]
- public NativeArray<quaternion> rotList;
- [Unity.Collections.ReadOnly]
- public NativeArray<float3> nextPosList;
- [Unity.Collections.ReadOnly]
- public NativeArray<quaternion> nextRotList;
- public NativeArray<float3> oldSlowPosList;
- // パーティクルごと
- public void Execute(int index)
- {
- var flag = flagList[index];
- if (flag.IsValid() == false)
- return;
- // チームデータ
- int teamId = teamIdList[index];
- var teamData = teamDataList[teamId];
- float3 viewPos = 0;
- quaternion viewRot = quaternion.identity;
- //var basePos = basePosList[index];
- //var baseRot = baseRotList[index];
- var snapBasePos = snapBasePosList[index];
- var snapBaseRot = snapBaseRotList[index];
- if (flag.IsFixed() == false)
- {
- // 未来予測
- // 1フレーム前の表示位置と将来の予測位置を、現在のフレーム位置で線形補間する
- //var velocity = velocityList[index]; // 従来
- //var velocity = posList[index]; // 実際の速度(どうもこっちだとカクつき?があるぞ)
- var velocity = localPosList[index]; // 実際の速度
- var futurePos = oldPosList[index] + velocity * updateDeltaTime;
- var oldViewPos = oldSlowPosList[index];
- float addTime = teamData.addTime;
- float oldTime = teamData.time - addTime;
- float futureTime = teamData.time + (updateDeltaTime - teamData.nowTime);
- float interval = futureTime - oldTime;
- //Debug.Log($"addTime:{teamData.addTime} interval:{interval}");
- if (addTime > 1e-06f && interval > 1e-06f)
- {
- float ratio = teamData.addTime / interval;
- viewPos = math.lerp(oldViewPos, futurePos, ratio);
- }
- else
- {
- viewPos = oldViewPos;
- }
- viewRot = oldRotList[index];
- viewRot = math.normalize(viewRot); // 回転蓄積で精度が落ちていくので正規化しておく
- #if false
- // 未来予測を切る
- futurePos = oldPosList[index];
- viewPos = futurePos;
- #endif
- oldSlowPosList[index] = viewPos;
- }
- else
- {
- // 固定パーティクルの表示位置は常にベース位置
- //viewPos = basePos;
- //viewRot = baseRot;
- viewPos = snapBasePos;
- viewRot = snapBaseRot;
- // 固定パーティクルは今回のbasePosを記録する(更新時のみ)
- if (teamData.IsRunning())
- {
- // 最終計算位置を格納する
- oldPosList[index] = nextPosList[index];
- oldRotList[index] = nextRotList[index];
- }
- }
- // ブレンド
- if (teamData.blendRatio < 0.99f)
- {
- //viewPos = math.lerp(basePos, viewPos, teamData.blendRatio);
- //viewRot = math.slerp(baseRot, viewRot, teamData.blendRatio);
- viewPos = math.lerp(snapBasePos, viewPos, teamData.blendRatio);
- viewRot = math.slerp(snapBaseRot, viewRot, teamData.blendRatio);
- viewRot = math.normalize(viewRot); // 回転蓄積で精度が落ちていくので正規化しておく
- }
- // test
- //viewPos = snapBasePos;
- //viewRot = snapBaseRot;
- // 表示位置
- posList[index] = viewPos;
- rotList[index] = viewRot;
- // 1つ前の基準位置を記録
- if (teamData.IsRunning())
- {
- oldBasePosList[index] = basePosList[index];
- oldBaseRotList[index] = baseRotList[index];
- }
- }
- }
- //=========================================================================================
- /// <summary>
- /// ワーカーウォームアップ処理実行
- /// </summary>
- void WarmupWorker()
- {
- if (workers == null || workers.Count == 0)
- return;
- for (int i = 0; i < workers.Count; i++)
- {
- var worker = workers[i];
- worker.Warmup();
- }
- }
- }
- }
|