Unity 2021.3.0f1でQuest開発している時に遭遇したUIが消える不具合について

エンジニアの岡村です。

先週うぃすきーさんから障害対処の記事が出ていたので、自分も重大度としては低いですが、社内開発中に発生した不具合と、それが解決するまでの過程を作業記録として書いてみることにしました。何かの参考になれば幸いです。

結論

Unity 2021.3.0f1 は、XR Interaction Toolkit + Meta Quest2で不具合があるので、 これらの機能を使う場合はUnity 2021.3.2f1以上にアップデートすることをお勧めします。

不具合発生

少し前に、Meta Quest2向けのUIの実装を行っていました。元となるUIが既に存在していたので、それをVR空間内で触れるようにNew Input SystemやXR Interaction Toolkitの繋ぎこみをしていたのですが、一通り組み立てて動作テストをしたとき、奇妙な現象に見舞われました。

スクロールビューをポインターで操作すると、トリガーを離した瞬間にUIの表示が消滅してしまい、二度と戻ってきません。

必ず発生するわけではないのですが、仮に発生した場合UI操作が出来なくなってしまうので、修正が必要です。まずは繋いだInputSystem --> XR Interaction Toolkitの辺りに原因があるのではないかと仮定して調査を始めました。

再現

UIの不具合を検証するにはUnity Editor上で状態を確認するのが一番なので、Editor上で該当のUIを操作してみたのですが、Editor上では再現しませんでした。

仕方ないので、ログを仕込んでQuest実機でテストします。今回の症状がスクロールビューの内容が消えているという事なので、まずはScrollViewの子要素(Content)の座標をログに出してみました。

02-10 02:02:30.036  9193  9216 I Unity   : [ScrollPositionChecker] Scroll Position = (0.00, NaN, 0.00)
02-10 02:02:30.036  9193  9216 I Unity   : UnityEngine.StackTraceUtility:ExtractStackTrace () (at /Users/bokken/buildslave/unity/build/Runtime/Export/Scripting/StackTrace.cs:37)
02-10 02:02:30.036  9193  9216 I Unity   : UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[])
02-10 02:02:30.036  9193  9216 I Unity   : UnityEngine.Logger:Log (UnityEngine.LogType,object)
02-10 02:02:30.036  9193  9216 I Unity   : UnityEngine.Debug:Log (object)
02-10 02:02:30.036  9193  9216 I Unity   : ScrollPositionChecker:Update () (at C:/Users/Sokuhatiku/Documents/Projects/ScrollBugTest/Assets/ScrollPositionChecker.cs:20)
02-10 02:02:30.036  9193  9216 I Unity   :

Logcatで取得したログを読んでみると、YにNaNが入っています。何かのルートでNaNが入ってしまっているようです。

原因特定

NaNの出元を辿ります。Transformに座標を入れている箇所を探し、それぞれに別のIDを振ってログを仕込み、どこの代入でNaNが出ているのかを特定します。すると、ScrollRectから発行されている、スクロールポジションが変化した時に発行される、onValueChangedイベントからNaNが渡されている事がわかりました。

docs.unity3d.com

しかも、一度NaNになってしまうと、Transform Positionなどを手動で修正してもScrollrect側から永遠にNaNが帰ってくるようになってしまっていました。どうやらScrollRect内におかしな値が残ってしまっているようです。

解決策の検索

こうなるとScrollRectを利用している側ではどうしようもありませんので、Unityの不具合であると決め打ち、解決策を探すことにします。

Issue Trackerを検索してみたところ、それらしいIssueがHitしました。

issuetracker.unity3d.com

XR Interaction Toolkitを使い、Quest実機上でスクロールビューをドラッグするとコンテンツが消えるという症状が完全に一致しています。

IssueにUnity公式の返信が付いているので読んでみると、

  • 原因は2つ
    • Quest実機にてunscaledDeltaTimeに0が入る事がある
    • unscaledDeltaTimeに0が入る事がScrollRect側で考慮されていない
  • 両方ともUnity 2021.3.2f1で修正済み

とのことです。

検証

たまたま他の検証でUnity 2021.3.16f1を入れていたので、試してみました(本当は最小限のアップデートに止めるべき)。

プロジェクトをUnity2021.3.16f1で開き直し、Androidビルドを実行、Quest2実機で確認してみたところ、問題なくスクロールが行えるようになっていました!

これにて不具合の原因と、修正方法が判明しました。ここからはUnityのアップデートによる副作用を検証するフェーズが始まります……

おまけ:どのような仕組みでNaNが発生しているのかソースコードを調べてみた

UnityのUIなど一部分はソースコードが公開されているので、中を覗いてみます。

以前はbitbucketで公開されていましたが、Unity 2019.2以降はUnity本体の Data\Resources\PackageManager\BuiltInPackages\com.unity.ugui にあるからそれを見てね、という形に変わったようです。

github.com

差分を覗いてみると、 LateUpdate 内でunscaledDeltaTimeがゼロ超であることをチェックするコードが追加されていました。

下の方で除算が行われているので、恐らくここがゼロ除算になり、NaNが生まれてしまっていたのでしょう。

unscaledDeltaTimeに0が入ることがある根本的な理由に関しては……おそらくエンジン側のソースを見ないと分からなさそうです。