テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】Position as UV1…とは

f:id:tsubaki_t1:20170810212027j:plain

少し話題に登ったので、書いておきます。書かないと忘れる

Position as UV1とは何ぞや

f:id:tsubaki_t1:20170810212235j:plain

Position as UV1というコンポーネントがあります。この謎コンポーネントは太古の昔(UIが作られたUnity 4.6系)から存在し、我々を見守ってきました。

 

で、コレは要するに何かとマニュアルを見てみますが、今ひとつ要領を得ません。

(原文)This adds a simple Position as UV1 effect to text and image graphics.

(訳)Text や Image グラフィックにシンプルな Position as UV1 エフェクトを付加します。

Position as UV1は、UIに頂点情報を流し込むコンポーネント

で、Position as UV1とは何ぞやと言えば、要するにUIにUV1の情報を流し込むモノです。これに対応するシェーダーを使用すると、UVのサイズとは別に模様を使用したり出来ます。

例えば下のようなレイアウトのUIがあります。二つのUIがあり、大きさが異なります。このUIに一定間隔で穴を開けようと思います。

f:id:tsubaki_t1:20170810214409j:plain

これにUV0で穴を開けようと思った場合、大きさが異なるので穴の大きさも異なってしまいます。

f:id:tsubaki_t1:20170810214520j:plain

これをPosition as UV1を利用して模様を付けると、UIの大きさに関わらず一定の大きさ・間隔で穴を空けてくれる訳です。

f:id:tsubaki_t1:20170810214622j:plain

動かしてみると分かりやすいかもしれません。

f:id:tsubaki_t1:20170810214826g:plain

実際にやってみる

CanvasのAdd Shader ChannelでTexcoord1を追加します。

f:id:tsubaki_t1:20170810215140j:plain

シェーダーを用意して、Materialに設定します(今回はUV1Sample)

gist.github.com

f:id:tsubaki_t1:20170810215639j:plain

後はマテリアルをUIに登録して、Position as UV1を追加します。

f:id:tsubaki_t1:20170810215842j:plain

 

で、何の役に立つの?

知らん、そんな事は俺の管轄外だ

 

関連

実装

Unity-Technologies / UI / source / UnityEngine.UI / UI / Core / VertexModifiers / PositionAsUV1.cs — Bitbucket

【Unity】AnimationControllerからTimelineへのアニメーション切替を目立たなくする

今回はTimelineを再生する際に、アニメーションの切替が一瞬で切り替わってしまう問題の対策についてです。

Timelineを使用するとアニメーションが一瞬で切り替わってしまう

Timelineをキャラクターに流し込んだ際、キャラクターのアニメーションがバツっと一瞬で切り替わってしまう事があります。

例えばダッシュモーション(AnimationController)からジャンプ(timeline)に切り替えると、こんな感じで動作します。アニメーションの切替がいきなり行われてるのが分かります。

f:id:tsubaki_t1:20170810075652g:plain

Timelineの入りと出でフェードする

この問題を解決するには、Timelineの最初のクリップにEase In Duration、最後のクリップにEase Out Durationを設定します。

この時間でAnimationControllerとTimelineでフェードを行います。

f:id:tsubaki_t1:20170810075912j:plain

f:id:tsubaki_t1:20170810075929j:plain

f:id:tsubaki_t1:20170810075444g:plain

 

これなら、ちょっとしたアニメーションの再生(例えばRPG戦闘シーンでのスキル発動や、特定ギミックの発動、死亡アニメーション等々)はTimelineで流し込むといった事ができそうです。

【Unity】動作が完結してるアニメーションを分割する

例えばジャンプアニメーション等、AssetStoreから入手したアセットのアニメーションが繋がっている事があります。

そういった時に、アニメーションを分割するアプローチについてです。

繋がっているアニメーション

ジャンプ等のアニメーションは、繋がっていない場合と繋がっている場合があります。これは単純に用途の問題で、

  • 繋がっている場合:MatchTarget等で段差を飛び越える等の、固定で動く移動
  • 分かれている場合:ジャンプモーション等に使用する

といった感じでしょう。

f:id:tsubaki_t1:20170807233650g:plain

固定移動の場合は繋がっている方が、シーケンスの制御が楽で良いのですが、ジャンプ中といった場合はそうはなりません。
オブジェクトの晒されている状況に応じて適当なアニメーションを割り当てる必要があります。
例えばジャンプアニメーションの流れは下のようなモノになると思いますが、

  1. ジャンプ開始
  2. ジャンプ上昇中
  3. ジャンプ中
  4. ジャンプ下降中
  5. 着地

アクションゲームではジャンプ開始は固定でも、ジャンプ上昇時間やジャンプ下降時間は可変である事が予想されます。

アニメーションを分割する

繋がっているアニメーションで可変するアニメーションを表現するのは面倒です。なので、単純にアニメーションを複数のAnimationClipに分割し、Mecanimのステートで制御可能にしてしまいます。

 

分割…と書きましたが、アニメーションを分割して3つのアニメーションにする等では無く、短いアニメーションを作るといった流れが正しいです。

作業の流れ

Modelを選択してAnimationImporterを開きます。

f:id:tsubaki_t1:20170807234836j:plain

後は+を押して新しいAnimationClipを生成、範囲を絞ってアニメーションの一部を取り出します。例えばJamping@loopは170.0~238.0の間のアニメーションなので、そこからジャンプ開始・ジャンプ上昇中・ジャンプ中・ジャンプ下降中・着地を取り出す訳です。

f:id:tsubaki_t1:20170807234648j:plain

f:id:tsubaki_t1:20170807235031g:plain

docs.unity3d.com

関連

tsubakit1.hateblo.jp

【Unity】PrefabにScriptableObjectを格納する

f:id:tsubaki_t1:20170803233437j:plain

今回はPrefabにScriptableObjectを格納する話です。

ScriptableObjectを使うと何が良いの?

Prefabをインスタンス化する場合、コンポーネントの複製が行われます。もしインスタンス化したPrefabのパラメータが殆ど変更無い場合は、これは非常に無駄になります。

例えばEnemyというPrefabを作成し、EnemyStateコンポーネントには以下のようなデータが大量にあったとします。

  • 敵の名前
  • パラメータ
  • スキル一覧
  • アニメーション一覧

そういった場合、オブジェクトをインスタンス化する度に、コンポーネントはこれらのパラメータを格納するメモリを要求します。また、パラメータの流し込みコスト(地味に重い)が発生します。
あと開放コストも地味に増えます。DestroyやUnloadが妙に重い場合は、単純に数が多すぎたり、パラメータが多すぎたりするのを直すと、治ったりします。

f:id:tsubaki_t1:20170803235036j:plain

コレを回避する最も手っ取り早い方法がScriptableObjectにパラメータを退避する事です。Prefabは一つのScriptableObjectを参照し、Prefabからインスタンス化したオブジェクトは一つのScriptableObjectを参照する。
これならばロードコストもパラメータのメモリ消費も1回で済みます。

f:id:tsubaki_t1:20170804000226j:plain

ただ、ScriptableObjectを生成するとプロジェクトが散らかります。1Prefab 1ScriptableObjectと考えても、Prefabが100体になると管理が煩雑になる事が予想されます。

f:id:tsubaki_t1:20170804000110j:plain

SriptableObjectをPrefabに格納してしまおう

指定Prefabしか使わないのに別にScriptableObjectを用意すると色々と管理が面倒そうなので、Prefab内にScriptableObjectを格納してしまいます。

こんな感じに。

f:id:tsubaki_t1:20170804000930j:plain

f:id:tsubaki_t1:20170804083402j:plain

サンプル

サンプルコードでは、PrefabのコンテキストメニューからAddを足すとScriptableObjectが追加され、Removeすると破棄されます。

このPrefabから生成したインスタンスは全てPrefabに格納したScriptableObjectを参照している感じです。

f:id:tsubaki_t1:20170804001523g:plain

gist.github.com

 

f:id:tsubaki_t1:20170804000433j:plain

Tips

  • Prefabかどうかの判定は、 PrefabUtility.GetPrefabTypeが楽です。
  • Prefab内のオブジェクトを取り出すのはAssetDatabase.LoadAllAssetsAtPathです。
  • Prefabの中に格納したScriptableObjectのOnEnableはPrefabを参照していると自動で呼ばれます。