ゴイサギ日記

東京でエンジニアとして頑張って何とか生きてます。。ゆる~く更新していきます

【Unity】Triggers モジュールについて

明けましておめでとうございます。もう2月ですが・・ ^_^;

今回は Particle System の Triggers モジュールについて調べてみました。
確認バージョンは 2019.1.0b2 です。

実装

Trigger モジュールは Colliders に設定したコライダーに対してパーティクルが接触した際の処理を設定することができます。

設定できる処理は以下になります。

項目 処理内容
Ignore 何もしない
Kill ParticleSystemが設定されているGameObjectを削除
Callback スクリプトに通知

今回はこの中の Callback についてまとめてみました。

コールバックを設定するスクリプトを用意します。今回は ParticleTriggerTest.cs という名前で作成して Particle System と同じ GameObject にアタッチします。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ParticleTriggerTest : MonoBehaviour
{
    ParticleSystem m_particleSystem;
    List<ParticleSystem.Particle> m_enterList = new List<ParticleSystem.Particle>();
    List<ParticleSystem.Particle> m_exitList = new List<ParticleSystem.Particle>();

    void Start()
    {
        m_particleSystem = this.GetComponent<ParticleSystem>();
    }

    /// <summary>
    /// .
    /// </summary>
    void OnParticleTrigger()
    {
        // 条件に一致するパーティクルを ParticleSystem から取得する.
        int numEnter = m_particleSystem.GetTriggerParticles( ParticleSystemTriggerEventType.Enter, m_enterList );
        int numExit = m_particleSystem.GetTriggerParticles( ParticleSystemTriggerEventType.Exit, m_exitList );

        // 取得したパーティクルの色を変更する.
        for( int idx=0 ; idx < numEnter ; idx++ ){
            ParticleSystem.Particle p = m_enterList[ idx ];
            p.startColor = Color.red;   // 赤色.
            m_enterList[ idx ] = p;
        }
        for( int idx=0 ; idx < numExit ; idx++ ){
            ParticleSystem.Particle p = m_exitList[ idx ];
            p.startColor = Color.yellow; // 黄色.
            m_exitList[ idx ] = p;
        }

        // 変更したパーティクルを ParticleSystem に再設定.
        m_particleSystem.SetTriggerParticles( ParticleSystemTriggerEventType.Enter, m_enterList );
        m_particleSystem.SetTriggerParticles( ParticleSystemTriggerEventType.Exit, m_exitList );
    }
}
  1. Triggersモジュールを使用すると OnParticleTrigger が呼び出されます。
  2. インスペクタで Callback に設定した条件(Outside, Inside, Exit, Enter)ごとのパーティクルを取得するには GetTriggerParticles を使います。
  3. 取得したパーティクルのパラメータに変更を加えたら SetTriggerParticles で変更内容を適用してあげます。

上記のサンプルスクリプトはパーティクルのカラーを Enter時に赤色、Exit時に黄色 に変えています。

気になる点

OnParticleTrigger が毎フレーム呼ばれる
Outside のパーティクルを取得するために毎フレーム呼び出しになっているようです。しかも Triggers モジュールのチェックが有効になるだけで呼ばれてしまうところにも注意が必要です。

GetTriggerParticles / SetTriggersParticles の負荷が高い
こちらは ParticleSystem.GetParticles/SetParticles と同様にパーティクルの情報に直接アクセスする事が出来ず、一度配列にコピーした後に変更を加えて、再度データを流し込む必要があるため負荷が高くなります。

Colliderの登録が面倒
インスペクタ上から Colliders にコライダーを登録する必要があるのですが、数が多いと大変です。ParticleSystem.trigger.SetCollider() を使えばコライダーを登録する事ができるので スクリプトから制御するのも手ですね。

まとめ

パフォーマンスの面で気になるところが多い印象でした。こちらのフォーラムにあるように今後の更新で JobSystem によるパフォーマンス改善が出来ないかUnityさんの方で色々と試しているようですね。表現の幅は広がりそうなのでとても楽しみです。^_^

参考

Triggers モジュール - Unity マニュアル

【Unity】VideoPlayerを使ってみた

最近、Unityでの動画再生について調べる必要があったので自身の備忘録としてまとめました。

VideoPlayer

Unityの動画再生はUnity5.6から追加された VideoPlayer コンポーネントを使う必要があります。Unity5.6より前は MovieTexture を使っていましたが Unity2018.3 から廃止されてしまったので VideoPlayer 一択となりました。

設定方法

VideoPlayerで動画の再生を確認するだけであれば割と簡単です。

  1. 動画ファイルをProjectビューに配置します。 f:id:aki517:20181229124056p:plain

  2. Main Camera が設定されている GameObject に VideoPlayerコンポーネントを追加
    f:id:aki517:20181229123808p:plain

  3. VideoPlayerコンポーネンとの Video Clip に動画ファイルを設定
    f:id:aki517:20181229125744p:plain

  4. Unityエディタを再生
    f:id:aki517:20181229130311g:plain

事前読込

VideoPlayer.Prepare() を使えばバッファへ動画データを事前に読込んでおくことができます。VideoPlayer.prepareComplete にコールバックを設定すれば読込完了を検出することができます。

void Start()
{
    // VideoPlayerコンポーネント取得.
    videoPlayer = obj.GetComponent<VideoPlayer>();
    // 即再生されるのを防ぐ.
    videoPlayer.playOnAwake = false;
    // パス or VideoClip を設定.
    videoPlayer.url = "Assets/Resources/testfile.mp4";
    // videoPlayer.clip = videoClip;
    // 読込完了時のコールバックを設定.
    videoPlayer.prepareCompleted = OnCompletePrepare;
    
    // 読込開始.
    videoPlayer.Prepare();
}

// 読込完了時のコールバック.
void OnCompletePrepare()
{
    // 読込が完了したら再生.
    videoPlayer.Play();
}
その他

あと動画に関する知識があまりに無かったので、その辺もメモしておきます ^_^;

コーデック

データ(映像、音声)の圧縮・変換と復元の方法です。COmpression/DEcompressionを縮めたもので映像と音声でコーデックがそれぞれ異なります。圧縮・変換を「エンコード」復元を「デコード」と言います。

映像コーデック
コーデック 概要
MPEG-4 第三世代携帯電話や携帯ゲーム機などモバイルで主流になりつつある
H.264 ビットレートで高画質を維持することができるため、動画配信サービスやiPhone,Androidなどのスマホに採用されている、現時点で最も主流な映像コーデック
H.265 H.264の後継、H.264よりも圧縮効率に優れているがエンコード時の負荷が高い、また、Unity2018.3時点ではVideoPlayerで再生サポートされていない(Unity2019.1aから公式サポートとのこと)
WMV9 マイクロソフトが開発、Windowsでの普及率は高い
Divx Divx, Inc がMPEG-4をベースに独自開発、DVDプレイヤー、カーナビなどのデジタル家電でよく利用される
Xvid フリーの映像コーデック、エンコードDivxより速いと言われている、商業使用時はそのソフトのソースコードを公開する義務が発生するので殆ど使用されていない
音声コーデック
コーデック 概要
MP3 最も使用されている音声コーデック
AAC MP3の後継、同程度のビットレートであればMP3より高い音声品質が実現、
AC3 5.1chの出力に対応、圧縮率が高い場合は他音声コーデックより音声品質が良い、DVD・Blu-ray等に使用される
コンテナ(動画形式)

映像コーデック + 音声コーデックのセット、正式名称は「コンテナフォーマット」と言うそうです。コンテナごとに扱える映像コーデックと音声コーデックが決まっているので目的に応じたコンテナを選択する必要があります。以下に代表的なものをまとめてみました。

コンテナ 映像コーデック 音声コーデック 拡張子
MP4 MPEG-4, H.264, H.265 AAC, AC3, MP3 .mp4, .m4a
MOV MPEG-4, H.264, MJEG AAC, MP3, LPCM .mov, .qt
WMV WMV9 WMA,AAC,MP3 .wmv
AVI MPEG-4, Divx, Xvid, H.264, H.265 AAC, MP3 .avi

MP4 が割と一般的なのかなと思いました。iPhone,Android, 携帯ゲーム機などで広く使われていますし ^_^

また、iPhone, Androidの端末やOSバージョンで対応しているコーデックは以下ページで確認できます。

iPhone
「Video Playback」「Audio Playback」参照
iPhone - Compare Models - Apple

Android
Supported media formats  |  Android Developers

参考

Unity - Scripting API: VideoPlayer

【Unity】Shuriken Particle Unity2018

Unity2018以降で Shuriken Particle に追加された機能で個人的に気になったものを書いていきます。

確認バージョンは 2018.3.0f1 です。

Ring Buffer Mode


メインモジュールに追加された機能です。
パーティクル数が Max Particles 到達時の処理を設定します。

パラメータ
説明
Disabled Ring Buffer Mode を無効にします。上限値に達した場合、そのパーティクルの寿命(Start Lifetime)がきて上限値未満になるまで次のパーティクルは発生しなくなります。
Pause Until Replaced 上限値に達した場合、古いパーティクルを即時削除して次のパーティクルを発生させます。
Loop Until Replaced Pause Until Replaced 同様に古いパーティクルを削除しますが、上限値に達するまで Loop Range で設定した値内でアニメーションをループ再生できます。

下の動画では Loop Range を 0.0 - 0.5 で設定した後に Color over Lifetime で 0.0 - 0.5 間は白→緑→白、0.5 - 1.0 間はαフェードを設定しています。

パーティクル発生中は緑色に発光し続けて、上限値に達して削除対象になった古いパーティクルはαフェードで徐々に消えています。

設定はこんな感じです。
注意点として、古いパーティクルが完全に消える前に次のパーティクルが発生するため一時的に Max Particles を超えたパーティクル数が発生します。
Orbital Velocity


Velocity over Lifetime モジュールに追加されたパラメータです。任意軸を中心に渦を巻くパーティクルの動きを設定できます。Orbital で軸を設定します。軸の中心はエミッターの位置になります。

(動画はパーティクルの動きを確認しやすくするためにTrailモジュールを使っています)

Offset パラメータで軸の中心を変更できます。エミッターの位置から離れるほど下の動画のように大きな渦になります。

Shape : Rectangle

Shape モジュールに追加されたパラメータです。テクスチャの色情報を元にパーティクルの発生開始位置を設定できます。

パラメータ 説明
Texture テクスチャを設定します。対象テクスチャはRead/Writeを有効にする必要があります
Clip Channel クリップするRGBAチャンネルを設定します。選択したチャンネルでマスクして発生開始位置を調整します。
Clip Threshold Clip Channel で設定したチャンネルの閾値を設定します。注意点として、Clip ChannelでAlphaを設定した場合は適切な閾値を設定しないと透明なパーティクル(下図)を生成して余計な描画負荷を引き起こします。
Color affects Particles チェックを入れるとパーティクルがテクスチャのカラーの影響を受けます。
Alpha affects Particles チェックを入れるとパーティクルがテクスチャのα値の影響を受けます。
Shape : MeshRenderer


こちらも Shape モジュールに追加された機能です。指定Mesh上からパーティクルを発生させます。

パラメータ 説明
Type パーティクルの発生位置を設定します。
Mode どのようにパーティクルを発生させるか設定します。Type を Vertex, Edge で設定可能
Spread パーティクルの発生間隔を設定できます。Type を Edge で設定可能
Speed 頂点間を移動する際の速度を設定できます。Type を Edge で設定可能
Mesh Meshを設定します。対象メッシュは Read/Write を有効にしてください。
Texture Sheet Animation : FPS


Texture Sheet Animation モジュールの Time Mode に追加されたパラメータです。テクスチャアニメーションの FPS を設定できます。

所感

あと今回の機能はβ版で確認したので正式リリースでは仕様変更される可能性もありますが、色々とゲームの演出に使えそうな機能を追加しており表現の幅は広がりそうです。

参考

【Unite Tokyo 2018】パーティクル・マニアクス - YouTube
【CEDEC2018】 パーティクル新機能の紹介 - YouTube

【Unity】パーティクルのボリューム表現

煙や雲を表現する場合、パーティクルのビルボードを使って実装するのが一般的です。(真面目に煙や雲のポリゴンモデルを用意して描画すると負荷が凄い事になってしまうので・・・)

ただ、この方法は処理が軽くなるけど四角形ポリゴンにテクスチャを貼り付けてるだけなのでボリューム感が出ない事があります。
f:id:aki517:20181027192548p:plain

ライトの影響を受ければ立体感が出るはずなので単純に光源からの距離に応じて頂点単位で明るさを調整するシェーダーを適用してみました。
f:id:aki517:20181026010111p:plain
だいぶマシになりましたがもう少しボリューム感が欲しいです ^^;

最終的にフラグメントシェーダーでテクスチャのα値を雲の厚みとして扱うようにして明るさの調整をしてみました。
f:id:aki517:20181026010150g:plain
だいぶ良い感じになりました。

テクスチャのα値とは別で設定したい場合は専用のテクスチャを用意してそちらの値を参照するのが良さそうです。

プロジェクト一式はこちらにアップしました。
github.com

今回はなるべく低コストでモバイルでも動かせるものにしたかったので擬似表現になりましたが、多光源対応やより精度の高いボリューム表現をしたい場合はボリュームレンダリングを使うとかになると思います。

参考

3Dゲームファンのための「ワンダと巨像」グラフィックス講座

【Unity】Unity2018.3からのPrefabワークフロー

Unity2018.3のβ版でPrefabのワークフローが色々と変更されました。今回はその中の Prefab Mode, Nested Prefab, Prefab Variant についてまとめてみました。

Prefab Mode

2018.3より前のバージョンでPrefabを編集する時は以下の流れが一般的でした。

  1. ProjectビューのPrefabをHierarchyビューにドラッグ&ドロップ
  2. Inspector/Sceneビュー上でPrefabを編集
  3. InspectorビューからApplyボタンを押して編集内容を保存
  4. Hierarchyビュー上からPrefabを削除

この流れだと以下の問題が起こりやすかったです。

・Applyボタンを押し忘れてPrefabの保存に失敗
・編集したPrefabの削除を忘れてシーンに残る

Prefab Mode はこういった問題を解決するためのものらしいです。
(Unityの公式ブログに書いてました)

Prefab Mode への移行方法は以下の3パターンがあります。
・Projectビューで対象Prefabをダブルクリック
・ProjectビューでPrefabを選択してInspectorビューの「Open Prefab」をクリック
・Hierarchyビュー上の対象Prefabの右側にある「>」をクリック

上記いずれかを実行すると以下のPrefab編集用の画面に移行します。

f:id:aki517:20181008085606p:plain

保存方法

Sceneビュー上部右端の「Auto Save」のチェックが有効なら編集内容は自動で保存されます。以前のように編集後に「Apply」ボタンを押す手間が無くなりました。

f:id:aki517:20181008083723p:plain

ただし、サイズの大きいPrefabを自動保存が有効な状態で編集すると動作が遅くなる場合があるので、その時は「Auto Save」のチェックを外します。手動で保存する場合は「Auto Save」の隣にある「Save」ボタンを押すか、または 「Ctrl + S」(Mac : Cmd + S) 保存できます。

f:id:aki517:20181008090406p:plain

環境設定

Prefab Modeでは 専用Sceneファイルを設定できます。 Edit > Project Settings > Editor > Prefab Editing Environments で設定できます。

f:id:aki517:20181008093715p:plain

例えば UI Environment にヘッダーとフッターのUIとCanvasを配置した Sceneファイルを設定しておけば、UI関連のPrefabを編集する際にそのSceneが読み込まれた状態で編集できます。これを上手く使えば、UIの編集をする際にヘッダーとフッターUIのPrefabも Hierarchyビューにドラッグ&ドロップして...という手間が省けますね

f:id:aki517:20181008121807g:plain

以下のようにスクリプトからも設定できます。

EditorSettings.prefabRegularEnvironment = customScene;
EditorSettings.prefabUIEnvironment = customSceneUI;

2019/6/23 追記
UI Environment に Scene を設定しなかった場合、PrefabMode時に Canvasコンポーネントだけが接続されたオブジェクトがルートに配置されるため、実際のゲームSceneでCanvas Scaler を接続して解像度に応じたUIオブジェクトのスケール処理を行なっている場合、PrefabModeで編集した結果とゲーム画面とでレイアウトが一致しない現象が発生することがあります。この問題は ゲームSceneと同じ Canvas Scaler を設定した Scene を UI Environment に設定すれば回避できます。
f:id:aki517:20190623012859p:plain

終了方法

Prefab Mode を終了するには Hierarchyビューの「<」をクリックするか、Sceneビュー上部の「Scenes」をクリックします。
f:id:aki517:20181008092025p:plain

Nested Prefab

Prefabの中にPrefabを設定できる仕組みです。これの便利なところは例えば下図のようにある Prefab に Particle System が設定された別Prefab が3個配置されている状態から、Prefab Mode で Particle System のカラーを1つ編集するだけで他の2つにもその設定が適用されます。

f:id:aki517:20181008202446g:plain

今までのように個別で設定を行いたい場合は対象Prefabを右クリックして「Unpack Prefab」か「Unpack Prefab Completely」を選択します。2つの違いは選択したPrefabに対してのみ適用されるか、その子階層にあるPrefabにも適用されるかです。

ちなみにNestは「入れ子」という意味です ^_^

Prefab Variant

あるPrefabをベースにして異なるパラメータや、追加のコンポーネントを設定したPrefabを作成したい場合に使います。

作成方法はベースとなるPrefabを右クリック > Create > Prefab Variant で作成できます。 f:id:aki517:20181008203353p:plain

下図のようにPrefabアイコンに矢印が描かれたPrefabが作成されます。今回はパーティクルサイズが異なる Prefab を作ってみるので「PrefabParticle_Large」としておきます。

f:id:aki517:20181008204111p:plain

PrefabParticle_Large の Prefab Mode に移行して Start Size を変更します。ベースと異なる部分があるとInspectorの左端に青いラインが表示されます。

f:id:aki517:20181008204514p:plain

保存方法

Variant Prefabの保存方法は通常Prefabと同様ですが、ベースのPrefabに設定値を適用したい場合はInspectorビューからOverrides > Apply All to Base をクリックするか
f:id:aki517:20181008210025p:plain

Overrides > 変更したコンポーネントを選択して 下図のようにベースとの変更差分を確認しながら 対象パラメータ上で右クリック > Apply to Prefab XXXXX で適用する方法があります。
f:id:aki517:20181008210022p:plain

所感

Prefab Modeでの編集はとても便利で今まで起こっていた操作ミスが減りそうです。Nested Prefab と Prefab Variant はきちんと仕様を把握しておかないと編集した内容が他のSceneやPrefabに影響を及ぼす可能性があるので注意が必要かなぁと思いました。

参考

Prefabs Manual - Google ドキュメント

Prefab Workflow - Unity

【Unity】Projectビューのお気に入り情報を抜き出してみる

前回に引き続き今回もProjectビューです。お気に入り情報を抜き出してファイルにエクスポート/インポートするエディタ拡張を作ってみました。

別PCのUnityエディタに自分のお気に入り情報をインポートしたい時くらいにしか使えない気がしますが内部処理を把握するのに良い勉強になりました ^^;

github.com

Unityのソースコードが公開されているのでそちらを参考にしました。調べたところSavedSearchFilter がお気に入り情報を管理してたのですが internal class だったのでリフレクションを使って参照しています・・ ^^; tsubakit1.hateblo.jp

【Unity】Projectビューについて

f:id:aki517:20180924135509p:plain

Unityエディタで開発をする上で大変お世話になるProjectビュー(Projectウインドウ?Projectブラウザ?) 色々と便利な機能があるのに私自身も知らない機能があったのでメモがてら書いていきます。

ショートカット
Windows Mac 操作
Ctrl + D Cmd + D 選択中のアセットを複製
Delete なし 選択中のアセットを削除(ダイアログ確認あり)
Delete + Shift Delete + Cmd 選択中アセットを削除(ダイアログ確認なし)
F2 Enter 選択中のアセットの名前を変更
F F フォルダ内の選択したアセットを表示
Tab Tab 左側カラム(フォルダ一覧とFavorites)と右側カラムを

自分が良く使うものだけ抜粋しました。

フィルタ機能
タイプ (t:)

Search by Type ボタンからアセットのタイプでフィルタリングします。 f:id:aki517:20180924133612g:plain

ラベル (l:)

Search by Label ボタンに設定されているラベルでフィルタリングします。 f:id:aki517:20180924133621g:plain

ちなみ以下のように任意のラベルを作成する事もできます。 f:id:aki517:20180924133630g:plain

アセットバンドル名 (b:)

その名の通りアセットバンドル名でフィルタリングします。 f:id:aki517:20180924134738g:plain

参照 (ref:)

これはほぼ使う機会がないのですが、パス or InstanceID 指定で参照するオブジェクトを検索します。Assets以下のアセット数が多くなると検索に物凄い時間がかかります。下手するとUnityエディタ固まります・・

例えば Assets/Scripts/Player.cs (InstanceID:12345)を参照するオブジェクトを検索する場合は「ref:Scripts/Player.cs」(Assets/を除く) または「ref:12345:」と入力します。
f:id:aki517:20180924133645g:plain

Scene内とかも検索する場合はこのスクリプト使ったほうが良いですね ^^;

qiita.com

ちなみに InstanceID は Object.GetInstanceID() で取得するか、下図のように Inspector > Debug に切り替えると確認できます。
f:id:aki517:20180924133605g:plain

お気に入り機能

検索結果に好きな名前を付けて左側カラムのFavoritesに保存できます。検索ファイル名 + フィルタといった複数条件も保存出来るので便利です。Unityエディタ単位での設定しか出来ず、プロジェクト単位での設定が出来ないのが懸念点ですが・・・

f:id:aki517:20180924121847g:plain

参考

プロジェクトウィンドウ - Unity マニュアル