【Unity】エディタ拡張でパフォーマンスを落とさずにScrollViewに大量の要素を表示させる

f:id:tm8r:20160713192115p:plain
特定の条件に合致するアセットのリストをEditorWindowに表示させてごにょごにょする系の拡張を作ることがちらほらあるんですけど、アセットはまあ運用すればするほど増えていくわけで、その数が数千数万になっていくと単純に表示するだけだとUnityが悲鳴を上げます。

実際、まさか一気にそこまで増えると思ってなかったとあるツールで表示はできてこそいるものの、スクロールがまるで動かんみたいな状況に陥ったので、自前でカリングする方法を考えてみます。

ようは表示領域にいない要素は描画しなければいいわけです。

まずは表示領域の高さを取得したいところですが、GUILayoutのBeginHorizontal(BeginVerticalも同様)は戻り値がvoidなので、Rectが返ってくるEditorGUILayoutの同名メソッドを使います。
次にその中に表示されるリストの各要素の高さを定義し、その時点のスクロール量に応じたリストの先頭と末尾のindexを算出できれば、あとは表示領域の高さが変わらないように、要素を描画しない領域に本来描画されるはずの高さを確保してあげれば要件が満たせそうです。

f:id:tm8r:20160713193745p:plain
実際はこんな表示になっちゃだめですが、表示領域の上下の見えない部分にこんな感じで表示領域の高さを保つためのスペースがあるイメージです。

というわけで実装した結果が以下のような感じ。

これで表示領域だけに要素が描画される形になったので、リストの要素が増えても大きくパフォーマンスが損なわれることはなくなりました。
めでたしめでたし。

【Unity】Sceneビューやカメラのレイヤー表示を切り替える

普通にGUI上からいじれますが、どうしてもスクリプトでやりたいでござる…!というときのために。

以下のようにTools.visibleLayersを編集することで実現できます。

// UIレイヤーを非表示
Tools.visibleLayers &= ~(1 << LayerMask.NameToLayer ("UI"));

// UIレイヤーを非表示にして他は表示
Tools.visibleLayers = ~(1 << LayerMask.NameToLayer ("UI"));

// UIレイヤーを表示
Tools.visibleLayers |= (1 << LayerMask.NameToLayer ("UI"));

// UIレイヤーのみ表示
Tools.visibleLayers = (1 << LayerMask.NameToLayer ("UI"));

GameViewのカメラのcullingMaskも同じように操作可能なので、その場合はTools.visibleLayersをCamera.main.cullingMaskなどに読み替えてください。

また、上のコードではLayerMask.NameToLayerを用いてレイヤーのindexを取得してますが、勿論自分でindexを指定してもよいので、その場合はレイヤーのInspectorを開けば操作対象のindexが分かります。
(「UI」でいうと「Builtin Layer 5」になっているので5を指定する形)

Everything(全レイヤーを表示)に戻したい場合は-1を代入してやればよいです。

Tools.visibleLayers = -1;

【Unity】SceneViewのカメラを特定のオブジェクトに向ける

Hierarchyでオブジェクトをダブルクリックしたときと同じ挙動をScriptから再現するやつ。

public class FocusSceneViewCamera : MonoBehaviour
{
    [SerializeField]
    GameObject focusTarget;

    void Awake ()
    {
        SceneView.onSceneGUIDelegate += InitializeSceneCamera;
    }

    void InitializeSceneCamera (SceneView sceneView)
    {
        SceneView.onSceneGUIDelegate -= InitializeSceneCamera;
        if (focusTarget != null) {
            Selection.activeGameObject = focusTarget;
            sceneView.FrameSelected ();
        }
    }
}

前述の挙動の実装が、SceneViewのFrameSelectedを叩いてるっぽいんですけど、その中でSelectionからその対象を引っ張ってきているので、SelectionのactiveGameObjectを任意のGameObjectで書き換えた上で同メソッドを叩くことで実現しています。
こちらの例はゲームプレイのタイミングで一回だけ任意のGameObjectにフォーカスしてますが、Awakeで行ってる処理を行うメソッドを用意すれば好きなタイミングで呼び出せるかと思います。

正直あんまり使いどころはないですが、SceneViewのカメラとGameViewのカメラを同期したいケースでは使えなくもなかったりします。
同期は以下のようなメソッドを上と同じようにSceneViewのonSceneGUIDelegateに登録してあげれば実現できます。

void SyncGameViewCamera (SceneView sceneView)
{
    Camera.main.transform.position = sceneView.camera.transform.position;
    Camera.main.transform.rotation = sceneView.camera.transform.rotation;
}

【Maya】作成したツールの設定を保存する

Mayaのツールを作ったものの、その設定を次回起動時も引き継ぐためにはどうしようか、jsonか、csvか、どこに保存しようか、と思ってたらどうやらoptionVarという便利メソッドがあるようで。

help.autodesk.com

import maya.cmds as cmds

saveKey='myToolWindowWidth'

# 無ければ追加
if cmds.optionVar(exists=saveKey) == False:
    cmds.optionVar(intValue=(saveKey, 300 ))

# 取得
print (cmds.optionVar(q=saveKey))

# 削除
cmds.optionVar(remove=saveKey)

という感じで使えます。
上書きは追加のときと同じ形です。

このメソッドを使って保存した内容はユーザーごとのprefsディレクトリのuserPrefs.melに保存されます
Macでいうとこのあたり。

/Users/ユーザー名/Library/Preferences/Autodesk/maya/2015-x64/ja_JP/prefs/userPrefs.mel

Mayaがぶっ壊れたときにprefsディレクトリを消すみたいな悲しいオペレーションがあったりするので、そのときは泣いてもらうほかないですが、基本的にはこれで簡単に設定の保存、読み込みができそうです。
べんり。

【Unity】Unityに出力可能なエフェクトエディタ「SPARK GEAR」

sparkgear.net
UnityとCocos-2Dxに対応しており、大量のテクスチャやエフェクトのバンドル、簡単なモデルの作成、スマホ実機にリアルタイムで変更が反映できる、などが売りの新しいエフェクトエディタ。
ドローコールの削減など、負荷削減に関する対策もされているようで、期待が高まります。

詳細は上記公式サイトと、以下のページ、スライドが参考になります。
jp.gamesindustry.biz

www.slideshare.net

スライドの最後にもある通り、現在機能制限のあるフリー版が無料配布されています。
ダウンロードは以下の公式Facebookページから。
株式会社Spark

起動にはいくつかランタイムが必要なので、zip解凍してReadmeを読みましょう。
(Readme.txtを読む文化をすっかり忘れて一人で「起動しない…!!」ってなってました)

尚、エディタはWindows専用なので、MacユーザーはVirtualBoxとかで試す感じですね。
サンプルがいくつか含まれているので、使い方がわからない場合はサンプルを見て各種設定を確認することが出来ます。

このフリー版にはSDKなどが含まれていないので、Unityでの動作確認はできなさそうです。
サイトによると、

Unity,Cocos2d-xの組み込み再生が可能。逆にUnityなどで制作したものを再利用することも可能。特にUnityではPrefab化したリソースをスクリプトからPlayするだけで組込可能。
(エンジンの依存性なし)
ランタイムを組み込むことでSPARKFXエディターで制作したアセットをiOS,Android,OSX,Windows上で再生できます。
http://sparkfx.jp/main/%E5%B9%85%E5%BA%83%E3%81%84%E4%BA%92%E6%8F%9B%E6%80%A7/

とのことなので導入は容易そうですが、実際のところは使ってみないと分からないのと、初期費用100万円+月額20万円は容易に出せない(白目)ので、一旦は今後利用者が増えてレポートが出るのを待つばかり。

【Unity】アセットの読み込みでシンボリックリンクを使う

Mayaで作業をしててFBX書き出しをしてUnity上で確認したいんだけど、FBXファイルをUnityの該当プロジェクトのAssets配下に置きたくないみたいなこと、ありませんか!
あんまりないと思いますけど、なんやかんやであったので覚書です。

ぱっと思い浮かぶのはMacならエイリアス、Windowsならショートカットだったんですけど、それぞれこれではうまくいきません。
じゃあシンボリックリンクならどうか、ということでとりあえずMacで試してみます。

まずはAssets配下にResourcesディレクトリを作成して、ここに特定のディレクトリへのシンボリックリンクを作ることにします。
ターミナルを開いて以下のような感じでコマンドを実行します。

# Resourcesに移動
cd /Users/tm8r/Documents/TestUnityProject/Assets/Resources

# シンボリックリンクを作成
ln -s /Users/tm8r/Documents/maya/projects/default/scenes scenes

これでUnityに戻ると、「/Users/tm8r/Documents/maya/projects/default/scenes」があたかも「Assets/Resources/scenes」にあるかのように振る舞ってくれるので、あとはResources.Loadとかでいつも通りファイルを扱えます。

次にWindows。Resourcesディレクトリ作成までは変わりません。
準備ができたら憎きコマンドプロンプトを起動して以下のような感じでコマンドを実行します。

# Resourcesに移動
cd C:¥Users¥tm8r¥Documents¥TestUnityProject¥Assets¥Resources

# シンボリックリンクを作成
mklink /D scenes C:¥Users¥tm8r¥Documents¥maya¥projects¥default¥scenes

「/D」はディレクトリのシンボリックリンクを作成するための引数です。

lnコマンドとターゲットとソースの引数の順番が逆なのが若干罠ですね。
これでMac同様、WindowsでもUnityでちゃんと認識されるシンボリックリンクが作成できました。わいわい。

スポンサーリンク