20210413のUnityに関する記事は3件です。

Unity IAPの中を調べる【iOS】

仕事でUnity IAP周りの挙動で不具合が発生し原因究明のためいろいろ調べていたので自らのメモとしてまとめます。 といっても主にiOS周りが中心でそれ以外のプラットフォームは全く見ていないです(Androidはちょっと見た) 尚、今回調べたのはUnityIAP2.2.7です。 UnityPurchasingの初期化フロー 基本形としてUnityPurchasing.InitializeにIStoreListenerを実装したクラスと商品情報を設定したConfigurationBuilderを渡す。 ほとんどのアプリでは以下のような初期化から始まると思います。 public class PurchasingTest : MonoBehaviour, IStoreListener { void Start(){ StandardPurchasingModule module = StandardPurchasingModule.Instance(); builder = ConfigurationBuilder.Instance(module); UnityPurchasing.Initialize(this, builder); } } StandardPurchasingModule、ConfigurationBuilderは一旦置いておくとして UnityPurchasing.Initializeが完了するとOnStoreInitializedが呼ばれるわけだけど、この間にPending状態の課金アイテムを処理したり実はいろいろな処理が呼ばれている。 全体像としてはこんな感じです いろいろと複雑なものの、要は現在のplatformに合わせてStoreインスタンスが生成され、そのStoreからNativeへアクセスするインスタンスに対して処理を実行するような感じのようです。 iOSの場合はネイティブからのコールバックなどのハンドリングはAppleStoreImpl、ネイティブへのアクセスはiOSStoreBindingsというのを使っていました。 シーケンス図にすると初期化はこんな感じです。 なお、OnInitializedで取得するIStoreControllerとは実体はPurchasingManagerインスタンスなので、ILSpyしてIStoreControllerの挙動を確認したい場合はPurchasingManagerクラスを見てみましょう。 FinishTransactionの扱いについて ConfirmPendingPurchaseなどをアプリ側で呼び出す、もしくはProcessPurchaseでCompleteを返した場合、その場でFinishTransactionが呼ばれます。 (より厳密に言えばProcessPurchaseでPurchaseProcessingResult.Completeが返ってきたタイミングでConfirmPendingPurchaseが呼ばれ、ConfirmPendingPurchaseメソッド内でFinishTransactionが呼ばれている) このFinishTransactionが呼ばれた時点で、SKPaymentQueueからも該当のtransactionはfinishTransactionされ、消えるのですが、このSKPaymentQueue.finishTransactionは呼ばれたら直ちに処理されるわけではないようです。 (個人的にここがハマりポイントでした...)     - (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions が呼ばれるまでは削除されないので、 例えばConfirmPendingPurchaseした直後にUnityPurchasingを再度初期化しようとしたりすると、既に処理が終わっているtransactionがまだSKPaymentQueue.defaultQueue内に残っているのでPending状態になっていると見なされ、再度FinishTransactionしようとしてエラーが発生します。 (DuplicateTransactionみたいな内容のエラーが出る) という個人的なハマリポイントでした。 Androidではこの問題は発生しなかったのでちゃんと見てません。 (ちらっと見たらiOSより複雑怪奇だった) その他 ConfigurationBuilder、PurchasingModuleの初期化周り PurchasingManager周りの関係性
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VRChatのワールドの描画負荷を下げる

概要 ここでは描画負荷を下げるための手法の一つである「オクリュージョンカリング」について解説します。VRChatのワールド制作向けに書いてはいますが、VRChat以外でも使用できる手法です。 ワールドの容量を減らす手法ではないのでそこだけは間違えないでください。 環境 ・Unity2018.4.20f1を使用 ・VRCSDK2-2020.11.16.12.43_Publicを使用 オクリュージョンカリングとは あるオブジェクトが他のオブジェクトに隠されてカメラに映らないときに、隠れているオブジェクトのレンダリングを無効にする機能です。 「壁の後ろにあるものはどうせ見えないんだから、描画しないで処理を軽くしちゃおー」って感じ。 ただし、なんでもかんでもオクリュージョンカリングを適応してしまうと、逆にオクリュージョンカリングの処理で重くなり、本末転倒になってしまうので適切に設定しましょう。 1. オクリュージョンカリングについて 1-1. 前準備 カメラの設定 カメラのOcclusion Cullingにチェックが入っているか確認しましょう。デフォルトで入っているので恐らく大丈夫なはずです。 オクリュージョンカリングを行うウィンドウ Window → Rendering → Occulusion Culling でオクリュージョンカリングの設定を行うウィンドウを出すことができます。 1-2. オクリュージョンカリングの設定について まず初めに遮蔽物となるオブジェクトと遮蔽物に隠れると描画されなくなるオブジェクトの設定をそれぞれ行います。 設定は各オブジェクトのInspectorの右上のStatic設定で行います。 その中のOccluder StaticとOccludee Staticの2つがオクリュージョンカリングの設定に関わってきます。 両方とも似たような名前で分かりにくいと思うのでそれぞれ説明していきます。 Occluder Static 他のオブジェクトを遮蔽するオブジェクト。 「隠す方」 Occludee Static 他のオブジェクトから遮蔽されるオブジェクト。 「隠される方」 1-3. どんなものに設定するのか ・動くオブジェクト(動的オブジェクト) 共に設定しない ・家の壁や塀 Occluder Static・Occludee Staticともに設定する。 ・家具や小物類 Occludee Staticのみを設定する。 2. オクリュージョンカリングを実践する 2-1. ベイク 以上のことを元にオブジェクトにOccluder StaticとOccludee Staticの設定を行いましょう。地道にポチポチと。 設定が終わったら早速オクリュージョンカリングを適用させていきます。 Occulusionのウィンドウを開き、右下にあるBakeを押しましょう。規模にもよりますが遅くても5~10秒ほどでベイクが完了します。データ容量自体は多くても80KB辺りになると思います。 せっかく設定してもベイクをしないと意味がないので忘れないようにしましょう。 2-2. それぞれのタブの説明 Occulusionのウィンドウにそれぞれ「Object」「Bake」「Visualization」の3つのタブがあると思います。それぞれ説明していきます。 Objectタブ 選択中のオブジェクトのOccluder Staticと・ccludee Staticを行う場所です。 先ほど説明したようにInspectorのStatic設定でも同様のことが行えます。 Bakeタブ オクリュージョンカリングのBake設定を行う場所。 ・Smallest Occluder この値よりも大きいオブジェクトが遮蔽物(Occluder)として見なされます ・Smallest Hole この値よりも小さな隙間は視線を通さないと見なされ、奥にあるオブジェクトは遮蔽されます。 ・Backface Threshold 値を100未満に設定するとオブジェクトの見えない裏側のメッシュの描画を省略して、データを小さくします。 Visualizationタブ シーンでオクリュージョンカリングの状態を確認する場所。 このタブを選択した状態でカメラを動かしてみると…… (赤色が壁/青色が遮蔽されるオブジェクト) ただし、カメラがこの青いセルの範囲外にでるとオクリュージョンカリングが効かなくってしまいます。 そういうときにはOcculusion Areaというものを使います。 2-3. Occulusion Area まず、Create → CreateEmpty で空のオブジェクトを作成し、AddComponentからOcculusion Areaを追加します。 そして範囲を設定します。 この状態のまま再びベイク。すると… 先ほどは範囲外だった遠い位置からでもオクリュージョンカリングが効いてることが分かるかと思います。(分かりづらいけれど) 説明は以上となります。 参考記事 ・UnityDocumention
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityにおけるオブジェクト破棄のタイミング

概要 シングルトンオブジェクトのデストラクタでゲーム設定の保存処理を行うようにしたところ、エディタ終了時にクラッシュする現象が発生しました。原因を調査すると、Unityエディタではプレイ中に生成されたオブジェクトが少し変わったタイミングで破棄されていました。 結論 Unityエディタでプレイ中に生成されたオブジェクトは次回のプレイ開始時及びエディタの終了時に破棄されます。直感的にはプレイ停止時に破棄されていそうですが、次のプレイ、もしくはエディタの終了時までオブジェクトは保持されているようです。 実験 以下のコードでデストラクタの実行タイミングを確かめます。 SingletonDestractor.cs using UnityEngine; public class SingletonDestractor { static SingletonDestractor instance; static public SingletonDestractor Instance { get { if(instance == null) { instance = new SingletonDestractor(); } return instance; } } public void Call() { Debug.Log("Call"); } ~SingletonDestractor() { Debug.Log("Destract"); } } デストラクタでDebug.Logを呼び出すシングルトンオブジェクトです。 以下のコンポーネントでこれを生成します。 Caller.cs using UnityEngine; public class Caller : MonoBehaviour { void Start() { SingletonDestractor.Instance.Call(); } } 実行、停止したところ、コンソールは以下のようになりました。 デストラクタ内で呼び出しているはずのDebug.Log("Destract");が実行されていません。 この状態で再度実行、停止したところ、コンソールは以下のようになりました。 このことから、前のプレイ時のSingletonDestractorオブジェクトが今回のプレイ開始時に破棄されたことが分かります。間が2秒ほど空いていることから、恐らくプレイボタンを押してから実行が開始されるまでの間に破棄されていると思われます。 また、しばらく別の作業をしていた所、以下のようになりました。 時間経過、もしくは何らかのタイミングでも破棄されるようです。いずれにせよデストラクタの実行タイミングはコントロールしづらく、使用は避けたほうがいいでしょう。 解決策 オブジェクト破棄時に何か処理をしたい場合は、MonoBehaviourを継承して、OnDestroy関数を使うべきです。具体的には以下のようにします。 SingletonDestractor.cs using UnityEngine; public class SingletonDestractor : MonoBehaviour { static SingletonDestractor instance; static public SingletonDestractor Instance { get { if(instance == null) { var go = new GameObject(); instance = go.AddComponent<SingletonDestractor>(); DontDestroyOnLoad(go); } return instance; } } public void Call() { Debug.Log("Call"); } void OnDestroy() { Debug.Log("Destract"); } } このようにすると、先程のシングルトンクラスと同様に扱うことができ、なおかつゲームオブジェクトの破棄はプレイ終了時に行われるので、意図したタイミングでデストラクタ相当の処理を行うことができます。実際にこちらのクラスでプレイ、停止したところ、コンソールは以下のようになりました。 正しく終了時に破棄が行われていることが確認できます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む