ユーセンブログ

ゲーム開発に関することをたまに書きます

【Unity】ViveのHandTracking SDKのサンプルをVive Proで試してみる

はじめに

Viveのカメラを使ったHandTackingのSDKが公開されました。 細かい説明は3/19のGDCで説明があると思うのですが、とりあえず試してみたいということでサンプルを落として動かしてみたのでまとめます。

community.viveport.com

動作環境

  • Unity 2018.3.8f1
  • GeForce Game Ready Driver 419.35
  • Vive Pro

手順

SDKの準備

まずはHandTrackingのSDKをこちらのページからダウンロードします。ViveProかつUnityの場合以外は上のResorcesタブから該当のSDKを落としてきてください。 developer.vive.com

Unityの設定

ダウンロードしたファイルの中に”Hand Tracking SDK Unity Sample.unitypackage”と"Hand Tracking SDK Unity.unitypackage"が入っているのでこれをUnityにインポートします。 その後、Package ManagerからOpenVR Pluginをインポートして、XR SettingsのVirtual Reality Supportedをオンにしてください。 これでUnity側の準備は完了です。しかし、このままVive ProをつなげてもVive Proのカメラが有効になっていないためハンドトラッキングをすることはできません。

Vive Proのカメラを有効にする

カメラを有効にするためには、Steam VRの設定>カメラから"カメラを有効にする"を選択して有効化してください。 カメラを有効化することができたら一度Steamを再起動してカメラのウィンドウからカメラレートのテストでカメラが動いているかを確認してください。 無事にカメラが動いているようでしたら準備は完了になります。 f:id:k_tachiban:20190318170445p:plain

動かす

これで準備は一通り終わったので次はサンプルを動かしてみます。 Aristoフォルダ内にあるSampleシーンを起動します。

f:id:k_tachiban:20190318175015g:plain

動きました。

このシーンでできるアクションは

  • 右手を握って開くとレーザーが出せる
  • 両手を握ってエイムを箱に合わせて開くと掴む、手をもう一度握ると放す
  • 左手で箱を掴む
  • 右手で箱を押す
  • 右手の人差指を立てると出てくる光の玉を順になぞると箱を出せる

f:id:k_tachiban:20190318172131p:plain

といったアクションが可能になっています。

参考

developer.viveport.com

developer.viveport.com

おまけ

自分の環境ではデフォルトのまま実行するといくつかエラーが出てました。毎フレーム出てくるエラーがあるので対処法を書いておきます。 あと原因は不明なんですがハンドトラッキング周りの処理のCPU負荷がやばい。(i7-7700) f:id:k_tachiban:20190318174157p:plain

大量のMissingComponentException

両手を使ったAimを行うと前のUIパネルにレイがヒットしてしまい、アタッチされていないRigidbodyを参照しようとします。なのでヒエラルキーの中にあるInstructionといゲームオブジェクトのレイヤーをIgnore Raycastに変更してください。

【Unity】Mirage Soloでステンシルバッファが使えなかったときの対処

はじめに

MIrage Soloで開発を行った際、なぜかステンシルが効かずハマったのでメモ

原因としてはシンプルでDayDreamのDepthBufferの設定がデフォルトでステンシルバッファを含まないものになっていたからでした。

対処方法

PlayerSettings>XR Settings>DayDreamのDepthFormatを16-bit depthから24-bit depth | 8-bit stencilに変更すればOK

これでステンシルが使えるようになるはず。ちなみにこの問題はDayDream系全般ハマるはずなので注意。

f:id:k_tachiban:20181226161133p:plain

【Unity】選択したオブジェクトを強調表示するためのアウトラインシェーダーの作成

はじめに

ゲームを製作しているときに選んでいるオブジェクトをわかりやすくするために分かりやすいアウトラインを出して強調したいという場面は割とよくあるのですが、簡単に使えて綺麗にアウトラインを表示する方法がなかなか見つからなかったので作成して見ました。 単純にアウトライン部分のみを深度を無視して描画するシェーダーなので使い方は簡単でカメラにアウトライン表示用のスクリプト、オブジェクトに今回作成するシェーダをアタッチしたマテリアルを追加するだけでこんな感じに裏に回った部分もアウトラインだけ表示される形で強調表示ができるようになります。 f:id:k_tachiban:20180917151938p:plain

実装

今回のシェーダーの実装ですが方法としてはステンシルバッファにステンシルのみ書き込んで後からポストプロセスでアウトライン部分を描画しています。アウトラインの実装はよくある裏面を法線方向に拡大して描画する手法を使っています。

オブジェクト用のシェーダー

アウトラインをつけるオブジェクト用のシェーダーコードです。 今回は2Passを使って描画をしています。

1Pass目

1Pass目ではZWrite、ZTestをオフ、アルファを0にした状態でポリゴンの裏面を法線方向に伸ばした上で描画しています。この時あとでアウトラインとして描画するためのステンシルを書き込んでおきます。

2Pass目

2Pass目でもZWrite、ZTestをオフ、アルファを0にした状態に設定し、ステンシルの番号を変えて描画処理を行います。 これで法線方向が反転しているような特殊なモデル以外はアウトライン部分が1のStencilが書き込まれた状態になります。(深度テストを行わないため法線が反転していると表示がおかしくなりがち)

全文

ポストプロセス

ポストプロセス用スクリプト

続いては、アウトラインを実際に書き込むためにスクリプトを作成します。 本来ではOnRenderImage内でBlitを使ってポストプロセス処理を行うのですが、Blitを使ってポストプロセスを使ってステンシルを利用しようとするとかきこまれたステンシルを参照できないというバグ(?)がありました。 なので、この場合はCommandBuffer経由で描画してやる必要があるようです。 (今回はこちらのサイトのものをお借りしました)

[Unity]イメージエフェクトを特定のモデルだけにかける

using UnityEngine;
using UnityEngine.Rendering;

[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class ImageEffect : MonoBehaviour
{
    /// <summary>
    /// コマンドバッファ名
    /// </summary>
    private const string CommandBufferName = "StencilImageEffect";

    /// <summary>
    /// イメージエフェクトで使用するマテリアル
    /// </summary>
    [SerializeField] private Material material;

    /// <summary>
    /// イメージエフェクト用コマンドバッファ
    /// </summary>
    private CommandBuffer commandBuffer;


    private void OnEnable()
    {
        if (material == null) return;
        if (commandBuffer != null) return;

        var cam = GetComponent<Camera>();
        var cbs = cam.GetCommandBuffers(CameraEvent.BeforeImageEffects);
        foreach (var cb in cbs)
        {
            // 多重登録を回避するため、名前でチェック
            if (cb.name == CommandBufferName) return;
        }

        commandBuffer = new CommandBuffer();
        commandBuffer.name = CommandBufferName;

        // Blitでmaterialを適用してイメージエフェクトをかける
        commandBuffer.Blit(
            BuiltinRenderTextureType.CameraTarget,
            BuiltinRenderTextureType.CameraTarget,
            material);

        // カメラにコマンドバッファを登録
        cam.AddCommandBuffer(CameraEvent.BeforeImageEffects, commandBuffer);
    }

    private void OnDisable()
    {
        if (commandBuffer == null) return;

        var cam = GetComponent<Camera>();
        cam.RemoveCommandBuffer(CameraEvent.BeforeImageEffects, commandBuffer);
        commandBuffer = null;
    }
}

ポストプロセス用シェーダ

ポストプロセス用のシェーダーはシンプルにステンシルが書き込まれている場所に指定したカラーを描画するだけのシンプルなものになります。

StencilOutlinePostEffect.shader

この方法のメリット、デメリット

メリット

  • アウトラインの付け外しが楽
  • 半透明なものに対しても綺麗なアウトラインが描画できる
  • 既存のマテリアルに基本的に干渉しないため応用しやすい

デメリット

  • 通常の描画に加えて2Pass+ポストプロセス1Passなのでオーバヘッドが多い
  • アウトライン部分は深度チェックを行っていないため法線が反転しているものは相性が悪い
  • 鋭角なモデルに対してはポリゴンが浮いて見える

今回のスクリプト、シェーダはGitHubに上げておきました。 便利に使ってもらえると嬉しいです。 GitHub github.com

UnityPackerge Release StencilOutline.unitypackage · TachibanaKoki/StencilOutline · GitHub

参考サイト

ToonLitOutlineとステンシルによるOutlineの違い - AIプログラムとかUnityゲーム開発について

【Unity】【シェーダ】ステンシルバッファでアウトラインを描画する - LIGHT11

【Unity】ステンシルバッファをポストエフェクトで使う方法(と謎の挙動) - LIGHT11

[Unity]イメージエフェクトを特定のモデルだけにかける

Unity謎機能まとめ

なんとなくまとめたくなったのでUnityの存在しているがなんの為につかうのかよくわからない機能をまとめてみようと思います。

こう使うと便利だよ、とかこんな謎機能あるよだとか募集します。

Animator Parameter

使い方

  • Window>Animator Parameter

Animation Parametrsをみることが出来るwindow。普通のAnimatorWindowと同じ内容が表示される。 Animator見れば問題は無い。 用途は不明。

【Unity】Animator Parameterというウィンドウ - テラシュールブログ

Extract From Prefab

使い方

  • Project ビューでマテリアルが埋め込まれているモデルを右クリック>Extract From Prefab

モデルからマテリアルを抽出する機能。 マテリアル自体はインポート時に作成されるのでマテリアルを取得する機能として使うことはなさそう。データ容量が減らせたりする?

【Unity】Project ビューを右クリックした時に表示される「Extract From Prefab」とは - コガネブログ

まとめ

みんな気づいてないけど実は良い機能あったりしないかなーとか思ったり。 他にも謎機能があれば見つけ次第追加していきます。

【Lumberyard】Script Canvas入門

Lumberyard Advent Calendar 2017 の10日目です。 今回はLumberyard1.11.0から追加されたScriptCanvasの基本的な使い方と機能の紹介をします。

ScriptCanvasについて

ScriptCanvasはLumberryard1.11から追加された目玉機能の一つで新しいビジュアルスクリプト((UE4のBPのようなスクリプト環境環境になります。 CryEngineからの流れでFlow Graphというビジュアルスクリプト環境はあったのですが今後はScriptCanvasに置き換えられていく流れになると思います。 使用感としては機能縮小版BPといった感じでした。 今回はScriptCanvasの紹介とキーの入力でオブジェクトを動かすところまでやりたいと思います。  

ScriptCanvasのエディタ基本機能

ScriptCanvasエディターの基本構成の説明です。 といっても基本構成はシンプルで、左にノードを一覧できるNode Palleteとノードをつなげたり、管理するCanvasがあるだけです。 この画面はtools>Script Canvsから開けます。

image.png

ノードの追加は左のビューからドラッグアンドドロップか右クリックから検索で行います。

追加のウィンドウ

基本構成以外の追加可能なウィンドウもあります。 追加可能なウィンドウはNode InspectorNode OutLinerの二つです。

image.png

右上のNode Inspectorはノードが設定している定数が見れるようです(今後増える?) 右下のNode OutLinerではキャンバスに配置されているノードを一覧することができる機能です。

コメント

ScriptCanvasではコメント機能もありました。 コメントの追加方法はノードと同じようにcommentを探して追加するか、右クリック時に出てくるAdd Commentで追加できます。 使用感としてはキャンバスに置けるメモといった感じでサイズの変更もできずUE4のようにグループ化するために使うといったことはできなさそうです。 f:id:k_tachiban:20171203201702p:plain

ScriptCanvasの作成

Script Canvasを作成するには

  • Tools>Script CanvasまたはEntiityのScriptCanvasからScript Canvasのウィンドウを開く
  • File>New Scriptで作成
  • Ctrl+SまたはFile>Saveで名前を付けて保存 成功すると.scariptcanvasファイルが作成されます。

ユーザーからの入力を取得する

それではいよいよScriptCanvasの記述方法についてです。 まずはユーザーからの入力を受け取るスクリプトから書いていきます。

Input Bindingの作成

Script Canvasで入力を行うためにはまず初めに.inputBindingsを作成する必要があります。 手順は以下の通りです。

  • Tools>Input EditorでInput Binding Editorを開く
  • File>Create New Asset>Input to Event Bindings Assetで.inputbindingsを作成
  • Input Event Groupsの横の+ボタンを押す
  • 作成されたUnspecified EventにEvent Nameを入力
  • 作成したイベントのEvent Generatorsの+をクリック
  • Input Device TypeとInput Nameをイベントに合わせて入力
  • 以降Input Eventに必要な数のイベントを作成する
  • 入力が終わったらSave&Closeで保存

WASDでのキー入力をこんな感じで登録しました。

image.png

これでScriptCanvasでキーの入力がイベント名で取れるようになります。

入力を取得する

それでは作成したInput Bindingを使ってキーの入力を取得します。 Inputの取得にはInput Handlerノードを使用します。

 image.png

Event Nameのところに先ほど作成したInput Bindingのイベント名を入力してその入力時にログを出します。 ログを出すにはUtilities>Debug下のLogノードとVariables>CreateVariablesのStringからStringのVariableノードを作成することで実現できます。

image.png

出力を確認する

出力を確認するためにEntityに作成したScriptCanvasをAddします。 今回は入力をするためScrpit Canvas ComponentのほかにInput Componentの追加します。

image.png

そのあとCtrl+Gでゲームを実行。 登録したDを押したら無事Consoleにログが出ました。

image.png

オブジェクトの移動操作

ユーザーからの入力が取れたところでオブジェクトを移動させてみます。 オブジェクトの移動はMoveEntityノードで行えます。

image.png

キーの入力に合わせてこんな感じで作成。

キャプチャ.PNG

f:id:k_tachiban:20171203195120g:plain

これで動くようになりましたがノードが少々汚いのでもう少し改善します。 具体的にはInputBindingを編集して、S(Down)、A(Left)を押したときに-1が帰るように変更し、ノードを減らします。

f:id:k_tachiban:20171203200044p:plain

イベントをmove_X、move_Yの二つに減らしてS、Aの入力時のEvent value multiplierの値を-1.0にしています。 こうすることでノードがすっきりしました。

f:id:k_tachiban:20171203200404p:plain

まとめ

現時点でのScript Canvasを簡単に使ってみた感触ですが機能も少なく、シンプルなビジュアルスクリプティングといえると思いました。 UE4のブループリントのようにがっつり作るのには向いていませんがシンプルな機能の実装や、短期間での高速な開発には向いているようにかんじました。 シンプルなものにはScript Canvas、複雑なものにはC++luaを使うといった住み分けができるので状況に合わせて何を使ってスクリプティングするのか選択して使うのがよさそうです。

参考

Getting Started with Script Canvas - Lumberyard

Script Canvas Tutorials - Lumberyard

script canvas - Game Dev Forum

【Lumberyard】箱に物理を導入する

Lumberyardアドカレの6日目です。 Lumberyardで箱を出して物理を導入するだけの簡単な記事です。 使用したエンジンは1.11.1です。

Lumberyardで箱を出す

Lumberyardで単純な箱などのオブジェクトをを出すのはちょっとわかりにくいので紹介します。 LumberyardではUnityやUE4のように箱やカプセルなどの単純なオブジェクトをEntityの作成時に作れません。 しかし、単純なメッシュ自体はデフォルトで存在しているのでそれをアサインしてやれば使えるようになります。 手順は以下の通りです。

  • エンティティを作成
  • MeshをAdd Component
  • MeshのMesh Assetの「…」をクリックしてGame/Objects/Primitives/Box1x1.cgfを選択

f:id:k_tachiban:20171205222847p:plain

箱が表示されるようになりました!

primitivesには箱以外にもいくつかあるのでそれらをアサインすればとりあえず表示するオブジェクトには困らずに済みます。

面白いところだと「egg_001.cgf」「egg_proxy_001.cgf」なるモデルがありました。

f:id:k_tachiban:20171205223217p:plain
マジタマゴ

箱に物理をつける

作成した箱が物理挙動をするように設定するやり方です。 なんとなくで結構進む気がしたんですがそんなことはなく。 作成した箱のエンティティに以下の操作をしてください。

  • RigidBodyPhysics をAdd Component
  • Mesh ColliderをAdd Component
    • この時、~Shapeとprimitive colliderを代わりにAddすることでシンプルなコリジョンで動かせるようになります・
  • (1.10以前)RigidBodyPhysicsの「at rest initially」のチェックを外す。

f:id:k_tachiban:20171205230908g:plain

物理で動いた!

はまりポイント

オブジェクトの表示から物理を入れるまでは比較的簡単にいくのですが一部のモデルはMeshColliderをつけて物理を効かせようとすると動きません。

Primitivesの中だとproxyと書かれているものセットのモデルはproxyと書かれているモデル以外は動かなくなります。

どうしても動かしたい場合はShape系とprimitive colliderでシンプルに動かす必要があります。

あと、検証はしてませんが自前のモデルもMesh Colliderを使いたい場合はMaya、blenderの専用プラグイン通さないとダメな気がします。

まとめ

Lumberyardで物理をやる場合、UnityやUE4と比較して若干制約があるっぽいので何も見ずやったら案外はまりました。 今回の記事がにぎやかしくらいにはなればと思います。

【Unity】Compute Shaderでグローバルなテクスチャを使う方法

 UnityのCompute ShaderでGbufferをどうにか頑張ってRenderTextureに変換して使っていたのですが、もっと簡単に扱えることにあとで気がつきました。

 自分と似たような状態の人がいないとも限らないのでちょっと記事にしてみようかと思います。

概要

 _CameraGBufferTexture0などのグローバルなテクスチャをCompute Shaderで使いたい場合は

cs.SetTextureFromGlobal(index, "Albedo", "_CameraGBufferTexture0");

のようにCompute ShaderのインスタンスSetTextureFromGlobal関数を使ってセットすることでCompute Shaderで扱えるようになります。

今回の話はこれで終わりです。

説明

UnityではデフォルトではForwardに設定されているのですが設定を変更することでDeferredレンダリングに変更することができます。

Defferdレンダリングに設定すると

  • _CameraGBufferTexture0
  • _CameraGBufferTexture1
  • _CameraGBufferTexture2
  • _CameraGBufferTexture3
  • _CameraDepthTexture

などのGBuffer及びBufferがグローバルで定義されています。

通常のシェーダーでは_CameraGBufferTexture0などをsampler2Dとして定義することで使用することができるのですが、Compute Shaderでは使用することができませんでした。

これらのグローバルなテクスチャをCompute Shaderで扱う場合、Compute Shaderクラスのインスタンスから先述のSetTextureFromGlobal関数を呼び出して引数にカーネルのインデックスCompute Shaderで定義されているTextureSampler2Dの名前グローバルなテクスチャの名前をそれぞれ渡すことでCompute Shaderでもグローバルなテクスチャを扱うことができるようになります。