123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700 |
- // Magica Cloth.
- // Copyright (c) MagicaSoft, 2020-2022.
- // https://magicasoft.jp
- using System;
- using System.Linq;
- using System.Collections.Generic;
- #if MAGICACLOTH_ECS
- using Unity.Entities;
- #endif
- using UnityEngine;
- using UnityEngine.LowLevel;
- namespace MagicaCloth
- {
- /// <summary>
- /// MagicaCloth物理マネージャ
- /// </summary>
- [HelpURL("https://magicasoft.jp/magica-cloth-physics-manager/")]
- public partial class MagicaPhysicsManager : CreateSingleton<MagicaPhysicsManager>
- {
- /// <summary>
- /// 更新管理
- /// </summary>
- [SerializeField]
- UpdateTimeManager updateTime = new UpdateTimeManager();
- /// <summary>
- /// パーティクルデータ
- /// </summary>
- PhysicsManagerParticleData particle = new PhysicsManagerParticleData();
- /// <summary>
- /// トランスフォームデータ
- /// </summary>
- PhysicsManagerBoneData bone = new PhysicsManagerBoneData();
- /// <summary>
- /// メッシュデータ
- /// </summary>
- PhysicsManagerMeshData mesh = new PhysicsManagerMeshData();
- /// <summary>
- /// チームデータ
- /// </summary>
- PhysicsManagerTeamData team = new PhysicsManagerTeamData();
- /// <summary>
- /// 風データ
- /// </summary>
- PhysicsManagerWindData wind = new PhysicsManagerWindData();
- /// <summary>
- /// 全コンポーネントデータ
- /// </summary>
- PhysicsManagerComponent component = new PhysicsManagerComponent();
- /// <summary>
- /// 物理計算処理
- /// </summary>
- PhysicsManagerCompute compute = new PhysicsManagerCompute();
- /// <summary>
- /// Unity2021.2以降でのGetVertexBuffer()による高速書き込みの利用
- /// 実行中は変更できない
- /// </summary>
- [SerializeField]
- private bool useFasterWrite = true;
- // コンピュートシェーダー
- private ComputeShader meshWriter = null;
- //=========================================================================================
- /// <summary>
- /// シミュレーション計算前イベント
- /// Simulation pre-calculation event.
- /// </summary>
- public PhysicsManagerPreUpdateEvent OnPreUpdate = new PhysicsManagerPreUpdateEvent();
- /// <summary>
- /// シミュレーション計算後イベント
- /// Simulation post-calculation event.
- /// </summary>
- public PhysicsManagerPostUpdateEvent OnPostUpdate = new PhysicsManagerPostUpdateEvent();
- //=========================================================================================
- /// <summary>
- /// 遅延実行の有無
- /// ランタイムで変更できるようにバッファリング
- /// </summary>
- private bool useDelay = false;
- /// <summary>
- /// Update()でのPlayerLoopチェック完了フラグ
- /// </summary>
- private bool updatePlayerLoop = false;
- /// <summary>
- /// マネージャ全体のアクティブフラグ
- /// </summary>
- private bool isActive = true;
- //=========================================================================================
- public UpdateTimeManager UpdateTime
- {
- get
- {
- return updateTime;
- }
- }
- public PhysicsManagerParticleData Particle
- {
- get
- {
- particle.SetParent(this);
- return particle;
- }
- }
- public PhysicsManagerBoneData Bone
- {
- get
- {
- bone.SetParent(this);
- return bone;
- }
- }
- public PhysicsManagerMeshData Mesh
- {
- get
- {
- mesh.SetParent(this);
- return mesh;
- }
- }
- public PhysicsManagerTeamData Team
- {
- get
- {
- team.SetParent(this);
- return team;
- }
- }
- public PhysicsManagerWindData Wind
- {
- get
- {
- wind.SetParent(this);
- return wind;
- }
- }
- public PhysicsManagerComponent Component
- {
- get
- {
- component.SetParent(this);
- return component;
- }
- }
- public PhysicsManagerCompute Compute
- {
- get
- {
- compute.SetParent(this);
- return compute;
- }
- }
- public bool IsDelay
- {
- get
- {
- return useDelay;
- }
- }
- public bool IsActive
- {
- get
- {
- return isActive;
- }
- set
- {
- // アクティブはコンポーネントのenableフラグで行う
- this.enabled = value;
- }
- }
- public bool IsFasterWrite
- {
- get
- {
- if (useFasterWrite)
- {
- #if UNITY_2021_2_OR_NEWER
- if (MeshWriterShader != null)
- {
- if (MeshWriterShader.IsSupported(0) && MeshWriterShader.IsSupported(1))
- {
- return true;
- }
- }
- #endif
- }
- return false;
- }
- }
- internal ComputeShader MeshWriterShader
- {
- get
- {
- if (meshWriter == null)
- {
- meshWriter = (ComputeShader)Resources.Load("MeshWriter");
- }
- return meshWriter;
- }
- }
- //=========================================================================================
- protected override void Awake()
- {
- base.Awake();
- }
- /// <summary>
- /// 初期化
- /// </summary>
- protected override void InitSingleton()
- {
- Component.Create();
- Particle.Create();
- Bone.Create();
- Mesh.Create();
- Team.Create();
- Wind.Create();
- Compute.Create();
- }
- /// <summary>
- /// 2つ目の破棄されるマネージャの通知
- /// </summary>
- /// <param name="duplicate"></param>
- protected override void DuplicateDetection(MagicaPhysicsManager duplicate)
- {
- // 設定をコピーする
- UpdateMode = duplicate.UpdateMode;
- UpdatePerSeccond = duplicate.UpdatePerSeccond;
- FuturePredictionRate = duplicate.FuturePredictionRate;
- }
- protected void OnEnable()
- {
- if (isActive == false)
- {
- isActive = true;
- Component.UpdateComponentStatus();
- }
- }
- protected void OnDisable()
- {
- if (isActive == true)
- {
- isActive = false;
- Component.UpdateComponentStatus();
- }
- }
- private void Update()
- {
- // Unity2019.3以降の場合はUpdate時に一度カスタムループの登録チェックを行う
- // すでに登録されていればスルーし、登録されていなければ再登録する
- // これは他のアセットによりPlayerLoopが書き換えられてしまった場合の対策です
- if (updatePlayerLoop == false)
- {
- //Debug.Log("Update check!!");
- InitCustomGameLoop();
- updatePlayerLoop = true;
- }
- }
- private void FixedUpdate()
- {
- if (isActive)
- {
- UpdateTime.AddFixedUpdateCount();
- }
- }
- /// <summary>
- /// 破棄
- /// </summary>
- protected override void OnDestroy()
- {
- Compute.Dispose();
- Wind.Dispose();
- Team.Dispose();
- Mesh.Dispose();
- Bone.Dispose();
- Particle.Dispose();
- Component.Dispose();
- base.OnDestroy();
- }
- //=========================================================================================
- /// <summary>
- /// EarlyUpdateの後
- /// </summary>
- private void AfterEarlyUpdate()
- {
- //Debug.Log($"After Early Update! F:{Time.frameCount}");
- // フレーム開始時に行うチーム更新
- Team.EarlyUpdateTeamAlways();
- }
- //private void BeforeFixedUpdate()
- //{
- // //Debug.Log("Before Fixed Update!" + Time.frameCount);
- // // シミュレーションに必要なボーンの状態をもとに戻す(更新モード = UnityPhysics)
- // if (Team.ActiveTeamCount > 0 && Team.PhysicsUpdateCount > 0)
- // {
- // Compute.InitJob();
- // Compute.UpdateRestoreBone(PhysicsTeam.TeamUpdateMode.UnityPhysics);
- // Compute.CompleteJob();
- // }
- //}
- private void AfterFixedUpdate()
- {
- //Debug.Log("After Fixed Update!" + Time.frameCount);
- // シミュレーションに必要なボーンの状態をもとに戻す(更新モード = UnityPhysics)
- if (Team.ActiveTeamCount > 0 && Team.PhysicsUpdateCount > 0)
- {
- Compute.InitJob();
- Compute.UpdateRestoreBone(PhysicsTeam.TeamUpdateMode.UnityPhysics);
- Compute.CompleteJob();
- }
- }
- /// <summary>
- /// Update()後の更新
- /// </summary>
- private void AfterUpdate()
- {
- //Debug.Log("After Update!" + Time.frameCount);
- // シミュレーションに必要なボーンの状態をもとに戻す(更新モード = Normal)
- if (Team.ActiveTeamCount > 0 && Team.NormalUpdateCount > 0)
- {
- Compute.InitJob();
- Compute.UpdateRestoreBone(PhysicsTeam.TeamUpdateMode.Normal);
- Compute.CompleteJob();
- }
- }
- /// <summary>
- /// LateUpdate()前の更新
- /// </summary>
- //private void BeforeLateUpdate()
- //{
- // //Debug.Log("Before Late Update!" + Time.frameCount);
- //}
- /// <summary>
- /// LateUpdate()後の更新
- /// </summary>
- private void AfterLateUpdate()
- {
- //Debug.Log("After Late Update!" + Time.frameCount);
- //Debug.Log("dtime:" + Time.deltaTime + " smooth:" + Time.smoothDeltaTime);
- // 遅延実行の切り替え判定
- if (useDelay != UpdateTime.IsDelay)
- {
- if (useDelay == false)
- {
- // 結果の保持
- Compute.UpdateSwapBuffer();
- Compute.UpdateSyncBuffer();
- }
- useDelay = UpdateTime.IsDelay;
- }
- // パーティクルコンポーネントのデータ更新処理
- Component.DataUpdateParticleComponent();
- if (useDelay == false)
- {
- // 即時
- OnPreUpdate.Invoke();
- Compute.UpdateTeamAlways();
- Compute.InitJob();
- Compute.UpdateReadBone();
- Compute.UpdateStartSimulation(updateTime);
- Compute.UpdateWriteBone();
- Compute.MeshCalculation();
- Compute.UpdateCompleteSimulation();
- Compute.NormalWritingMesh();
- OnPostUpdate.Invoke();
- }
- }
- /// <summary>
- /// PostLateUpdate.ScriptRunDelayedDynamicFrameRateの後
- /// LateUpdate()やアセットバンドルロード完了コールバックでクロスコンポーネントをインスタンス化すると、
- /// Start()が少し遅れてPostLateUpdateのScriptRunDelayedDynamicFrameRateで呼ばれることになる。
- /// 遅延実行時にこの処理が入ると、すでにクロスシミュレーションのジョブが開始されているため、
- /// Start()の初期化処理などでNativeリストにアクセスすると例外が発生してしまう。
- /// 従って遅延実行時はクロスコンポーネントのStart()が完了するScriptRunDelayedDynamicFrameRate
- /// の後にシミュレーションを開始するようにする。(v1.5.1)
- /// </summary>
- private void PostLateUpdate()
- {
- //Debug.Log("Post Late Update!" + Time.frameCount);
- if (useDelay)
- {
- // 遅延実行
- OnPreUpdate.Invoke();
- Compute.UpdateTeamAlways();
- Compute.InitJob();
- Compute.UpdateReadWriteBone();
- Compute.UpdateStartSimulation(updateTime);
- Compute.ScheduleJob();
- Compute.MeshCalculation();
- Compute.NormalWritingMesh(); // 前回の結果をメッシュに反映
- //Debug.Log($"Delay Job! F:{Time.frameCount}");
- }
- }
- /// <summary>
- /// レンダリング完了後の更新
- /// </summary>
- private void AfterRendering()
- {
- //Debug.Log($"After Rendering Update! F:{Time.frameCount}");
- if (useDelay)
- {
- // 遅延実行
- // シミュレーション終了待機
- Compute.UpdateCompleteSimulation();
- // 結果の保持
- Compute.UpdateSwapBuffer();
- Compute.UpdateSyncBuffer();
- OnPostUpdate.Invoke();
- }
- // シミュレーションに必要なボーンの状態をもとに戻す
- //Compute.InitJob();
- //Compute.UpdateRestoreBone();
- //Compute.CompleteJob();
- // FixedUpdateCountクリア
- UpdateTime.ResetFixedUpdateCount();
- }
- //=========================================================================================
- /// <summary>
- /// Reload Domain 対策
- /// </summary>
- [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
- private static void Init()
- {
- InitMember();
- }
- /// <summary>
- /// カスタム更新ループ登録
- /// </summary>
- [RuntimeInitializeOnLoadMethod()]
- public static void InitCustomGameLoop()
- {
- //Debug.Log("PhysicsManager.InitCustomGameLoop()");
- PlayerLoopSystem playerLoop = PlayerLoop.GetCurrentPlayerLoop();
- // すでに設定されているならばスルー
- if (CheckRegist(ref playerLoop))
- {
- //Debug.Log("Skip!!");
- return;
- }
- // MagicaCloth用PlayerLoopを追加
- SetCustomGameLoop(ref playerLoop);
- PlayerLoop.SetPlayerLoop(playerLoop);
- }
- /// <summary>
- /// playerLoopにMagicaClothで必要なCustomPlayerLoopを追加します
- /// </summary>
- /// <param name="playerLoop"></param>
- public static void SetCustomGameLoop(ref PlayerLoopSystem playerLoop)
- {
- #if false
- // debug
- foreach (var header in playerLoop.subSystemList)
- {
- Debug.LogFormat("------{0}------", header.type.Name);
- foreach (var subSystem in header.subSystemList)
- {
- Debug.LogFormat("{0}.{1}", header.type.Name, subSystem.type.Name);
- }
- }
- #endif
- PlayerLoopSystem afterEarlyUpdate = new PlayerLoopSystem()
- {
- type = typeof(MagicaPhysicsManager),
- updateDelegate = () =>
- {
- if (IsInstance())
- {
- Instance.AfterEarlyUpdate();
- }
- }
- };
- //PlayerLoopSystem beforeFixedUpdate = new PlayerLoopSystem()
- //{
- // type = typeof(MagicaPhysicsManager),
- // updateDelegate = () =>
- // {
- // if (IsInstance())
- // {
- // Instance.BeforeFixedUpdate();
- // }
- // }
- //};
- PlayerLoopSystem afterFixedUpdate = new PlayerLoopSystem()
- {
- type = typeof(MagicaPhysicsManager),
- updateDelegate = () =>
- {
- if (IsInstance())
- {
- Instance.AfterFixedUpdate();
- }
- }
- };
- PlayerLoopSystem afterUpdate = new PlayerLoopSystem()
- {
- type = typeof(MagicaPhysicsManager),
- updateDelegate = () =>
- {
- if (IsInstance())
- {
- Instance.AfterUpdate();
- }
- }
- };
- //PlayerLoopSystem beforeLateUpdate = new PlayerLoopSystem()
- //{
- // type = typeof(MagicaPhysicsManager),
- // updateDelegate = () =>
- // {
- // if (IsInstance())
- // {
- // Instance.BeforeLateUpdate();
- // }
- // }
- //};
- PlayerLoopSystem afterLateUpdate = new PlayerLoopSystem()
- {
- type = typeof(MagicaPhysicsManager),
- updateDelegate = () =>
- {
- if (IsInstance())
- {
- Instance.AfterLateUpdate();
- }
- }
- };
- PlayerLoopSystem postLateUpdate = new PlayerLoopSystem()
- {
- type = typeof(MagicaPhysicsManager),
- updateDelegate = () =>
- {
- if (IsInstance())
- {
- Instance.PostLateUpdate();
- }
- }
- };
- PlayerLoopSystem afterRendering = new PlayerLoopSystem()
- {
- type = typeof(MagicaPhysicsManager),
- updateDelegate = () =>
- {
- if (IsInstance())
- {
- Instance.AfterRendering();
- }
- }
- };
- int sysIndex = 0;
- int index = 0;
- // early update
- sysIndex = Array.FindIndex(playerLoop.subSystemList, (s) => s.type.Name == "EarlyUpdate");
- PlayerLoopSystem earlyUpdateSystem = playerLoop.subSystemList[sysIndex];
- var earlyUpdateSubsystemList = new List<PlayerLoopSystem>(earlyUpdateSystem.subSystemList);
- earlyUpdateSubsystemList.Add(afterEarlyUpdate);
- earlyUpdateSystem.subSystemList = earlyUpdateSubsystemList.ToArray();
- playerLoop.subSystemList[sysIndex] = earlyUpdateSystem;
- // fixed udpate
- //sysIndex = Array.FindIndex(playerLoop.subSystemList, (s) => s.type.Name == "FixedUpdate");
- //PlayerLoopSystem fixedUpdateSystem = playerLoop.subSystemList[sysIndex];
- //var fixedUpdateSubsystemList = new List<PlayerLoopSystem>(fixedUpdateSystem.subSystemList);
- //fixedUpdateSubsystemList.Insert(0, beforeFixedUpdate);
- //fixedUpdateSystem.subSystemList = fixedUpdateSubsystemList.ToArray();
- //playerLoop.subSystemList[sysIndex] = fixedUpdateSystem;
- // after fixed update
- sysIndex = Array.FindIndex(playerLoop.subSystemList, (s) => s.type.Name == "FixedUpdate");
- PlayerLoopSystem fixedUpdateSystem = playerLoop.subSystemList[sysIndex];
- var fixedUpdateSubsystemList = new List<PlayerLoopSystem>(fixedUpdateSystem.subSystemList);
- index = fixedUpdateSubsystemList.FindIndex(h => h.type.Name.Contains("ScriptRunBehaviourFixedUpdate"));
- fixedUpdateSubsystemList.Insert(index + 1, afterFixedUpdate); // FixedUpdate() after
- fixedUpdateSystem.subSystemList = fixedUpdateSubsystemList.ToArray();
- playerLoop.subSystemList[sysIndex] = fixedUpdateSystem;
- // update
- sysIndex = Array.FindIndex(playerLoop.subSystemList, (s) => s.type.Name == "Update");
- PlayerLoopSystem updateSystem = playerLoop.subSystemList[sysIndex];
- var updateSubsystemList = new List<PlayerLoopSystem>(updateSystem.subSystemList);
- index = updateSubsystemList.FindIndex(h => h.type.Name.Contains("ScriptRunDelayedDynamicFrameRate"));
- updateSubsystemList.Insert(index + 1, afterUpdate); // Update() after
- updateSystem.subSystemList = updateSubsystemList.ToArray();
- playerLoop.subSystemList[sysIndex] = updateSystem;
- // late update
- sysIndex = Array.FindIndex(playerLoop.subSystemList, (s) => s.type.Name == "PreLateUpdate");
- PlayerLoopSystem lateUpdateSystem = playerLoop.subSystemList[sysIndex];
- var lateUpdateSubsystemList = new List<PlayerLoopSystem>(lateUpdateSystem.subSystemList);
- index = lateUpdateSubsystemList.FindIndex(h => h.type.Name.Contains("ScriptRunBehaviourLateUpdate"));
- //lateUpdateSubsystemList.Insert(index, beforeLateUpdate); // LateUpdate() before
- //lateUpdateSubsystemList.Insert(index + 2, afterLateUpdate); // LateUpdate() after
- lateUpdateSubsystemList.Insert(index + 1, afterLateUpdate); // LateUpdate() after
- lateUpdateSystem.subSystemList = lateUpdateSubsystemList.ToArray();
- playerLoop.subSystemList[sysIndex] = lateUpdateSystem;
- // post late update
- sysIndex = Array.FindIndex(playerLoop.subSystemList, (s) => s.type.Name == "PostLateUpdate");
- PlayerLoopSystem postLateUpdateSystem = playerLoop.subSystemList[sysIndex];
- var postLateUpdateSubsystemList = new List<PlayerLoopSystem>(postLateUpdateSystem.subSystemList);
- index = postLateUpdateSubsystemList.FindIndex(h => h.type.Name.Contains("ScriptRunDelayedDynamicFrameRate"));
- postLateUpdateSubsystemList.Insert(index + 1, postLateUpdate); // postLateUpdate()
- postLateUpdateSystem.subSystemList = postLateUpdateSubsystemList.ToArray();
- playerLoop.subSystemList[sysIndex] = postLateUpdateSystem;
- // rendering
- sysIndex = Array.FindIndex(playerLoop.subSystemList, (s) => s.type.Name == "PostLateUpdate");
- PlayerLoopSystem postLateSystem = playerLoop.subSystemList[sysIndex];
- var postLateSubsystemList = new List<PlayerLoopSystem>(postLateSystem.subSystemList);
- index = postLateSubsystemList.FindIndex(h => h.type.Name.Contains("FinishFrameRendering"));
- postLateSubsystemList.Insert(index + 1, afterRendering); // rendering after
- postLateSystem.subSystemList = postLateSubsystemList.ToArray();
- playerLoop.subSystemList[sysIndex] = postLateSystem;
- }
- /// <summary>
- /// MagicaClothのカスタムループが登録されているかチェックする
- /// </summary>
- /// <param name="playerLoop"></param>
- /// <returns></returns>
- private static bool CheckRegist(ref PlayerLoopSystem playerLoop)
- {
- var t = typeof(MagicaPhysicsManager);
- foreach (var subloop in playerLoop.subSystemList)
- {
- if (subloop.subSystemList != null && subloop.subSystemList.Any(x => x.type == t))
- {
- return true;
- }
- }
- return false;
- }
- }
- }
|