神様は有休消化中です。

Unity関連の技術ネタを書いてます。

【Unity】マテリアルの描画がシェーダーのQueue順に処理されない原因と対策

自作シェーダーなどを使用してレンダリングを行う場合、レンダリング順序をTagsのQueueで指定しますが、特定の条件でこのレンダリング順序が無視される現象が発生したので共有。

簡潔にまとめだけ

まとめると
現象  :シェーダーで指定したレンダリングキューが無視されることがある
原因  :MaterialのCustom Render Queueに不正値が入っているため
発生条件:自作シェーダーを使用 & 自作シェーダー設定前に、他のシェーダーを割り当てていた場合
対策  :Custom Render Queueに-1を設定すればOK

続きを読む

【Unity】Graphicを継承したクラスでMissingReferenceExceptionが発生する

先日、Graphicを継承したクラスで何故かMissingReferenceExceptionが発生することがあったので共有。
結論から言うと、OnDisableをオーバーライドすると発生する様子。

テスト用にこんなクラスをすると、コンパイル時にMissingReferenceExceptionが発生します。

public class HogeUI : Graphic {
    protected override void OnDisable ()
    {
        /* なんらかの処理 */
    }
}

Exceptionの内容はこんな感じ。HogeUIが破棄されたのにアクセスしていますと。

MissingReferenceException: The object of type 'HogeUI' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
UnityEngine.UI.Graphic.OnRebuildRequested () (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Graphic.cs:396)
UnityEngine.UI.GraphicRebuildTracker.OnRebuildRequested () (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/GraphicRebuildTracker.cs:33)
UnityEngine.CanvasRenderer.RequestRefresh ()


おそらくGraphicクラスのOnDisableで何かしら必要な処理を行っていて、オーバーライドによって走らなくなったために起こっているのかと。

対応は以下のようにしました。

public class HogeUI : Graphic {
    protected override void OnDisable ()
    {
        base.OnDisable(); // 追加

        /* なんらかの処理 */
    }
}


Graphicクラスの関数をオーバーライドする場合は、基本的に親クラスの処理を呼び出したほうがいいのかもしれません。

【Unity】AssetBundle化したPrefabのシェーダー参照が壊れる現象

先日、AssetBundle化したPrefabのシェーダー参照が壊れる現象に遭遇したため解決策を共有。状況としてはこんな感じ。
・自作のUGUIオブジェクトにカスタムシェーダーを適用してPrefab化
・上記Prefabをシーンに追加して実行→正常動作
・上記PrefabをAssetBundleから読みこんで実行→表示が壊れる

FrameDebuggerで確認すると、シェーダー名称は適用したカスタムシェーダーの物になっているが、レンダーステートが明らかにおかしい・・・。

Google先生に聞くと、以下の記事を発見。
NGUIオブジェクトをAssetBundle化すると、シェーダー参照が壊れることがあるらしい。blog.livedoor.jp

古い情報だしNGUIだし、関係ないだろーと思いながらランタイムでシェーダーを再設定するとちゃんと表示できた。何ぞこれ。

private void Awake(){
   Material material = GetComponentInChildren<Material>();
   if(material != null){
      Shader s = Shader.Find("Custom/Hoge");
      if(s){
         material.shader = s;
      }
   }
}

ちなみに、上記のコードを実行した場合、UnitEditorと実機で適用されるシェーダーが変わる。
UnityEditor:/Assets以下に入っているカスタムシェーダー
実機:AssetBundleに入っているカスタムシェーダー
これはShader.Findの検索順に依存していると思われます。

しかし、Shader.Findでシェーダーが見つかるのに参照が壊れる理由が本当に不明。
シェーダーコンパイルやらの関係・・・?うーむ。
何か情報をもっている方がおられたら、コメント欄で教えて下さい。

【Unity】EventSystemsから受け取った座標をRectTransform.localPositionに設定する方法

uGUIのEventSystems(IBeginDragHandler, IDragHandler, IEndDragHandlerなど)から受け取った座標をそのままRectTransform.localPositionに設定すると、Canvasのscaleによってはぶっ飛んだ位置(描画領域外)に移動してしまうことがあります。
EventSystemsから渡される座標はスクリーン座標のため、scaleが影響してぶっ飛んでしまうわけですが、今回はこのぶっ飛び現象を回避するためにスクリーン座標→ローカル座標へ変換する方法を共有します。

続きを読む

【Unity5】ゆっくり動き始めて、ゆっくり止まる補間を実装する

カメラやキャラクターの移動で、以下のグラフのような補間を実装する方法を共有。ゲームで一番よく使う補間方法です。
正式名称(?)はEase-in, Ease-Outとのこと。
f:id:appleorbit:20151018205414p:plain

続きを読む

【Unity5】Visual Studio Codeを使ってデバッグする

Visuat Studio Codeを使ってデバッグするための情報が公式から出たので、試してみました。
今の所Mac OS X以外は未サポートみたいです。

環境

Mac OS X 10.10.1
・Unity 5.2.1f1
Visual Studio Code 0.8.0

やりたいこと

・UnityのエディタとしてVisual Studio Codeを使う
デバッグもしたい

続きを読む