【Unity】UI開発 おまけ
前回の記事に入り切らなかった最適化の内容です。
Image
Raycast Target
タッチ制御なしの場合はチェックを外す、無駄な計算を省けます。
Cull Transparent Mesh
チェックすると、α値が0以下の時に頂点データを転送しません。
Animator
Animatorは常にCanvasを更新するため、一時的なUI演出などに使うと良いです。 こちらのUnity公式ページも言及しています。
Shader
前回の最適化でも少し触れましたが、左右や上下に揺れる周期性のある動きはシェーダで表現するのも手です。GPU処理のためCanvasの更新も走らないです。
こういう表現とか面白いですよね。 baba-s.hatenablog.com
【Unity】UI開発 Part 4 最適化編
UI開発シリーズ、最後は最適化です。CanvasのBatch処理、Overdrawを例に上げた後、Profilerによる確認方法をまとめてます。
Canvas
全てのUIはCanvas配下になります。何も考えず大量にUIを配置するとパフォーマンスを低下させます。
Batch処理
最も効果的なのはBatch処理です。これはザックリ言うとCPUがGPUに描画の命令を出す時に、必要な情報(Material, Texture)をまとめる事で命令数を減らしCPUの負荷を軽減するというものです。
という訳で、以下にBatch処理を有効にする条件・注意点をまとめました。
同じTextureを参照
Batch処理を有効にするために、個別TextureをAtlas化して一つのTextureにまとめてにます。
kan-kikuchi.hatenablog.com同じMaterialを参照
Textureと同様にまとめれるものは同じMaterialを参照します。 UIのレイヤー表示に注意
MaterialA, MaterialB を参照するImageを下図のように交互に重ねて表示する場合、Batch処理が効かないです。
この場合はMaterialをまとめるか、重ねない表示にするかです。
同じCanvasに配置
uGUIのBatch処理はCanvas単位で実行されます。前述でまとめたTexture,Materialが他のCanvasを跨がないよう調整します。
Canvas単位の表示制御に注意
UIをCanvas単位で表示・非表示する時はCanvasを無効にしてください。Canvas を無効化すると頂点データを維持するため、次回有効時に頂点バッファの更新せずにすむためです。
Canvasの親子関係に注意
ただし、Canvasに親子関係を設定している場合、子Canvasの無効化時に親Canvasは更新されてしまいます。動かさない
各UIを更新すると都度Batch処理が実行されます。これは中々に重たい処理でUI生成時など限定的なタイミングならまだ良いですが毎フレーム走る場合は問題になります。
Canvas単位でBatch処理を実行するため、動かしていない他UIも含めて影響します。
Canvasを分割する
とはいえ毎フレーム更新するUIは出てきます。対処法の1つは更新用Canvasに分割します。
こうすれば更新用CanvasのみBatch処理が走り、影響範囲を最小限に抑えれます。
ただし、Canvasを分割し過ぎると今度はBatch処理の意味がなくなるので、負荷を計測して分割数を決めていきます。
Shaderで動かす
もう1つの対処法は周期性(左右・上下振動)のある表現をシェーダで実装します。GPU側で処理するためCanvasのBatch処理は走らないです。
baba-s.hatenablog.com
Overdraw
半透明のUIを大量に重ねると余計な描画処理が発生するため、なるべく半透明UIを重ねないよう気をつける必要があります。Overdrawは下図のようにSceneビューで確認できます。明るい所ほどポリゴンが重なっており負荷が高いです。
Profiler
最後にUnityのProfilerを使い、ここまでの最適化の効果を確認する方法です。
Window > Analysis > Profiler で開きます。
CPU Usage
Batch処理の発生回数・負荷を確認できます。下図の検索フォームに "Canvas.BuildBatch" と入力すると確認できます。
UI/UI Details
Batch処理失敗の原因をBatch Break Reasonで確認できます。
UISystemPreviewWindow
UI/UI Details の右下に表示されるウインドウです。Batch範囲とOverdrawを確認できます。
composite overdraw を選択すると対象UIの overdraw を確認できます。
まとめ
Canvasを中心に最適化方法をまとめました。Batch処理・OverdrawはUIに限らず3Dでも注意すべき内容です。UnityのProfilerはすぐに起動できて詳細情報も確認しやすく優秀です。
これらを活用して普段からパフォーマンスを意識して開発をしたいですね。終盤でバタバタしながら対応するのは大変ですし・・^_^;
参考
https://unity3d.com/jp/how-to/unity-ui-optimization-tips
Unityでパフォーマンスの良いUIを作る為のTips | PPT
【Unity】UI開発 Part 3 Tween編
今回もUIです。UIアニメーションでよく使うTween関連です。
Tween
シンプルな動きはTween制御系Assetが便利です。有名な DOTween, LeanTween, iTweenの特徴とサンプルコードを貼ってます。
また、パフォーマンス比較はDOTween公式サイトにまとまってます。
ちなみに私はパフォーマンス重視なのでLeanTweenを使ってます。また、ゲーム仕様に依存する部分はこちらやこちらを参考に自前のTween制御を書いてます。
DOTween
無料版はパッケージにコードは含まれないです。(GitHubにアップはされている)有料版はTextMeshPro対応とEditor上でTweenを編集できます。
// !!初回起動時に1回だけ呼ぶ必要あり. DOTween.Init(); // 実行. 2秒で targetPos へ Linear補間で移動後、OnCompleteに通知. Tweener twr = this.transform.DOMove( targetPos, 2.0f ); twr.SetEase( Ease.Linear ); twr.onComplete = OnComplete; // 中断. twr.Kill( complete:true ); // 一時停止. twr.Pause(); // 再開. twr.Play();
LeanTween
パフォーマンス重視のTweenです。コードは全て含まれてるのでカスタムしやすいです。
// !!初回起動時に1回だけ呼ぶ必要あり. LeanTween.init(); // 実行. 2秒で targetPos へ Linear補間で移動後、OnCompleteに通知. LTDescr dsc = this.transform.LeanMove( targetPos, 2.0f ); dsc.setEase( LeanTweenType.linear ); dsc.setOnComplete( OnComplete ); // 中断. LeanTween.cancel( dsc.uniqueId, callOnComplete:true ); // 一時停止. dsc.pause(); // 再開. dsc.resume();
iTween
iTween.cs だけのシンプルな作りです。
// 実行. 2秒で targetPos へ Linear補間で移動後、OnCompleteに通知. var hash = iTween.Hash( "position", targetPos, "time", 2.0f, "easetype", iTween.EaseType.linear, "oncomplete", "OnComplete" ); iTween.MoveTo( this.gameObject, hash ); // 中断. iTween.Stop( this.gameObject ); // 一時停止. iTween.Pause( this.gameObject, includechildren:true ); // 再開. iTween.Resume( this.gameObject );
Time.timeScaleの影響
上記3つのTweenの時間制御は Time.deltaTime を参照しています。こちらの値は Time.timeScale の影響を受けます。そして、これは演出系のUIアニメーションで問題になる場合があります。
例えば以下のような格闘ゲームのKO演出です。キャラ・背景は一時停止していますが、"KO"のUIはアニメーションしてます。
ゲーム全体のアニメーションを停止であればTime.timeScaleの値を変更すれば良いです。
しかし、このケースではUIアニメーションは影響を受けない設定が必要です。
以下に各TweenのTime.timeScaleの影響を受けない設定をするサンプルコードです。
DOTween
twr.SetUpdate( UpdateType.Normal, isIndependentUpdate:true );
LeanTween
dsc.setIgnoreTimeScale( useUnScaledTime:true );
iTween
// "ignoretimescale" に true を設定する. var hash = iTween.Hash( "position", targetPos, "time", 2.0f, "easetype", iTween.EaseType.linear, "oncomplete", "OnComplete", "ignoretimescale", true ); // ←ここ.
おまけ
Tweenとは別ですがParticleSystemで作られたUIエフェクトは Delta Time を Unscaled にすると TimeScale の影響を受けません。
まとめ
Tween制御系Assetをまとめてみました。簡単なアニメーションはTweenはとても便利です。 より複雑なアニメーションは Animator, AnimationClip を使う感じですかね。
【Unity】UI開発 Part 2 テキスト編
前回に引き続きUnityによるUI開発です。今回はテキスト編です。
概要
Unityのテキスト表示は uGUI標準のText と TextMeshPro です。
今回はTextMeshPro を取り上げます。
導入方法
Window > TextMeshPro > Import TMP Essential Resources から最低限のアセットをインポートします。
FontAsset
TextMeshProでテキストを表示するためにFontAssetを作成します。
作成方法
- Window > TextMesh Pro > Font Asset Creator を選択
- Source Font File に フォントデータ(TTF, OTF) を設定
- Atlas Resolution に 解像度を設定、ASCIIなら 512 x 512,
日本語(ひらがな・カタカナ・常用漢字含む)なら 4096 x 4096 くらいで収まります。 - Character Set を Custom Characters に設定
- Custom Character List に対象テキストを追加
- Render Mode に SDF AA を選択
- 「Generate Font Atlas」をクリック
※データ量によって生成に1〜2分ほど掛かります。 - 「Save」をクリックして Font Asset を .asset にして保存
使い方
TextMeshProコンポーネントの Font Asset に作成した Font Asset を設定するだけです。
Dynamic SDF
Font Asset をダイナミックフォント的な扱いを可能にする Dynamic SDF 形式にする方法です。
- 作成した Font Asset を選択
- Source Font File に フォントデータ(TTF, OTF) を設定
Atlas Population Mode で Dynamic を選択
Atlas Width/Height に任意の解像度を設定
- 「Apply」をクリック
Font Fallback
Font Asset 内に無い文字を指定した際、別のFont Assetを参照する機能です。
設定方法は対象Font Asset を選択
Font Fallback Asset に Font Asset を設定します。
使用例としては
英数字は良く使うが、全角文字はほぼ使わないゲームがあるとします。
・ASCII制御文字(半角英数字・記号) のみの Font Asset A を作成
・そのFontFallback に Dynamic SDF 形式 の 全角文字のFont Asset B を設定
こうすれば、普段は A を参照しつつ、全角文字を使う際は B を参照し
フォント用テクスチャのメモリ消費を抑えられます。
絵文字
TextMeshProはテキスト領域に絵文字を挿入できます。Sprite Asset を必要とします。
Sprite Asset 作成方法
- 対象のテクスチャを選択
- Inspectorビューから
Texture Type - Sprite (2D and UI) を選択
Sprite Mode - Multiple を選択
- 「Apply」をクリック
- 「Sprite Editor」をクリック
- Sprite Editor 上で使いたい絵文字を切り抜く
- 「Apply」をクリック
- Projectビュー > Create > TextMeshPro > Sprite Asset を選択
- Sprite Asset が作成されます。
表示方法
- TextMeshPro コンポーネント の Extra Settings を開く
- Sprite Asset の項目に作成した Sprite Asset を設定
- テキスト領域に以下のようにタグを使って入力
表示結果
表示位置のズレ
以下の方法でオフセットを調整すると直ります。
Sprite Asset の Sprite Glyph Table を開き個別にオフセットを調整します。
まとめて設定したい場合は Sprite Glyph Table の最下部にある Global Offsets & Scale を調整します。
ルビ
TextMeshPro はルビ(ふりがな)を設定できます。コガネブログさんのサイトがとても参考になります。
baba-s.hatenablog.com
まとめ
TextMeshPro は各アセット作成の手間はありますが表現の幅とパフォーマンスは uGUI標準のText よりも良いです。単純なテキスト表示であれば Text でも十分です。
参考
【Unity】TextMeshProにFont FallbackとDynamic SDF Systemが追加、日本語が使いやすくなった。 - テラシュールブログ
Unity Live Help
TextMesh Pro: Sprite Assets - Unity Learn
【Unity】UI開発 Part 1 Canvasと描画順
あけましておめでとうございます。久しぶりの更新です ^_^;
今回は、UnityのuGUIを軸としたUI開発をまとめてみました。
Canvas
uGUIはCanvasコンポーネントを起点とします。このコンポーネント配下に各UI要素を配置します。
Render Mode
UIの描画方式を設定します。
解像度対応
モバイルは端末によって解像度が異なる問題を解決する必要があります。ここではアスペクト比を固定化する方法です。
- Canvas Scaler の設定を変更
・UI Scale Mode - Scale With Screen Size
・Reference Resolution - 基準解像度の半分 (1080 x 1920の場合、X:540 Y:960)
・Screen Match Mode - Expand - Canvas配下にPanelを配置
- 追加したPanel に Aspect Ratio Filter コンポーネントを追加
・Aspect Mode - Fit In Parent - クリップ処理が必要なら Panel に Maskコンポーネント を追加
・Show Mask Graphis - チェック外す
SafeArea対応
Unity2019.3以降であれば Device Simulator を使いエディタ上で大まかな判定が可能です。テラシュールさんの記事が綺麗にまとまってます。
【Unity】Device Simulatorでノッチとセーフエリアの対策 - テラシュールブログ
描画順
これはとても重要です。事前にUIデザイナーとエンジニアでルールを決めないと後で痛い目にあいます・・いやほんと・・(TAT)
Canvas内の描画順
Canvas内に限定した話であれば、Hierarchyビューの並びで描画順が決まります。
複数Canvas間の描画順
Screen Space - Overlay と Screen Space - Camera / World Space で異なる設定になります。
Screen Space - Overlay
・常に Screen Space - Camera と World Space のUIよりも手前に描画
・Sort Order で描画順を制御
Screen Space - Camera / World Space
・カメラDepth > Sorting Layer > Order In Layer の順で奥から手前に描画
こちらのサイトがとても綺麗にまとまっています。
uGUI 描画優先度のチートシート │ Aiming 開発者ブログ
UIにパーティクルを差し込む
例えばUI > Particle > UI で表示したい場合、Sorting Layer が同じ値ならOrder In Layer で調整できます。
手前のUI要素を 別Canvasの子にしてOrder In Layer を変更します。 (UI要素の Sorting Layer と Order In Layer は Canvas 単位の設定値になるため)
ただし、この方法はCanvasを増やすためパフォーマンス(SetPass増)に影響します。
この辺はゲーム仕様に応じて使い分けると良いです。
Image
画像やシンプルな矩形を表示するコンポーネントです。
テクスチャの設定
Imageに使用するテクスチャは Texture Type を Sprite (2D and UI) に設定します。
Image Type
ImageType | 表示 |
---|---|
Simple | 最もシンプルな表示です。拡大縮小すると画像全体を引き伸ばします。 |
Sliced | 拡大縮小時にBorder(境界)部分の大きさは固定したままで、中心部分だけ引き伸ばします。 |
Tiled | Borderの制御はSlicedと同じです。中心部分を繰り返し表示にできます。 |
Filled | Fill Methodで指定した方式で表示領域を変更します。 |
Border 設定方法
Sliced, Tiled を使う場合は Sprite Editor で Border の設定を必要とします。
1. 対象テクスチャのInSpectorビューから「Sprite Editor」を選択
2. Sprite Editor ウインドウ左上のプルダウンから「Custom Outline」を選択
3. Border の値を入力して右上の「Apply」をクリックで完了
RawImage
Image同様に画像を表示するコンポーネントです。
Imageと違い、Texture Type に依存しないので
・ネットワーク経由でダウンロードした画像
・ゲーム内の3Dモデルをテクスチャ
等に使用できます。
UV Rect
こちらのプロパティを編集することで UV ScrollやTilingを設定できます。
まとめ
Canvasとそれに紐づく解像度対応や描画順、最後に簡単に画像表示できる Image・RawImage について書きました。これだけでもかなりの量になりました。。本当はテキスト、アニメーション、パフォーマンスと書きたい事は沢山ありますが今回はこの辺で ^_^;
参考
https://learning.unity3d.jp/tag/ui/
Unityでパフォーマンスの良いUIを作る為のTips | PPT
Unity Live Help
【Unity】Google Mobile Ads Unity Plugin を試す
今回は Google Mobile Ads SDK Unity プラグインを使った動画リワード広告を試してみました。
リワード広告とは
ユーザーが広告を操作・視聴するのと引き換えに、アプリ内で報酬を獲得できるものです。スマホのアプリでよくある、ここから先は動画広告を見たら遊べる的なやつです。
Google AdMob
まずは Google AdMob でAdMobアカウント、アプリ情報、広告ユニットの作成をします。すでにある方は読み飛ばしてOKです。
AdMobアカウント作成
こちらの Google AdMob にアクセス、アカウントが無ければ以下のような表示になります。
必要な情報を入力してAdSence 利用規約を確認してチェックを入れたら「ADMOBアカウントを作成」をクリック
ちなみに私は以下の情報で作成
国または地域:日本
タイムゾーン:(UTC+09:00) 東京
お支払い通貨:(JPY¥)
アプリ情報を作成
アプリ固有のアプリIDを取得するためにアプリ情報を作成してAdMobに追加します。
広告ユニットを作成
アプリ用の広告ユニットを作成します。
Google Mobile Ads Unity Plugin
パッケージのインストール
こちらのGitHubから GoogleMobileAds-v[バージョン].unitypackage をダウンロードします。
適当なUnityプロジェクトを作成して Assets > Import Package > Custom Package からダウンロードした .unitypackage をインポートします。
インポート中に Package Manager Resolver ウインドウが表示され、Game Package Registry by Google のレジストリをPackage Managerに追加して良いかと聞かれるので 「Add Selected Registries」をクリックします。
次に Assets > Google Mobile Ads > Settings を選択
GoogleMobileAdsSettings.assetが生成されます。
Android用の設定
Assets > External Dependency Manager > Android Resolver > Settings を選択
Enable Auto-Resolution, Enable Resolution On Build のチェックを外しておきます。
最後に Assets > External Dependency Manager > Android Resolver > Resolve を選択すると
Android 固有ライブラリ(AARなど) が Assets/Plugins/Android に配置されます。iOS用の設定
Cocoapods が未インストールの場合は
Assets > External Dependency Manager > iOS Resolver > Install Cocoapods からインストール
次に Assets > External Dependency Manager > iOS Resolver > Settings を選択
Xcode Project - Add Cocoapods to the Xcode project を選択後、OKをクリック
これでUnity Editor上で必要な設定は完了です。
スクリプトの設定
適当なCSファイルを作成して広告表示までの処理を書いていきます。
初期化
アプリ起動時などに MobileAds.Initialize() を一度だけ呼び出して初期化します。
using UnityEngine; using GoogleMobileAds.Api; using GoogleMobileAds.Common; public class SampleAds : MonoBehaviour { void Start() { // 広告を読込前に一度だけ呼び出す. MobileAds.Initialize( OnInitCompleted ); } void OnInitCompleted( InitializationStatus initStatus ){ } }
広告オブジェクトの作成と読込
広告ユニットIDを設定してリワード広告オブジェクトの作成と読込を行います。
RewardedAd m_rewardedAd; void CreateAndLoadRewardedAd() { // プラットフォームに応じた広告ユニットIDを設定. string adUnitId = "unexpected_platform"; #if UNITY_ANDROID adUnitId = "ca-app-pub-xxxxxxxxxxxxxxxxxxx/xxxxxxxxxxx"; #elif UNITY_IPHONE adUnitId = "ca-app-pub-xxxxxxxxxxxxxxxxxxx/xxxxxxxxxxx"; #endif // リワード広告オブジェクトを作成. m_rewardedAd = new RewardedAd( adUnitId ); // リワード広告を読込. AdRequest request = new AdRequest.Builder().Build(); m_rewardedAd.LoadAd( request ); }
広告の表示
リワード広告の表示は RewardedAd.Show() を呼ぶだけです。ただし、広告を1回表示するとそのRewaredAdオブジェクトは破棄されるので、このオブジェクトを使い回して以降の広告を読込/表示はできません。
void Show() { if( m_rewardedAd.IsLoaded()){ m_rewardedAd.Show(); } }
イベントの設定
以下のようにRewardedAdに広告用イベントを設定できます。
m_rewardedAd.OnAdLoaded += OnAdLoaded; // 広告読込完了時に呼び出される. m_rewardedAd.OnAdClosed += OnAdClosed; // 広告を閉じた時に呼び出される.
設定できるイベントは以下です。
イベント | 説明 |
---|---|
OnAdLoaded | 広告読込完了時に呼び出される。 |
OnAdFailedToLoad | 広告の読込失敗時に呼び出される |
OnAdOpening | 広告が表示されると呼び出される。用途は必要に応じてアプリの音声やゲームループを停止する等 |
OnAdFailedToShow | 広告の表示が失敗時に呼び出される |
OnAdClosed | ユーザが「閉じる」アイコンまたは「戻る」ボタンをタップして広告を閉じると呼び出される。用途は必要に応じてアプリの音声やゲームループを再開する等 |
OnUserEarnedReward | 動画広告を視聴したユーザへのリワード付与時(動画を最後まで視聴した時)に呼び出される。引数のRewardには広告ユニットに設定した報酬アイテム(Type)報酬の数(Amount)が入る |
<注意>上記イベントはUnityのメインスレッドとは別スレッドで実行されるので、設定したイベント内でUnityのAPIを呼びたい場合は以下のように MobileAdsEventExecutor.ExecuteInUpdate() を使って例外を回避する必要があります。
[SerializeField] UnityEvent m_onLoadedAd; void OnAdLoaded( object sender, EventArgs args ) { MobileAdsEventExecutor.ExecuteInUpdate( ()=>{ m_onLoadedAd.Invoke(); }); }
イベントをキューイングしてUpdate()で実行してるだけなので同様の処理を自前で書いても良いです。
開発中の動作検証について
開発中にテスト広告を使わずに何度もリリース用の広告を呼び出すと不正な操作と検出されてAdMobアカウントをBANないしは利用制限が掛かる可能性があります。
テスト広告ユニットID
遷移やイベントの検知確認などのアプリをリリースする前のチェックであればこちらにテスト広告ユニットIDが用意されているのでこれらを使用してください。
テストデバイス追加
テスト広告ユニットではなく自分の作成した広告ユニットで確認したい場合、対象端末のテストデバイスIDを追加すれば確認できます。
テストデバイスIDの確認と設定方法は以下です。
1.まずは先程のスクリプトの公告ユニットIDを設定するところをテスト広告ユニットIDに変更します。
void CreateAndLoadRewardedAd() { // 動画リワードのテスト広告ユニットIDを設定. string adUnitId = "unexpected_platform"; #if UNITY_ANDROID adUnitId = "ca-app-pub-3940256099942544/5224354917"; #elif UNITY_IPHONE adUnitId = "ca-app-pub-3940256099942544/1712485313"; #endif m_rewardedAd = new RewardedAd( adUnitId ); AdRequest request = new AdRequest.Builder().Build(); m_rewardedAd.LoadAd( request ); }
2.上記スクリプトが含まれる確認用アプリを作成して起動後のログからテストデバイスIDを取得します。
Android
adb logcat | grep I/Ads から確認できます。
I/Ads (12708): Use RequestConfiguration.Builder().setTestDeviceIds(Arrays.asList("ここにテストデバイスIDが入る") to get test ads on this device.
iOS
・XCode の View > Debug Area > Active Console から確認できます。
<Google> To get test ads on this device, set: GADMobileAds.sharedInstance.requestConfiguration.testDeviceIdentifiers = @[ @"ここにテストデバイスIDが入る" ];
以下のエラーが出る場合、iOS端末の 設定 > プライバシー > 広告 > 追跡型広告の制限をオフにしてアプリを再起動してください。
<Google> Limit Ad Tracking may be enabled. To get test ads on this device, disable Limit AdTracking.
3.確認したテストデバイスIDを AdRequest.AddTestDevice() に設定します。
<注意>リリース版ではAddTestDevice()が含まれないようにしてください
// リワード広告を読込. AdRequest request = new AdRequest.Builder() .AddTestDevice( AdRequest.TestDeviceSimulator ) #if UNITY_ANDROID .AddTestDevice( "テストデバイスID for Android" ) #elif UNITY_IPHONE .AddTestDevice( "テストデバイスID for iOS" ) #endif .Build();
これで準備が完了です!自分の作成した広告ユニットを使いテストデバイスによる確認ができます。長かった・・・^_^;
まとめ
最後に簡単なミニゲームとリワード広告を連携させたサンプルをこちらのGitHubにアップしておきました。
参考
・始める | Unity | Google for Developers
・[Xcode]Mac OS Catalinaにアップデートしたらpodコマンドが通らなくなった
【Unity】Enumファイルを自動生成する
Enumファイルを自動生成するEditor拡張を作ってみました。生成部分は .Net Framework の System.CodeDom.Compiler を使ってます。