【Unity】3Dオブジェクトに動画を埋め込む
会社のアーティストさんから3Dオブジェクト内に動画を埋め込む方法を教えて欲しいと言われたので需要があるか分かりませんがその辺をまとめてみました。
リソースの準備
まずは必要リソースを準備します。
動画ファイル
動画ファイルです。まずはこれが無いと何も始まりませんね
RenderTexture
動画のレンダリング先となるテクスチャを用意します。
Projectビュー内で 右クリック > Create > Render Texture で作成します。
RenderTexture の Inspectorで重要な項目を以下にまとめました。
項目 | 概要 |
---|---|
Dimension | ここは2DでOKです。 |
Size | テクスチャの解像度を設定します。設定する数値は2のべき乗(128, 256, 512...)にする必要があります。 |
Anti-aliasing | アンチエイリアスを設定します。必要無ければ None にしておきます。 |
Enable Compatible Color Format |
チェックを入れておくと Color Format で設定したフォーマットが未対応ハードの場合、互換性のあるフォーマットを設定してくれます。 |
Color Format | テクスチャのカラーフォーマットを設定します。 |
Depth Buffer | Depthを用いて何か処理をしない限り必要ないのでサイズ削減のために None を選択します。デフォルトでは「At least 24 bit ...」が設定されているので注意 |
マテリアル
次にマテリアルを用意します。先ほど同様に Projectビュー内で 右クリック > Create > Material で作成します。Shader は今回はシンプルに Unlit > Texture にしています。あとはこのマテリアルに先ほどのRenderTexture を設定して準備は完了です。
設定
まずはシーン内に適当な3Dオブジェクトを配置します。
今回はHierarchyビュー上で 右クリック > 3D Object > Cube で立方体を作成しました。
次に対象の3DオブジェクトのMaterials に作成したマテリアルを設定します。
Inspectorビューから Add Component を選択して VideoPlayer を接続します。
Video Clipに 動画ファイルを設定します。
Render Mode を Render Texture に変更後、Target Textuure に先ほど作成した RenderTexture を設定します。
以上で準備は完了です。シーンを再生すると3Dオブジェクト内に動画が再生されてます。
まとめ
というわけで今回は VideoPlayer と RenderTexture を使って
3Dオブジェクトに動画を埋め込む方法をまとめてみました。
スクリプトなしでここまで出来るUnityやっぱり凄いですね。
ちなみにスクリプト制御での動画再生やコーデックについてはこちらにまとめてます。
goisagi-517.hatenablog.com
参考
【Unity】UI以外のタッチ制御
UI(ボタンやスクロールビュー)領域外のタッチ制御やスマホであればフリック、ピンチの制御をサンプルプログラムを作るたびに作成していたのでクラスにまとめてみました。
機能
UI領域外のクリック(ダブルクリック含む)、ピンチ、フリックのイベントを受け取ることができます。
参考
入力制御のベースとなる部分はこちらを参考にしました。
kan.kikuchiさん、ありがとうございます。
kan-kikuchi.hatenablog.com
【Unity】サウンド AudioClip と AudioMixer
久しぶりの更新です。。今回は備忘録がてらにUnityサウンドの AudioClip と AudioMixer についてまとめてみました。
AudioClip
WAV,MP3,OGG等の音声ファイルをUnityにインポートして Projectビューからファイルを選択すると Inspectorビュー に AudioClip の設定画面が表示されます。
Force To Mono
モノラルにします。データサイズが半分になります。SEなど音質をあまり気にしないデータは有効にすると良いです。
Load In Background
チェックを入れるとバックグラウンド読込が有効になります。ロードが完了したかどうかは AudioClip.loadStateで確認できます。
Load Type
音声データの読込方法を設定します。この設定はメモリやCPU負荷に影響するため、用途に応じた適切な設定が必要です。
項目 | 処理 | データサイズ | 用途 |
---|---|---|---|
Decompressed On Load | ・読込と同時にメモリへ展開される ・再生時の負荷が少ない |
200KB未満 | SE |
Compressed In Memory | ・圧縮されてメモリに載り、再生時に展開される ・消費メモリが抑えられる ・再生時のCPU負荷が大きい |
200KB〜1MB | Voice, Jingle |
Streaming | ・データを段階的にメモリへ読込で展開する ・消費メモリは最小になる ・即時再生ができない ・読込と展開が都度行われるのでCPU負荷が大きい |
1MB以上 | BGM, Voice(長尺) |
Preload Audio Data
チェックを入れるとアプリ起動時にメモリへ展開されます。再生時の負荷を抑えれますがデータ数に比例してアプリ起動の時間がかかるようになります。システムSE(決定音、キャンセル音)などゲーム内で常駐する必要があるものはチェックを入れておくと良いかもです。
Compression Format
圧縮フォーマットを設定します。ADPCMは圧縮率がVorbisほど高くはないですがCPU負荷が小さいメリットがあります。Vorbisは圧縮率が良いですが展開コストが高いです。
Quality
Compression Format で Vorbis を選択した場合に設定可能です。圧縮率の設定を行い、0に近いほどサイズが小さくなるがノイズが発生しやすくなります。70〜100の範囲は普通の人には差が分からないレベルなので、50〜70の間で設定すると良いでしょう。
AudioMixer
BGM, SE, Voiceなどのカテゴリーに応じたボリュームやエフェクトの設定が行えます。
作り方
Projectビュー内で右クリック > Create > Audio Mixer で作成出来ます。
Groups
カテゴリーの設定を行います。Masterをルートに階層で設定ができます。
Snapshots
AudioMixerの設定を保存することができます。また、このsnapshotを使って場面に応じたボリュームやエフェクトの設定に切り替えることができます。例えばバトル中にメニューを開いた時にメニュー系システムSEのみ聞こえる かつ BGMボリュームを下げる設定にする場合は下図のようなsnapshotを作成しておき、ゲーム内で切り替えることによって実現できます。
スクリプトでsnapshotを変更する方法は以下の2通りになります。また、方法2の weights は 0.5 に設定すると2つのsnapshotがミックスされた設定になります。
[SerializeField] AudioMixer audioMixer; // 方法2. 1秒かけて OpenMenu の snapshot へ移行する. void Example1() { var snapshotOpenMenu = audioMixer.FindSnapshot( "OpenMenu" ); snapshotOpenMenu.TransitionTo( 1f ); } // 方法2. 1秒かけて, Default > OpenMenu の Snapshot へ移行する. void Example2() { var snapShotDefault = audioMixer.FindSnapshot( "Default" ); var snapShotOpenMenu = audioMixer.FindSnapshot( "OpenMenu" ); var snapshots = new AudioMixerSnapshot[]{ snapShotDefault, snapShotOpenMenu }; var weights = new float[]{ 0.0f, 1.0f }; audioMixer.TransitionToSnapshots( snapshots, weights, 1f ); }
切り替え時の補間方法はデフォルトではLinear(線形)になっています。snapshot単位で調整したい場合は対象のsnapshotのMasterを選択 > Inspector の各項目で右クリックをすると下図のように補間方法を選択することができます。
スクリプトからボリュームを制御したい
AudioMixerのsnapshotを使わないでスクリプトからボリュームを制御する方法は以下になります。
- AudioMixerから対象Groupを選択
Inspector の Volume を右クリック >「Expose 〜」 をクリック
AudioMixer 右上にある Exposed Parameters をクリックして対象パラメータをリネーム
制御スクリプトは以下になります。
[SerializeField] AudioMixer audioMixer; void Example() { float masterVolume; audioMixer.GetFloat( "MaserVolume", out masterVolume ); masterVolume *= 0.5f // 適当にボリュームを半分にする. audioMixer.SetFloat( "MasterVolume", masterVolume ); }
ちなみにAwake()内でAudioMixer.SetFloat()を実行しても適用されません。Start()であれば問題ないです。こちらのフォーラムにも上がっていますが私が動作を確認した Unity2019.1でも修正されていませんでした・・(^_^;
まとめ
AudioClip は 用途に応じて Load Type を設定して Compression Format, Quality の設定を適切に行うのが良いでしょう。最終的にサウンドデータは数が多くなるので Presets機能 を使って自動設定ができるようにするのが良いかと思います。
AudioMixerはsnapshot機能はボリューム調整を個別に対応しなくて良いので便利ですが、ボリュームを調整したい場面が増えてくるとそれに比例してsnapshot数が増えていくので注意が必要です。
参考
【Unite Tokyo 2018】実践的なパフォーマンス分析と最適化
コンセプトと AudioMixer の概要 - Unity マニュアル
【Unity】IParticleSystemJob を使ってみた
今回は IParticleSystemJob を使ってみました。
確認バージョンは Unity2019.1.0f2 です。
はじめに
IParticleSystemJobとは、昨年くらいから何かと話題の「JobSystem」を使ってパーティクルデータの操作が出来るものです。試験的な機能なのでFix版までは今後も変更が入ってくる可能性がありますが・・
2021/05/02 追記
Unity2019.3から正式版として UnityEngine.ParticleSystemJobs に移行
実装
最もシンプルな実装はこちらにまとまっています。今回は折角なので CustomData モジュールで定義したカーブアニメーションを IParticleSystemJob から取得してカラー変更する処理を実装してみます。
以下コードです。
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Experimental.ParticleSystemJobs; public class SampleParticle : MonoBehaviour { void Awake() { ParticleSystem ps = GetComponent<ParticleSystem>(); ps.SetJob( new ParticleJob()); } struct ParticleJob : IParticleSystemJob { public void ProcessParticleSystem( ParticleSystemJobData jobData ) { Color customColor = Color.white; var startColors = jobData.startColors; var customDatas = jobData.customData1; for( int idx=0 ; idx < startColors.Length ; idx++ ) { customColor.r = customDatas.x[ idx ]; customColor.g = customDatas.y[ idx ]; customColor.b = customDatas.z[ idx ]; customColor.a = customDatas.w[ idx ]; startColors[ idx ] = customColor; } } } }
殆ど説明が必要ない短さですね(^^;)
1. IParticleSystemJob を継承した構造体を定義
2. ProcessParticleSystem() を定義
3. 引数の ParticleSystemJobData に Active状態のパーティクルデータが入ってくるので必要な更新を記述
4. 対象ParticleSystem の SetJob() にジョブを設定
実行画面はこんな感じです。
Profiler で確認すると Worker Threadで処理されてます。
Worker Thread と Main Threadで比較が出来るプロジェクトをgithubに上げてあります。
まとめ
パーティクルデータのコピーなしでデータ操作出来るのは便利です。ParticleSystemのGetParticles/SetParticles は呼び出しコストが高いのでそこが無くなるだけでも恩恵はあるかなと・・
あとフォーラムにも書いてましたが将来的に Trigger/Collisionモジュールの衝突検知用コールバックが IParticleSystem に追加されるとゲームロジックに合わせた処理を入れたりと実装の幅が広がりそうですね。
ただ、ゲームロジックが絡んでこない処理なら Custom Vertex Stream を使ってシェーダ側で処理をした方が速度が出ると思います。
参考
【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 ); } }
- Triggersモジュールを使用すると OnParticleTrigger が呼び出されます。
- インスペクタで Callback に設定した条件(Outside, Inside, Exit, Enter)ごとのパーティクルを取得するには GetTriggerParticles を使います。
- 取得したパーティクルのパラメータに変更を加えたら SetTriggerParticles で変更内容を適用してあげます。
上記のサンプルスクリプトはパーティクルのカラーを Enter時に赤色、Exit時に黄色 に変えています。
気になる点
OnParticleTrigger が毎フレーム呼ばれる
Outside のパーティクルを取得するために毎フレーム呼び出しになっているようです。しかも Triggers モジュールのチェックが有効になるだけで呼ばれてしまうところにも注意が必要です。
GetTriggerParticles / SetTriggersParticles の負荷が高い
こちらは ParticleSystem.GetParticles/SetParticles と同様にパーティクルの情報に直接アクセスする事が出来ず、一度配列にコピーした後に変更を加えて、再度データを流し込む必要があるため負荷が高くなります。
Colliderの登録が面倒
インスペクタ上から Colliders にコライダーを登録する必要があるのですが、数が多いと大変です。ParticleSystem.trigger.SetCollider() を使えばコライダーを登録する事ができるので スクリプトから制御するのも手ですね。
まとめ
パフォーマンスの面で気になるところが多い印象でした。こちらのフォーラムにあるように今後の更新で JobSystem によるパフォーマンス改善が出来ないかUnityさんの方で色々と試しているようですね。表現の幅は広がりそうなのでとても楽しみです。^_^
参考
【Unity】VideoPlayerを使ってみた
最近、Unityでの動画再生について調べる必要があったので自身の備忘録としてまとめました。
VideoPlayer
Unityの動画再生はUnity5.6から追加された VideoPlayer コンポーネントを使う必要があります。Unity5.6より前は MovieTexture を使っていましたが Unity2018.3 から廃止されてしまったので VideoPlayer 一択となりました。
設定方法
VideoPlayerで動画の再生を確認するだけであれば割と簡単です。
動画ファイルをProjectビューに配置します。
Main Camera が設定されている GameObject に VideoPlayerコンポーネントを追加
VideoPlayerコンポーネンとの Video Clip に動画ファイルを設定
Unityエディタを再生
事前読込
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】Shuriken Particle Unity2018
Unity2018以降で Shuriken Particle に追加された機能で個人的に気になったものを書いていきます。
確認バージョンは 2018.3.0f1 です。
- Ring Buffer Mode
- Orbital Velocity
- Shape : Rectangle
- Shape : MeshRenderer
- Texture Sheet Animation : FPS
- 所感
- 参考
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