From 935afcb80dce5043985a126b8e9ad0c2fc68e7d9 Mon Sep 17 00:00:00 2001 From: Takayuki Matsuoka Date: Wed, 7 Sep 2022 17:51:10 +0900 Subject: [PATCH] Add new pseudo method NextFrameIfTimedOut to RuntimeOnlyAwaitCaller This change adds (pseudo) method RuntimeOnlyAwaitCaller.NextFrameIfTimedOut() which invokes NextFrame() if given time is elapsed. Otherwise, it does nothing. We'll be able to utilize this (pseudo) method to ease possible cause of spikes. For example: ---- public class VRMImporterContext : ImporterContext { protected override async Task OnLoadHierarchy(IAwaitCaller awaitCaller, ...) { ... var blendShapeList = VRM.blendShapeMaster.blendShapeGroups; if (blendShapeList != null && blendShapeList.Count > 0) { foreach (var x in blendShapeList) { await awaitCaller.NextFrameIfTimeout(); BlendShapeAvatar.Clips.Add(await LoadBlendShapeBind(awaitCaller, x, transformMeshTable)); } } ... } } ---- Note that this change doesn't add NextFrameIfTimeout() to IAwaitCaller to avoid breaking change. This limitation introduces extra (maybe unnecessarily) complexity. --- .../AwaitCaller/RuntimeOnlyAwaitCaller.cs | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/Assets/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyAwaitCaller.cs b/Assets/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyAwaitCaller.cs index 23cc7b592..83665d7a0 100644 --- a/Assets/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyAwaitCaller.cs +++ b/Assets/VRMShaders/GLTF/IO/Runtime/AwaitCaller/RuntimeOnlyAwaitCaller.cs @@ -32,5 +32,51 @@ namespace VRMShaders { return Task.Run(action); } + + /// + /// 指定した時間が経過している場合のみ、NextFrame() を使って1フレーム待つ + /// + /// タイムアウト時間(ミリ秒単位) + /// タイムアウト時はNextFrame()を呼び出す。そうではない場合、Task.CompletedTaskを返す + public Task NextFrameIfTimedOut_(float timeOutInMilliseconds = 1f) + { + if (!CheckTimeOut(timeOutInMilliseconds)) + { + return Task.CompletedTask; + } + _lastBaseTime = 0f; + return NextFrame(); + } + + private bool CheckTimeOut(float timeOutInMilliseconds) + { + float t = UnityEngine.Time.realtimeSinceStartup; + if (_lastBaseTime == 0f) + { + // Reset base time + _lastBaseTime = t; + } + return (t - _lastBaseTime) >= timeOutInMilliseconds * (1f / 1000f); + } + + private float _lastBaseTime; } -} \ No newline at end of file + + internal static class RuntimeOnlyAwaitCallerHelper + { + /// + /// 指定した時間が経過している場合のみ、NextFrame() を使って1フレーム待つ + /// + /// IAwaitCallerのインスタンス + /// タイムアウト時間(ミリ秒単位) + /// タイムアウト時はNextFrame()を呼び出す。そうではない場合、Task.CompletedTaskを返す + internal static Task NextFrameIfTimedOut(this IAwaitCaller iAwaitCaller, float timeOutInMilliseconds) + { + if (iAwaitCaller is RuntimeOnlyAwaitCaller runtimeOnlyAwaitCaller) + { + return runtimeOnlyAwaitCaller.NextFrameIfTimedOut_(timeOutInMilliseconds); + } + return Task.CompletedTask; + } + } +}