Loading...

【Unity】WebGL対応した際に発生したエラーまとめ【WebGL】

Unity
マイケル
マイケル
みなさんこんにちは!
マイケルです!
エレキベア
エレキベア
こんにちクマ〜〜〜
マイケル
マイケル
今日は開発中のオセロゲームをWebGL対応した際に
発生したエラーと対処内容
についてまとめていくぜ!
エレキベア
エレキベア
WebGL対応については確か以前もまとめていたクマね
マイケル
マイケル
そう、前対応した時はビルドが通るようにすればすんなり上手くいったんだけど、
今回はそれに加えていくつか対応しないといけない箇所があったからまとめてみたんだ!
エレキベア
エレキベア
今回は少しやっかいだったクマね
マイケル
マイケル
それではさっそく見ていこう!
スポンサーリンク

発生したエラー内容

マイケル
マイケル
対応した内容としては
・URPでのビルド時エラー
・UTSがWebGL非対応で表示がおかしい
・マルチスレッド処理が機能しない

の3つになります!
エレキベア
エレキベア
結構対応する箇所が出てきたクマね
マイケル
マイケル
なお、今回使用したUnityのバージョンは
2021.3.1f になります!
バージョンの差異によってはエラー内容が違ったり、解消されていたりする場合もあるためご注意ください!

URPでビルドしたらエラー

マイケル
マイケル
一つ目はURPプロジェクトとしてWebGLビルドした際に発生した下記のエラーです。
Shader error in 'Hidden/kMotion/CameraMotionVectors': SV_VertexID semantic is not supported on GLES 2.0 at line 11 (on gles)
マイケル
マイケル
こちらはエラー文言通り、Shaderの一部がGLES2.0(WebGL1)をサポートしていないために発生しているエラーになります。
エレキベア
エレキベア
今は確かWebGL2が主流でWebGL1は非推奨になっていた気がするクマね
マイケル
マイケル
今回は Build Settings – Other Settings から
Graphics APIs の Auto Graphics APIのチェックを外してWebGL1を削除 することで解決しました!
ScreenShot 2022 10 10 16 39 27↑Graphics APIsからWebGL1を削除
エレキベア
エレキベア
簡単な対応クマ〜〜

UTSがWebGL非対応

マイケル
マイケル
さあこれでビルドも通ったし一見落着!
・・・と思っていたところ、ゲーム画面を見て異変に気がつきました。
ScreenShot 2022 10 10 16 58 31
マイケル
マイケル
キャラクター表示がバグっている・・・・
エレキベア
エレキベア
これはひどいクマ・・・
マイケル
マイケル
調べたところ、今回使用させていただいた
UTS(UnityChanToonShader)はWebGLには非対応 らしく、その影響でバグってしまっているようでした。

GitHub – UnityChanToonShaderVer2_Project

エレキベア
エレキベア
確かにTargetPlatdformに載っていないクマ・・・
マイケル
マイケル
しかし開発終盤だったこともあり今からシェーダを変えたくないなという気持ちもありました・・・。
どうにかできないか見ていたところ、どうやら表示がおかしいのはアウトラインのみのようだったため、今回はアウトラインのみ無効にすることで対処できました。
ScreenShot 2022 10 10 17 05 36↑アウトラインを無効にすることで解決
エレキベア
エレキベア
それだけで済んでよかったクマ・・・
マイケル
マイケル
今回は助かったけど、ちゃんとプラットフォームのサポートは見て決めないといけないなと痛感しました・・・

マルチスレッド処理が動かない

マイケル
マイケル
さあ今度こそバッチリだぜ!
そう思いながらオセロをプレイしてみたところ・・・
ScreenShot 2022 10 10 23 02 23↑止まっている・・・
マイケル
マイケル
今度はオセロを開始した途端にAIが何も反応しないという事象が発生しました・・・
エレキベア
エレキベア
これでは何もできないクマ・・・
マイケル
マイケル
これを調べた結果、WebGLではマルチスレッドが使用できないために、
スレッドを切り替えて実行している処理は全く動作しない ということが分かりました。
        /// <summary>
        /// モンテカルロ探索処理
        /// </summary>
        private async UniTask<StoneIndex> SearchMonteCarloStoneTask()
        {
            await UniTask.SwitchToThreadPool(); // 時間がかかるため別スレッドで実行
            var gameRate = StoneCalculator.GetGameRate(StoneStates);
            var result = AIAlgorithm.SearchMonteCarloStone(StoneStates, MyStoneState, (int) (150 * gameRate));
            await UniTask.SwitchToMainThread();
            return result;
        }
↑モンテカルロ等の重い処理はスレッドを切り替えていた
エレキベア
エレキベア
ここに来て高い壁がクマ・・・
マイケル
マイケル
元々重かったからスレッドを分けたわけなので、シングルスレッドに戻すとそれはそれでカクカクしてひどいです。
つまりマルチスレッド以外の方法で重い処理を対処する必要があります。
エレキベア
エレキベア
むむ・・・どうすればいいクマか・・・
マイケル
マイケル
今回は手を決めるまでの時間を犠牲にして、
ある程度の処理を行なった後に1フレーム待機させることで対処しました。
マイケル
マイケル
具体的には下記のように対処しています。
モンテカルロ処理の中で指定回数ゲームを行なって勝利した回数を求める関数になるのですが、一定回数石を置いたら1フレーム待機させるよう、実装しました。

GitHub – unity-reversi-game-scripts/masarito617 – AIAlgorithm.cs

        /// <summary>
        /// 指定回数ゲームを行い、勝利した回数を返却する
        /// </summary>
        private static async UniTask<int> GetPlayGameWinCountAsync(StoneState[,] stoneStates, StoneState checkStoneState, StoneIndex checkStoneIndex, int playCount, bool isSaveRunOption, CancellationToken token)
        {
            // 別スレッドでも動作するようSystemの乱数を使用
            var random = new Random();
            // 石を置いた数(処理負荷対策チェック用)
            var checkPutCount = 0;
            // 勝利した回数をカウントする
            var winCount = 0;
            for (var i = 0; i < playCount; i++)
            {
                // 勝敗が決まるまでゲームを行う
                var activeStoneState = checkStoneState;
                var activeStoneStates = StoneCalculator.GetPutStoneState(stoneStates, activeStoneState, checkStoneIndex.X, checkStoneIndex.Z);
                while (true)
                {
                    // 手番を交代して置くことが可能なストーン状態を取得
                    activeStoneState = StoneCalculator.GetReverseStoneState(activeStoneState);
                    var canPutStonesIndex = StoneCalculator.GetAllCanPutStonesIndex(activeStoneStates, activeStoneState);
                    if (canPutStonesIndex == null || canPutStonesIndex.Count == 0)
                    {
                        // 置けなくなったらゲーム終了
                        break;
                    }
                    // ランダムで置く
                    var randomIndex = random.Next(0, canPutStonesIndex.Count);
                    var selectStoneIndex = canPutStonesIndex[randomIndex];
                    activeStoneStates = StoneCalculator.GetPutStoneState(activeStoneStates, activeStoneState, selectStoneIndex.X, selectStoneIndex.Z);
                    // 処理負荷対策:一定回数ごとに1フレーム待つ
                    if (isSaveRunOption)
                    {
                        checkPutCount++;
                        if (checkPutCount >= 200) // この数値を上げると1フレームの処理負荷が上がる
                        {
                            checkPutCount = 0; // クリア
                            await UniTask.DelayFrame(1, cancellationToken: token);
                        }
                    }
                }
                // 勝利判定を行う
                if (StoneCalculator.GetWinStoneState(activeStoneStates) == checkStoneState)
                {
                    winCount++;
                }
            }
            return winCount;
        }
↑一定回数石を置くごとに1フレーム待つ
マイケル
マイケル
このようにすることで1フレーム内で行う処理が減り、
結果として描画負荷を軽減させる
ことができます。
マイケル
マイケル
厳密には置いた回数より時間を計測した方が効率がいいとは思いますが、
今回はこれでヨシとします・・・!!
エレキベア
エレキベア
面倒臭かったクマね
マイケル
マイケル
以上、3つの対策で無事WebGLでも動作するようになりました!
エレキベア
エレキベア
やったクマ〜〜〜

おわりに

マイケル
マイケル
というわけで今回はWebGL対応した際のエラー対応でした!
どうだったかな??
エレキベア
エレキベア
前回はすんなりいったクマが今回は中々大変だったクマね
マイケル
マイケル
まあスレッド周りは勉強になったけど大変だったね・・・
マイケル
マイケル
みなさんもWebGL対応する際には描画周りとスレッドには気を付けましょう!!
それでは今日はこの辺で!アデューー!!!
エレキベア
エレキベア
クマ〜〜〜〜

【Unity】WebGL対応した際に発生したエラーまとめ【WebGL】〜完〜

Unity
スポンサーリンク
この記事をシェアしよう!
フォローお待ちしています!
都会のエレキベア

コメント