テラシュールブログ

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

【Unity】複数のColliderを結合するComposite Collider 2Dを使って少し遊ぶ

今回はUnity 5.6に追加されたComposite Collider 2Dについてです。

Compound Collidersという機能

Rigidbodyの下にColliderが複数ある時、実はUnityはColliderを一つにまとめて処理してくれます。これで動かす場合、MeshColliderよりも高速で動作します。

f:id:tsubaki_t1:20170222002439g:plain

こういったCompound(複合)コライダーはMeshColliderやPolygonColliderより大体高速で動作し、かつMeshCollider系の制約も殆ど受けないので色々と便利です。

 

例えば、下にMeshColliderとComposite Colliderで作成したモデルを用意してみます。

当たり判定は大体同じように作れますが、MeshColliderはCompositeColliderと比較して、単純に当たり判定の計算負荷が高くアニメーションに非対応*1、かつMeshCollider同士の当たり判定が出来ない問題があります。

そのため、単純な形状のコライダーを動かして当たり判定を作るCompoundColliderという機能があります。

f:id:tsubaki_t1:20170222221956j:plain

ちなみに、CompoundColliderはAColliderBuilderでサクっと作れます。

f:id:tsubaki_t1:20170222225404j:plain

https://www.assetstore.unity3d.com/jp/#!/content/15058

CompositeCollider2Dという機能

さて、5.6でCompoundColliderに微妙に似てますが異なる機能が追加されました。CompositeColliderなるコンポーネントです。

これは複数のCollider2D(MeshColliderとBoxColliderのような頂点ベースのコライダー)を結合し、一つのコライダーに変換する機能みたいです。

 

例えば下のように、複数のBoxColliderが同じ範囲に入ると、一つのColliderのように結合されているのが分かります。

f:id:tsubaki_t1:20170222222833g:plain

Colliderの結合は、同期(動かした時に計算?)、非同期、スクリプトからのアクセスの3タイプがあります。要するに、このメッシュ結合はランタイムで動きます。

f:id:tsubaki_t1:20170222223254j:plain

ちなみに結合コストは結構高いのか、弾幕を作り「一つのRigidbody + 一つのComposite Collider(内部に500個程のCollider)」をやってみた所、バラバラに動かしたほうが早かったです。

また、Geometry typeをOutlineに設定すると、コライダーの形状に沿ってコライダーを作成するみたいです。

f:id:tsubaki_t1:20170222223754j:plain

ダイナミック洞窟生成

この機能で思いついたのが、ダイナミック洞窟生成です。

やってる事は物凄い単純で、Geometry TypeをOutlineに設定し、あとはモノをどんどん増やしていくだけです。

下のようになります。

作り方

  1. 結合するCollider2Dの付いたGameObjectを用意する
  2. CompositeCollider2Dの付いたGameObjectを用意する
  3. 1を2の子オブジェクトとして配置
  4. 1のColliderのUse By Compositeにチェックを入れる

f:id:tsubaki_t1:20170222224642g:plain

 

後はEdge Radiusの値を調整します。小さすぎると当たり判定が貫通する事がありますし、大きすぎると凄い浮きます。

f:id:tsubaki_t1:20170222225021j:plain

後はComposite ColliderにはRigidbodyが付いてくるので、BodyTypeをStaticもしくはkinematicに設定しておきます。

f:id:tsubaki_t1:20170222225605j:plain

なんか、コレだけで何かゲームを作れそうな気がしなくもないですね。穴掘りゲーム的な。

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

*1:メッシュを作成しMeshBake等でメッシュ情報を更新しなければ当たり判定が付いてこない

【Unity】Area Lightと、Emissiveな材質を持つ発光するオブジェクトが輝けと囁く

Unityのライティングシステムの隅にひっそりと存在するArea Light(エリアライト)、その知られざる生態系について、今回は踏み込んでみようと思います。

影の表現が柔らかくなるAreaLight

AreaLightですが、マニュアルを見ても「ライトが柔らかくなる」的な事しか書いていません。

リアライトは複数の異なる方向から同時にオブジェクトを照らすので、他の種類のライトと比べてシェーディングが柔らかく繊細になります。

 細かい事は置いておいて、実際にAreaLightとDirectional Lightを比較すると、確かに影がかなり柔らかくなっています。左がAreaLight、右がDirectional Lightです。
Directional Lightはハッキリ輪郭が見えるのに対し、AreaLightは濃淡はハッキリしていますが輪郭はボヤけて見えます。

f:id:tsubaki_t1:20170206230834j:plain

広い範囲からの照射ばぼんやり、狭い範囲からの照射はハッキリ

Area Lightの挙動は2パターンのライト画像を比較すると、何となく想像が出来ます。

下にAreaLightの横幅が狭い物と広い物を用意して比較しました。狭いAreaLightは影の濃淡がハッキリと見えていますが、広いAreaLightは全体的に薄く広く広がっています。

f:id:tsubaki_t1:20170206231424j:plain

f:id:tsubaki_t1:20170206231428j:plain

実際の実装は分かりませんが、挙動としては多分こんな感じです。

AreaLightは複数の異なる方向から対象のオブジェクトを照らして、ふんわりと柔らかい影を表現してるんじゃないかなと思います。

f:id:tsubaki_t1:20170206233417j:plain

ちなみに現実も、空も光は太陽から直で来る訳ではなく大気である程度拡散してから降り注ぐ感じになると思います。それは正しいか?もっと詳しく?そんなこと俺が知るか!

AreaLightの影は静的なオブジェクトに焼く

ふわっと優しくなるAeraLightは、残念ながらリアルタイムに影を表現する事が出来ません。基本的に静的なオブジェクトに焼き、ライトマップを使用する感じで利用します。

基本的な光表現はLightProbeでダイナミックなオブジェクトに受け渡します。また、ScreenSpaceAmbientOcclusion等でAO表現や古き良き丸影を使うと、意外と馴染んで見えたりします。

f:id:tsubaki_t1:20170206235516j:plain

発光するEmissiveオブジェクト

AreaLightと似たような性質を持つ機能として、Emissiveな属性を持つマテリアル(材質)を持つオブジェクトという物があります。

例えばStandardAssetsの場合、Emissiveが設定されていて、かつLightmapのstaticが入ったオブジェクトであれば、発光します。

f:id:tsubaki_t1:20170206235902j:plain

f:id:tsubaki_t1:20170207000055j:plain

Emissiveの特性

EmissiveなオブジェクトはAreaLightと異なり、GIモードがRealtimeモードならばランタイム時に光の強度や色を変更する事が出来ます。

ただ、基本的にEnlitenのRealtime GI Resolutionベースで光源を設定しているので、Realtimeモードの場合はAreaLightと比較して光の表現が雑です。

f:id:tsubaki_t1:20170207000508g:plain

AreaLightと似たような特性

雑ではありますが、AreaLightと同様に広い範囲から照射すればフワッとした、狭い範囲から照射すれば割とハッキリとした影が表現されます。

また静的(static)なオブジェクトにしか影や光源が反映しないのも同様です。基本的に動的に動かすオブジェクトに影響を与えたい場合、Lightprobe様が大活躍します。

f:id:tsubaki_t1:20170207000916j:plain

また、マテリアルのGIモードをBakedに設定し、Final Gatherを設定すると、AreaLightと比較して殆ど見分けがつかないレベルの光が表現出来ます。

発光する範囲と形状

Emissiveなオブジェクトの優位性の一つは、テクスチャでマスクを設定したり、複雑な範囲は形状から発光出来る点です。

Emissiveな項目にテクスチャを設定すると、光が漏れないようにマスクを掛けたり、光の色にフィルターをかけるような表現が出来ます。

f:id:tsubaki_t1:20170207001837j:plain

また、マテリアル単位で光るので、複雑な…例えば蛍光灯やネオンのような表現も出来たりします。Arealightは基本的に四角で表現するので、複雑な形状を表現したい場合には若干有利です。

f:id:tsubaki_t1:20170207002727j:plain

で、どっちが良いの?

個人的にはEmissiveなオブジェクトの方が使いやすいといえば使いやすいです。

ただしRealtimeGIベースは表現が割と汚くなりやすく、しかしてBaked&FinalGatherを使用するとライトを焼くのに猛烈に時間がかかるので、その辺りがネックになります。

個人的な使い分けとしては、広範囲にやるならAreaLight、蛍光灯等の細かいパーツならEmissiveオブジェクト、輝度があまり高くなくうっすらと光る程度ならEmissiveといった感じです。

ちなみにUnity 5.6b6にProgressive Lightmapperという、「任意の範囲を優先して焼く&EmissiveをRealtimeGIベースじゃなくす」機能を持ったライティングモードが追加されるので、ある意味Emissiveの問題は回避は出来るといえば出来るようになるかもしれません。

f:id:tsubaki_t1:20170207003705g:plain

シーンビューで見てる位置を優先して、粗いライティングから収束していく感じでライトを焼いてくれます。広いマップでも見てる範囲を優先して焼いてくれるので、確認したい範囲をサクサクっと確認出来て便利

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

【Unity】コンポーネントのイベント実行順についてのTips

GameObjectにアタッチしたスクリプトの実行順番は、特に何もしなければ割とランダムです。今回はその辺りについて少し整理します。

スクリプトの実行順番

UnityはコンポーネントをGameObjectに設定すればコンポーネントに記述したイベントを呼び出してくれます。自動的に呼ばれる代表格はAwakeやOnEnable、StartやUpdate等です。

f:id:tsubaki_t1:20170204224959j:plain

若干面倒くさい事に、このコンポーネントの処理実行順は特に設定しなければ不透明…というか、どの順番で呼ばれるかは分かりません。
たとえばマネージャークラスのような物よりも先に末端のコンポーネントが先に呼ばれるといったケースも有りえます。

スクリプトの実行順を制御する

一応、スクリプトの実行順番は、Script Execution Orderのキーワードで設定する事が出来ます。

Script Execution OrderをGUIで設定

一番GUI的なのはScript Execution OrderのUIで書き換える事です。

  1. Edit > Project Settings > Script Execution Orderを開く
  2. +を押して登録したいスクリプトを選択
  3. スクリプトの実行順を設定

実行順は、上が優先度が高く下が低いです。
正確には、数値が低い方が優先されます。標準のコンポーネントは実行順は0です。

f:id:tsubaki_t1:20170204225757j:plain

f:id:tsubaki_t1:20170204225802j:plain

なお、一覧表示中にコンポーネント頭文字のキーを押すと、該当のスクリプトまで選択がジャンプします。一つしか無い場合はその瞬間に選択が確定します。

f:id:tsubaki_t1:20170204230454g:plain

メタデータに直接書き込む

スクリプトの量が多くなってくると、Script Execution Orderでは設定が面倒くさくなってきます。そんな時の力技は.metaを直接書き換えてしまうアプローチがあります。

Script Execution Orderの情報は各スクリプトメタデータに有ります。

metaを開いて、  executionOrderの指定する数値を書き換えます。無ければ追加します。

スクリプト単位で書き込めるので、手軽といえば手軽に設定できます。

f:id:tsubaki_t1:20170204231106j:plain

f:id:tsubaki_t1:20170204231147j:plain

DefaultExecutionOrderを使用

一方、スクリプト側から設定する方法も(多分)5.5辺りから追加されてるっぽいです。*1

コンポーネントのAttributeとして設定すると、指定のコンポーネントの実行順を制御します。またScript Execution Orderと同様、数値が低い方が優先され、標準コンポーネントの実行順は0です。

なおScript Execution Orderが優先されます。

f:id:tsubaki_t1:20170204231704j:plain

イベントの実行順

イベントの実行順ですが、Unity - マニュアル: イベント関数の実行順に絵付きで分かりやすく書いてあります。

要するに、

  1. Awake
  2. OnEnable
  3. Start
  4. Update

の順で呼ばれます。但し、StartとUpdateはインスタンス化直後ではなく、スタートのタイミングで呼ばれます。

 

  • Awake
    (シーンに配置orAddComponent直後
     GameObjectがActive時)
  • OnEnable
    (シーンに配置orAddComponent直後
     ComponentがEnable時)
  • Start
    (他のStartと同時)
  • Update
    (他のUpdateと同時)

つまりコンポーネントやオブジェクトを生成したタイミングで即座にAwake→OnEnableが呼ばれ、他の全てのAwakeとOnEnableが呼ばれた後にStartが呼ばれ始めます。

OnEnableとAwakeの違い

一見一気に呼ばれるAwakeとOnEnableですが、よく見ると若干挙動が異なります。

Awake: この関数は常に Start 関数の前およびプレハブのインスタンス化直後に呼び出されます。(もしゲームオブジェクトがスタートアップ時に無効である場合、有効化にされるまで Awake は呼び出されません。)
OnEnable: (オブジェクトがアクティブな場合にのみ呼び出されます): この関数は、オブジェクトを有効にした直後に呼び出されます。例えば、MonoBehaviour インスタンスが作成されたとき、レベルロードあるいはスクリプトコンポーネントのアタッチされたゲームオブジェクトがインスタンス化されたときに実行します。

要するに、

Awake:

OnEnable:

つまりGameObjectのインスタンス化後、コンポーネントがdisableでもAwakeは呼ばれ、enable時にOnEnableが呼ばれるという事です。

f:id:tsubaki_t1:20170205220200g:plain

これを上手く使えば、階層の有るPrefabのような場合、GameObjectのアクティブ/非アクティブやコンポーネントのenable/disableを上手く使うと、先に全てのAwakeを実行してからOnEnableを実行するといった事も出来なくは無いかもしれません。

ScriptableObjectのOnEnableは、大抵Awakeより先に呼ばれる

ScriptableObjectをシリアライズしている場合、参照先のScriptableObjectのOnEnableが呼ばれるタイミングは、他のAwakeよりも早いです。

  • シーンに参照があれば、まず呼ばれる
  • シーンが参照するPrefabから参照されていたら呼ばれる
  • Instantiateで生成する前に参照を辿って呼ばれる
  • PreloadAssetsに登録されていればシーン読み込む前に呼ばれる

ただし、エディターで操作中に意図せずOnEnableが呼ばれる事もあります。

tsubakit1.hateblo.jp

 Execution Orderが効かないケース

残念ながら、Execution Orderが効かないケースもあります。

と言うより、Execution Orderはどうも「生成時にコンポーネント呼出順を並べる機能」っぽく、逐次生成すると効果を発揮しないみたいです。
なので、下のような現象が発生します。

コンポーネントやオブジェクトを動的に追加した場合は、生成順になる

動的にコンポーネントを生成した場合、コンポーネントの実行順は(StartやUpdate等も)オブジェクトの生成順になります。

例えば下のようなコードが合った場合、Execution Orderを設定してもStartやUpdateの呼出順はScript1が先、Script2が後になります。

f:id:tsubaki_t1:20170204234348j:plain

同様に、これがGameObjectの生成であった場合も、先に生成されたGameObjectのStart、Updateが優先されます。

Script2がScript1より優先的に実行される状況を作っても、Script1がアタッチされているオブジェクトを先に生成すれば、StartはScript1が先に呼ばれます。

f:id:tsubaki_t1:20170204234944j:plain

f:id:tsubaki_t1:20170204235139j:plain

しかし”同時に”生成した場合は、Script Execution Order準拠

この生成した場合のルールですが、複数のコンポーネントがアタッチしているやPrefabの子オブジェクトにアタッチされているといった状況で、一気に複数のオブジェクトを生成出来る場合、Execution Orderが適応されます。

f:id:tsubaki_t1:20170204235802j:plain

f:id:tsubaki_t1:20170204235811j:plain

f:id:tsubaki_t1:20170205000016j:plain

関連

旧記事

tsubakit1.hateblo.jp

docs.unity3d.com

tsubakit1.hateblo.jp

*1:何故多分かと言えば、マニュアルに書いて無いからです。自分も5.6の新しいNavmesh機能のサンプル(ランタイムにNavmeshを構築するやつ)に使われてた時に気づきました。

【Unity】Statemachinebehaviourの処理の実行順について

f:id:tsubaki_t1:20170202234325j:plain

Statemachinebehaviourをステートに貼り付けた際、Statemachinebehaviourはどのような順番で呼ばれるのか。

確認してみました。

Statemachinebehaviourを呼ばれる順番

ルールは、どうも下の通りっぽいです。

  • 親ステートが子ステートよりも先に呼ばれる
  • 上に配置したStatemachinebehaviourが下のStatemachinebehaviourより先に呼ばれる
  • 上にあるレイヤーが下にあるレイヤーより先に呼ばれる

f:id:tsubaki_t1:20170203002806j:plain

SubStateMachineのStatemachinebehaviour

意外と気づいてない人も居るかもしれませんが、SubStateMachineにもStatemachinebehaviourを設定する事が出来ます。

f:id:tsubaki_t1:20170202235609j:plain

その場合、OnStateMachineEnterが「SubStateMachineに到達した時に呼ばれる処理」で、「OnStateEnter」が子ステートマシンで変化が合った際に呼ばれます。

たとえば下のような図のステートとStatemachinebehaviourが合った場合、OnStateEnterはNewStateとHumanoidWalkが切り替わる度に、OnStateMachineEnterはトリガー「何らかの条件」が呼ばれ、AnyStateからStateMachineに切り替わる度に呼ばれます。

f:id:tsubaki_t1:20170203000910j:plain

f:id:tsubaki_t1:20170203001059j:plain

またSubStateMachineの子が現在のステートの場合、OnStateUpdateは常に呼ばれ続けます。

関連

unity3d.com

tsubakit1.hateblo.jp