テラシュールブログ

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

【Unity】アニメーションと物理演算を連動させる 5.6以降

以前、アニメーションと物理演算を連動させる方法について紹介しましたが、Unity 5.6でもっとシンプルになりました。

tsubakit1.hateblo.jp

Animate Physicsなる機能

Unity 5.6のアップグレードガイドを眺めていると、少し気になる項目がありました。

docs.unity3d.com

Animate Physics: Rigidbodies attached to objects where the Animator has Animate Physics selected now have velocities applied to them when animated. This will give correct physical interactions with other physics objects, and bring the Animator in line with the behaviour of objects animated by the Animation Component.

This will affect how your animated Rigidbodies interact with other Rigidbodies (the Rigidbodies are moved instead of teleported every frame), so make sure to verify that your Animators with Animate Physics are behaving as you expect.

 

つまり、どういうことだってばよ

アニメーションの動きを物理演算で動くオブジェクトに伝える

どうも、アニメーションの動きを物理演算に伝える機能のようです。

例えば、下のように「上に急速に動く」地面の上に物を載せると、放り投げられたようにキャラクターが上にすっ飛びます。

この動きは、明らかに「テレポート」で動いておらず、確実に動きを追随してるように見えます。

f:id:tsubaki_t1:20170403220811g:plain

同様に、動いているプラットフォームの上に物を乗っけてみます。ちゃんと乗れば上手く運んでくれました。

f:id:tsubaki_t1:20170403221145g:plain

もちろん3Dでも動作します。

f:id:tsubaki_t1:20170403221922g:plain

やり方

やり方は簡単です。

  1. Animatorコンポーネントを追加する
  2. Animatorコンポーネントの子、もしくは同オブジェクトにRigidbodyを付ける
  3. Update modeをAnimate Physicsに設定する

f:id:tsubaki_t1:20170403222155j:plain

重要なのは、Animatorが動かすものにRigidbodyが付いている事と、Update ModeがAnimate Physicsになっている事です。

これで自由にモデルを放り投げる事ができそうです。

念願の動く床のプラットフォームゲームが出来ない

さて、これで動く床が出来そうに思いますが、実際自分もソレを夢見てましたが、そうは問屋がおろしませんでした。

物理演算の値を受けているハズなのに、明らかに滑っていきます。

f:id:tsubaki_t1:20170403223010g:plain

それもその筈で、Unityが標準で提供しているPlatformarCharacter2DやThirdPersonCharacterのコンポーネントは、RigidbodyのVelocityを上書きする事で移動しています。
このため、Animate Physicsがいくら値を設定しても上書きされ、滑ってしまうという訳です。

 

逆を言えば、ちゃんとRigidbodyの値を使っていれば物の上に乗れるという訳です。

例えば、適当ですが下のようにVelocityを残してやれば、プラットフォームに乗って動くようになります。

f:id:tsubaki_t1:20170403224206j:plain

f:id:tsubaki_t1:20170403224004g:plain

ただ、加速度が移動について回ってしまうので、2Dであって欲しい「キビキビした動き」は失われますので、その辺りも含めて調整する必要がありそうです。

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

【Unity】「Unity5.6のわりと地雷なバグ」についての補足

 

 

下で紹介された内容は、
どちらも解決したみたいです。
*1

 

 

madnesslabo.net

先日リリースされた「Unity 5.6」について、幾つか地雷なバグがあるそうなので見てみましたが、内容が少し気になったので調べてみました。

AddComponentでImageを足した際に、OnDisable→OnEnableが呼ばれる

これはKnown Issueにある通り、発生します。

UI: Adding UI elements via script causes OnDisable and OnEnable to be called on all scripts in the hierarchy if a RectTransform needs to be added. Workaround is to add a RectTransform component in the new GameObject call, for example: new GameObject("Canvas", typeof(RectTransform));. (882791)

 

これは正確には、以下の条件で発生します。

  • GameObjectを「new GameObject("name")」のAPIで、GameObjectを動的に生成する
  • RectTransformを要求するコンポーネントを AddComponentで追加する
    (例えばImageやButton等)

 

上の条件で、GameObjectに設定されていたTransformをRectTransformに変換する処理が走り、その際にOnDisable->OnEnableが呼ばれるみたいです。

特に破棄系の初期化処理を記述していた場合、ややこしい問題です。

 

Prefabを置くタイプなら問題ない

つまり、AddComponentを使用しなければ起こりませんし、AddComponentを使用した場合でもRectTransformが既にあれば初期化は発生しないという事みたいです。

 

例えばPrefabを置くタイプのように、既にRectTransformが設定されているオブジェクトを取得し生成する場合、今回紹介するような不具合は発生しないみたいです。

 

AddComponentは遅い

ちなみに、意外と知られていないようですがAddComponentは非常に遅いAPIです。

例えば下のように、GameObjectの生成に600ms近くかかった場合、その400msはAddComponentの処理時間です。

f:id:tsubaki_t1:20170402235555j:plain

実際、GameObjectに3つのコンポーネントを付けたオブジェクトを300個作った場合と、Prefabで読み出した場合では、Prefabから複製した方が早いです。

バグ環境下でAddComponentしたコ犯人ンポーネントを見つける

今回の不具合でどのコンポーネントがAddComponentやってるかを見つける方法です。下のコードをRootのCanvasに貼り付けると、AddComponentしたオブジェクトをスタックトレースで追えます。

gist.github.com

f:id:tsubaki_t1:20170403000720j:plain

上の画像では、SomコンポーネントのStartメソッド16行目でAddComponentが行われています。

 

コルーチンが止まる…というよりはリセットするコードが呼ばれる可能性がある

さて、今回の不具合に「コルーチンが止まるという」という情報が含まれていますが、これは補足が必要です。

 

コルーチンを止めるアイディアは以下の3つです。

  • StopCoroutineを実行
  • GameObjectを破棄する
  • GameObjectを非アクティブにする

今回の不具合ではこの条件を満たせないですし、実際試した感じ止まらなかったので、これが直接的な要因ではないと思われます。

むしろ、OnDisableにコルーチン停止コードが含まれていた場合にコルーチンを停止、直後にOnEnableに記述したコルーチン起動コードで再起動という流れが出来てしまうのが問題なんだと思います。

 

再度確認したところ、GameObjectが一旦非アクティブになるみたいです。ので、コルーチンは止まります。

 

まぁ、下のような中断に対応したコルーチンなら大丈夫だと思いますが、中断に対応していないコルーチンでは問題が起こるかもしれません。

gist.github.com

 

Canvas入れ子で入力が利かなくなる、はGraphicsRaycasterが無い為

Canvas入れ子で使っていると、アクティブのオン・オフを切り替えると入力が利かなくなる」ですが、これは正しい動作だったと認識しています。

というか、確かCanvas入れ子にしたい場合、Graphics RaycasterをCanvas毎に設定する必要があったはずで、むしろアクティブを切り替える等以前に何故反応するのかという気がしなくもないです(実際、エディターで確認すると反応したりしなかったりします)

f:id:tsubaki_t1:20170403001509j:plain

パっと見気づきにくい挙動なので、もしかしたら修正されるかもしれませんが、果たして。

 

一応、入れ子Canvasを設定した状態でのボタンは、エディター上なら動作(何故か)する事がありますが、ビルドしたコンテンツではGraphics Raycasterが無いと反応しなかったと記憶しています。

 

感想

5.6でまだ治ってない、 AddComponentとRectTransformのバグについてでした。

修正と回避策自体は非常にシンプルですが、DLLにコンパイル済みのコードやAssetStoreから提供されている他の人が作ったコード等、修正しにくいプロジェクトがあるのも事実です。趣味でやってる場合この不具合が怖いなら待つのは正しい選択かもしれません。

関連

tsubakit1.hateblo.jp

madnesslabo.net

speakerdeck.com

*1:Graphics Raycasterで毎回全Graphicsを精査するのは凄い無駄だと思うんですけどね…

【Unity】WebGLとWebAssembly

f:id:tsubaki_t1:20170331231028j:plain

WebAssembly

先日Google ChromeFirefoxがWebAssemblyに対応しました。

この素晴らしいニュースではFirefoxが対応したのは当然として、世界で圧倒的にユーザー数の多いGoogle Chromeも対応したという事です。

dev.classmethod.jp

Android環境でも「多分動かない」から「もしかしたら…動く…?」へ

また、アナウンスは気づかなかったですがAndroid版のFirefoxがWebAssemblyに対応した事で、パフォーマンス及びメモリ関連における問題がかなり取っ払われました。

お陰で、モバイルでWebGLをちゃんと動かすのが「多分動かない」から「もしかしたら動くかも」にまで行けるかもしれません。

iOSは全滅

 ちなみにiOS周りは全滅です。どのブラウザでも動作はガクガクで、ちょっとでも大きい物は起動せんしガンダム

 

PCではFirefox素晴らしい出来。Chromeは…

ChromeFirefox、それとSafariのパフォーマンスを比較してみます。

期待ではFirefoxが最速としてChrome、その後Safariといった順で続くかと思っていましたが、実際続いてはいましたがChromeがびっくりするぐらい遅いです。

 Android Firefoxでも動くような軽量最適化コンテンツを流し込んだ時など、その差にビックリです。

これがFirefoxが異常なのかChromeが遅いのかはまだ判断出来ませんが、出来れば早くなって貰いたい所です。

 

WebAssemblyを試す

たしか5.5辺りから、WebGLの項目にWebAssemblyのチェックボックスが追加されました。このチェックボックスを設定すると、WebAssemblyを使用したゲームがビルドされます。アセンブリを直接書いたりする必要もなく、チェック入れてビルドしたらWebAssemblyが出ます。S式は要りません

asm.jsも同時にビルドし同フォルダに配置されるっぽいです。WebAssembly非対応ブラウザならasm.jsが動作します。

f:id:tsubaki_t1:20170331232920j:plain

ただasm.jsはwebassemblyと比較して消費メモリはかなり多いです。webgl memory sizeを気にすると、どちらかに注目するのが正しい選択に見えます。

 

動作するのはFirefox 52とChrome 57以降です。それ以前の場合は設定で利用可能にする必要があったと記憶しています。

モバイルで動作させる

動くかどうかは置いておいて、モバイルでUnity のWebGLを動かそうとすると、下のようなダイアログが表示されます。

f:id:tsubaki_t1:20170331234215j:plain

Please note that Unity WebGL is not currently supported on mobiles. Please OK if you wish to continue anyway.

この内容をGoogle Chrome(自動翻訳機能付き)で見ると、こんな感じです。

f:id:tsubaki_t1:20170331234324j:plain

とにかく続行すればコンテンツが(動くかは置いといて)開始しますが、この不安を煽るダイアログは出来れば避けたい所です。

 

モバイルはまだサポートしてない旨のダイアログを無視する

ので、取っ払います。

やり方は簡単、WebGL向けに出力したフォルダのBuildフォルダ以下にUnityLoader.jsなる物があります。

f:id:tsubaki_t1:20170331234629j:plain

これの

UnityLoader.SystemInfo.hasWebGL?UnityLoader.SystemInfo.mobile?e.popup("Please note that Unity WebGL is not currently supported on mobiles. Press OK if you wish to continue anyway.",[{text:"OK",callback:t}]):["Firefox","Chrome","Safari"].indexOf(UnityLoader.SystemInfo.browser)==-1?e.popup("Please note that your browser is not currently supported for this Unity WebGL content. Press OK if you wish to continue anyway.",[{text:"OK",callback:t}]):t():e.popup("Your browser does not support WebGL",[{text:"OK",callback:r}])

t();

に置換するだけです。要するにダイアログ出してる所を大雑把に消しました。

色々と問題はあるかもしれませんが、これでとりあえずダイアログは出ません。

感想

とりあえず割とマトモに動作するようになってきたWebGLですが、まだ問題は色々とありそうです。

例えばTexture、StandaloneはCrunch Compressionが使えますがMobile環境で動くかは自分は知りません。モバイルに持っていくなら、ETC2のようなフォーマットに変換できるようなっていないとメモリが厳しいかもしれません。

 

f:id:tsubaki_t1:20170331235448j:plain

 

また、 AppleGoogleにとってはモバイルアプリはドル箱です。 このままGoogle PlayApp Storeのからブラウザに移行してしまうと、折角構築したプラットフォームが駄目になってしまいます。

ので、課金周りや動作周りで何らかの縛りを付けてくるような事も、可能性としてはあるかもしれません。

どちらにしろモバイル環境ではiOS/Androidのコンパチ、PCではChromeがマトモに動くようになったらの話です。

 

Shader頑張った系の表現特化コンテンツだけではなく、ゲームも頑張って欲しい所です。

関連

blogs.unity3d.co

blogs.unity3d.com

blogs.unity3d.com

ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう

【Unity】AssetBundleに格納したSceneやPrefabがピンクになる問題

f:id:tsubaki_t1:20170330000555j:plain

AssetBundleにモデルを格納した時、モデルのマテリアルがユニークなシェーダーを使用しているとモデルがピンクになる事があります。

今回はその原因と対策についてです。

モデルがピンクになるという事

Unityでモデルを生成した時、条件によっては伝統的なピンク色になる事があります。

f:id:tsubaki_t1:20170330001125j:plain

この現象を発生させるためには、モデル表現に使用するMaterialや、Materialが使用するShaderの参照が見つからない(missing)状態や、シェーダーが動作しない場合*1等があります。

要するに、下のいずれかのケースでモデルがピンク色になります。

  • Shaderへの参照が外れた
  • Shaderにエラーがある
  • Shaderが動作しない(環境依存)
  • Materialが無い(missing)
  • Unlit/Colorシェーダーで(R:1, G:0, B:1,A:1)を指定している

f:id:tsubaki_t1:20170330021334j:plain

ちなみに、このピンクはInternalErrorShaderっぽいですが上書き方法が分からないので、細かい事は置いておきます。

AssetBundleに格納したSceneやModelがピンクになる

さて、今回の内容ですが、AssetBundleに格納したモデル(PrefabやSceneからの参照)を表現する際、独自のシェーダーを使用しているモデルがピンク色になるという現象が確認出来る事があります。

下の画像の場合、Lit Outline のシェーダーを使用してAndroid向けにAssetBundle化した物をUnity エディターで展開した場合です。見事にLit Outlineのモデルがピンク色です。

f:id:tsubaki_t1:20170330003118j:plain

なお、この問題はエディターでのみ発生します。

問題の原因は、グラフィックAPIが異なる事

この問題ですが、ピンク色になる原因は「Shaderが動作しない」です。

 

Unityエディタは、初期設定ではWindowsならDirect X11OSXならOpenGLCore*2で動作しています。

f:id:tsubaki_t1:20170330004250j:plain

逆にAssetBundleに格納されているシェーダーは、iOS/Android向けに出力した場合 OpenGLES2/3やMetalといった物向けのシェーダーが、(5.5以降はバイナリに変換され)格納されます。

 

要するに、レンダラーとシェーダーのGraphics APIが異なります

結果としてAssetBundleから取得したシェーダーは読込に失敗し、ピンク色になります。*3

解決方法1:Graphics APIを対象プラットフォームに合わせる

問題はエディターのレンダラーが使用してるGraphics APIとAssetBundleに格納したシェーダーが使用するGraphics APIが異なり読めない事なので、解決方法は簡単です。Grahipcs APIを一致させれば良いのです。

 

Unity エディターのGraphics APIは(特に指定が無ければ)Standalone設定と一致するので、Grahpcis APIを読み込みたいAssetBundleが使用しているGraphics APIと合わせます。

これでエディターで読み込んだ場合も、モデルがピンクになる事は回避出来ます。

f:id:tsubaki_t1:20170330005630j:plain

f:id:tsubaki_t1:20170330010622j:plain

ただし、(例えば LightmapのRealtime GI等)任意のCPU向けに最適化されていて読めないデータ等もあるので、エディターのGraphics APIを合わせるよりは、エディターで動作確認する際にはStandalone向けにAssetBundleを出すほうが健全といえば健全に見えます。

解決法2:Shaderを実行時に差し替える(非推奨)

Googleで検索したときによくヒットする回避方法が、シェーダーを実行時に差し替える方法です。これはエディターのみ効果があり、実行時に使用されている場合には無駄なパフォーマンス浪費となります。

 

例えば下のようなコードをシーンやPrefabに登録しておき、実行時にマテリアルのシェーダーをリロードしてやります。

gist.github.com

この動作は、マテリアルが参照しているシェーダーを、エディターが保持しているStandalone向けのシェーダーに差し替えてやるという事です。

 

その為、AssetBundle化後にシェーダー内容を書き換えると、書き換えた内容が使用されるのが確認出来ます。下の図では、Lit outlineのシェーダーをAssetBundleに出力した後、シェーダーの中身をDefuseに差し替えてエディターで動作確認したものです。見事にシェーダーがDefuseに差し替えられています。

f:id:tsubaki_t1:20170330014115j:plain

またアプリケーションにこの機構が含まれていると、シーンに余計なデータが含まれデシリアライズコストが上がり、ついでにシェーダー検索の余計なコストも増加します。

 

とは言え、ゲームの構造によってはMaterialの数は殆ど無くAssetBundleのビルドコストが超高いというケースもあります。そういった場合はStandalone向けをビルドするよりは、シェーダー差し替えを行う方が開発工数的には楽になるかもしれません。

(一応、ビルドコストを下げる為に、Standalone向けとMobile向けのシェーダーを用意しVariantで差し替える手法も使えなくはないですが、ワークフローが複雑です)

 

tsubakit1.hateblo.jp

解決法3:AssetBundleシミュレーター

個人的には、この手法でやるよりはAssetBundle シミュレーターのような手法で動作検証するほうが良いような気もします。

勿論、あくまで「シミュレーター」なので実際の動作と異なるかもしれませんが、それはPCシェーダーもどっこいなので。

tsubakit1.hateblo.jp

シミュレーター自作が面倒ならAssetBundleManagerを使うのも手です。
ただし、こちらは自動でAssetBundleを開放する範囲が広いので、日本のUnityユーザーがよく使うような「AssetBundle読んで即開放」みたいな使い方をする場合は、一部のプラットフォームで問題が出るかもしれません。
(ロード時参照があるAssetBundleをロードし、開放時に非参照のAssetBundleは全て開放されてしまう。つまり、単一のAssetBundleのヘッダーが何度も展開・開放される危険があるかもしれない)

tsubakit1.hateblo.jp

関連

appleorbit.hatenablog.com

naochang | AssetBundle化したShaderが外れてしまう

 

tsubakit1.hateblo.jp

*1:Graphics APIが非対応やエラーがある

*2:5.6はMetal

*3:マニュアルに依ると、OpenGLCoreはOpenGLES2を読めるハズではありますが、読めませんでした