PhotonFusionのHostモードとSharedモードの違いと使い分け

はじめに

最近PhotonFusionを使った開発をすることが多くなってきて、少しずつ理解が進んできました。 今回は開発を始めるときに必ず知っておかなければならない2つのモードの違いをまとめておきます。

PhotonFusionとは

FusionはPhotonが出しているUnity向けのネットワークライブラリです。ざっくり言うと、複雑なことをあまり考えずにUnityでリアルタイム通信のマルチプレイゲームが作れるものです。料金は同時接続20人まで無料です。

Hostモードと Sharedモード

Fusionには大きく分けてHostモードとSharedモードがあります。この2つでは開発の仕方が大きく変わってくるので、作りたいゲームによって慎重に選ぶ必要があります。

Hostモード

Hostモードではホストがすべてのネットワークオブジェクトに対して権限(StateAuthority)を持ちます。

  • 他プレイヤー含め、ネットワークオブジェクトに関するすべての処理や変更はホストが行います。

  • [Networked]属性がついた変数の変更もホストのみが行なえます。

  • InputAuthorityとなるプレイヤーは各オブジェクトによって異なりますが、StateAuthorityは必ずホストになります。

特徴

  • ラグ補正機能があるためFPSなどの判定がシビアなゲームに適している

  • すべてのネットワークオブジェクトをホストが処理するため、多人数の同時接続には向いていない

  • ホストが切断した場合は基本的にセッションが終了する。(ホストマイグレーションでホストを譲渡することもできるが少し面倒くさい)

※Serverモードはサーバー構築から自分で行う必要があります。動作はHostモードと同じ感じになると思います。

Sharedモード

Sharedモードではプレイヤーそれぞれがネットワークオブジェクトへの権限(StateAuthority)を持ちます。

  • 権限を持つプレイヤーそれぞれがオブジェクトへの変更ができます。

  • [Networked]属性を持つ変数の変更はStateAuthorityを持つプレイヤーのみができます。

  • PUN2と似たような感じで開発できるそうです。(PUN2そんなに触ってないのでわからない)

特徴

  • プレイヤーそれぞれがオブジェクトへの権限を持つため、多人数が同時に接続するゲームなどに適している

  • ラグ補正機能が使えない

  • オブジェクトへの権限を譲渡できるので、接続しているプレイヤーが一人でもいる場合はセッションが生き続ける

実際どっちを使えばいいの?

公式が出している画像を見たら大体どっちを使うべきか判断できます。

ここにあるもの以外では、

  • ラグ補正が必要かどうか → 必要ならHostモード

  • 1ルームへの接続人数はどれくらいか → 多いならSharedモード

  • PUN2やStrixに慣れているか → 慣れているならSharedモード

というようにに考えればいいと思います。

Quest3でSharedSpatialAnchorのサンプルプロジェクトを動かしてみる

はじめに

サークルのアドベントカレンダーに向けてひっさしぶりにブログ書きました!最近はQuest3を買ったのでMR開発にハマってます。
今回はMetaのShared Spatial Anchor(共有空間アンカー)のサンプルシーンの導入から実際に動かすまでをやっていこうと思います。 (さらに詳しい記事を現在執筆中...)

Shared Spatial Anchorとは

SharedSpatialAnchor(以下アンカー)を使うと、アンカーを絶対的な目印としてシーンにあるオブジェクトの位置を同じ空間にいる他の人と共有することができます。

サンプルの動かし方

Metaの公式ドキュメントを参考にしながらやっていきます。

Shared Spatial Anchors Sample: Unity | Oculus Developers

サンプルのダウンロード

Unityバージョン:2020.3.42f
- Android Build Surportが必要
↓のGithubページからcloneしてください。
https://github.com/oculus-samples/Unity-SharedSpatialAnchors

プロジェクトをMetaの開発者ダッシュボードに登録

アンカーをクラウドに共有するためにアプリデータをDeveloperDashboardに登録する必要があります。(アカウントを持ってない場合は登録してください)

Oculus Developer Center | Authenticate

1. マイアプリから「新しいアプリを作成」を選択

2. アプリ名を決めてMeta Quest(App Lab)を選択

3. UserIDとUserProfileを追加してリクエストを送信
おそらく個人的に使う分には申請が拒否されたり承認に時間がかかったりはしないです。

4. 最後にAPIに移動してアプリIDをメモ

Photonのアプリケーションを作成

サンプルではPUN2という、ネットワーク機能を実装できるライブラリを使ってオブジェクトの同期を行っています。 Photonのアカウントを持っていない場合は登録しましょう。(https://www.photonengine.com/ja-jp)
登録したらダッシュボードに移動してPUN2用アプリケーションを作成します。
PUN2を選択

オブジェクト同期の機能のために使っているだけなので、実際に開発するときはPhotonFusionなどでも大丈夫です。

アプリケーションを作成したら、先程と同じ用にアプリIDをメモしておきます。

Unityエディタでの設定

Unityプロジェクトを開いたらAssets/SharedSpatialAnchors/Scenesの中のSharedSpatialAnchorシーンを開きます。

OVRManagerの設定
まずヒエラルキー上のOVRCameraRigにアタッチされているOVRManagerのインスペクタを設定します。

  • Tracking Origin Type: STAGE
  • Anchor Support: Enabled
  • Shared Spatial Anchor Support: RequiredまたはSupported
  • Passthrough Capability: Enabled

AndroidManifest.xmlの追加

[Oculus] -> [Tools] -> [Create store-compatible AndroidManifest.xml]を選択します

MetaアプリIDの指定
[Oculus] / [Platform] / [Edit Settings]に移動します。

  • [Meta Quest2/Pro]に先程メモしたMetaのアプリIDを指定します。
  • Quest Linkをテストする場合は、[Oculus Rift]の方にもアプリIDを入れます。
  • [Build Settings]の下で、Bundle Identifierを(com.yourcompany.ssa_sampleなど)置き換えます。

PhotonのアプリIDの設定
[Window] > [Photon Unity Networking] > [Highlight Server Settings]を開きます。 先程メモしたPhotonのアプリIDを貼り付けます

ビルド準備

  • BuildSettingsからAndroidにSwitch Platform

  • ProjectSettingsでAndroidのMinimamAPILevelを32以上に設定

ビルド

1. Oculus→OVRBuild→OVRBuildAPKからBuild
※バージョンコードが被ってるとアプリをアップロードできないのでAuto Incrementにチェックを入れておく

2. アプリケーションにアカウントを追加
もう一度Metaのアプリダッシュボードに移動して、リリースチャンネル>ALPHAを選択し、使っているQuestに入っているMetaアカウントを追加します。
※これをしないとアンカーをクラウド保存するために必要なユーザーIDの取得時にエラーがでます。

3. ビルドデータをアップロード
MetaQuestDeveloperHubを開いて、AppDistributionのUploadからAPKファイルをアップロードします。

サンプルシーンの操作

サンプルシーンではアンカーの保存、共有ができます。

メニュー

  1. Anchor Sharing Demoを選択
  2. Create New Roomを選択(二人目の入室時はJoinRoom)

メインUI(左手)

  • Toggle Anchor Creator:アンカー作成モードに切り替え
  • Load Local Anchors:ローカルに保存されているアンカーをロードしてインスタンス
  • Spawn Networked Cube:ネットワークで同期されるCubeを生成(他のプレイヤーと共有される)

アンカーUI

  • Save Anchor Locally: アンカーをローカルに保存
  • Hide Anchor:シーンからアンカーを削除(ローカルに保存されている場合はもう一度読み込めば復活)
  • Erase Anchor:アンカーをシーンから削除し、さらに、ローカルに保存されているアンカーデータも削除。
  • Share Anchor:ルームに接続している他のすべてのユーザー、ルームに新たに参加するユーザーとアンカーを共有
  • Align to Anchor:アンカーとの位置関係を元にプレイヤーの位置合わせをする。ネットワークで同期されているオブジェクトは全プレイヤーから同じ位置に表示される。

注意点

ビルドしないとアンカーをクラウドに保存できない

  • 実機じゃないとMetaのユーザー情報が取得できないため、QuestLinkなどでのデバッグはできません。(Linkではアンカーの配置とローカルへの保存のみ可能)
  • このサンプルではできませんが、最新のMeta XR Simulatorではデバッグ用のMetaアカウントにログインしてくれたりするのでわざわざ実機にビルドしなくてテストできます。

複数アカウントでテストする場合はMetaアプリのダッシュボードのリリースチャンネルからユーザー追加するのを忘れない

  • そもそもMetaQuestDeveloperHubからインストールする必要があるのでユーザー追加は必須です
  • ストアカウントでも動きます

クラウドに保存してもアプリを終了したら消える

  • もしアンカーを保持したい場合はローカルに保存しましょう

まとめ

SharedSpatialAnchorに関するドキュメントが少なかったのでかなり苦戦しました。まだ触ってないですが、最近BuildingBlocksにSharedSpatialAnchorの項目が追加されていたのでで、これからもっと簡単に使えるようになりそうです。この記事はほとんど公式ドキュメントの内容そのままでしたが、現在この機能を取り入れたゲームを開発しているので、もっと詳しい記事もこれから書こうと思ってます。(アドベントカレンダーの日までにまとめきれなかった...)

参考

共有空間アンカー | Oculus開発者

Meta QuestのShared Spatial Anchorsについて調査する - MRが楽しい

Shared Spatial Anchors Sample: Unity | Oculus Developers

C#のガベージコレクションって何してるの?

はじめに

どうも、にとです!
C#ってメモリ解放とかを勝手にやってくれるのですが、中でどんな風に動いているのか気になったので本棚に眠っていたオライリーの本を参考にして簡単にまとめてみました。

ガベージコレクションとは

ヒープブロックの割り当てを解除するタイミングを決定する機能。

ヒープ

ヒープとは動的に確保と解放を繰り返せるメモリ領域のことです。インスタンスをnewするなどで新しいヒープブロックが割り当てられます。
ヒープブロックにはオブジェクトの静的ではないすべてのフィールド(配列ならすべての要素)とヘッダが含まれる

1.オブジェクトの生存を決定する

まずは使っていないオブジェクトを判別するにはルートを決めます。

ルート

まずルートとは何かというと、「到達可能なオブジェクトへの参照」です。つまり今どこかで使われていて生存しているオブジェクトへの参照のことです。
他にも参照型の静的フィールドなど、プログラムが別のオブジェクト参照を経由しなくても将来必ず利用できるオブジェクトへの参照もルートになります。

ルートであるかの判定

ルートであるかは以下の条件で判断されます。

  • そのオブジェクトへの参照がnullでなければルート
  • ルートであるオブジェクトが参照しているオブジェクトもルート

※ローカル変数、メソッド引数はその生存期間だけルートになる(引数は渡した時点で終了)
※式の評価の結果として生成される一時オブジェクトも評価が完了するまで生存する

弱参照

弱参照を使うとオブジェクトへの到達可能性が若干変わります。

普通の参照と何が違う?

オブジェクトが弱参照からしか到達できないときはGCで割り当てを解放します。

つまり

  • 「自分以外が全員参照を手放したら、その時点で解放対象にしてほしい」
  • 「オブジェクトを参照しているけれど、GC的には参照してることにしないでほしい」

ときに使う

弱参照の宣言

WeakReference<T> hoge = new WeakReference<T>(value);
// コンストラクタ引数に渡したもので初期化される
// Tの部分は任意の型を指定する

2.メモリの回収

オブジェクトが死亡するとその分のメモリが回収され、ヒープに空き領域ができます。このとき新しく必要になったメモリを空のブロックにそのまま割り当てると無駄が多くなってしまいます。

そこで登場するのがコンパクションという処理です。

コンパクション

コンパクションとはヒープの空き領域が連続的になる状態にする処理のことです。これをすることで、

  • 新しいメモリを無駄なく割り当てられる
  • 関連するデータが近くになるので効率が良くなる

という利点があります。

ブロックを移動したときにはすべてのポインタを調整します。

この方法で万事解決...と思いきやもう一つ問題があります。それは古いオブジェクトが到達不能になったときにコンパクションに時間がかかってしまうというものです。

このようにオブジェクトの生存期間によってコンパクションのコストが変わってしまいます。そこでオブジェクトを世代に分けて考えます。

世代

オブジェクトの生存期間によるコンパクションのコストの違いを考慮し、オブジェクトを3つの世代に分け、世代によってGCのタイミングを変えます。

  • 世代0 … まだ一度もGCを経験していないオブジェクト
  • 世代1 … 短命か長命かを見極める待期期間

ここまでが短命世代と呼ばれ、世代1までの領域が閾値を超えると通常GCが発生します。

  • 世代2 … もっとも古い世代
    世代2まで生き残ったオブジェクトは
    • フルGCのときのみメモリが回収される
    • コンパクションに時間がかかる
    • CPUのキャッシュが消えていてコピーに時間がかかる

    (※世代2に入るがそれほど寿命が長くないオブジェクトができることを中年の危機と呼ぶらしい)

世代1まではプログラムが動いているときのGCによってメモリを回収し、世代2はフルGCのときのみメモリが回収されます。

大規模オブジェクトヒープ(LOH)

サイズが大きいオブジェクト(85000バイト以上)は大規模オブジェクトヒープと呼ばれるヒープに割り当てられます。コストがかかるため通常GCではコンパクションをせず、フルGCのときに明示的に要求しないとコンパクションはできません。

感想

今まで裏で動いているものや実際の開発でそれほど使わないような知識は結構すっ飛ばしていたんですが、こうやって調べてみると意外と面白かったです。Unity開発でもプロファイラを見るとたまにGCによってパフォーマンスがガクッと下がっていることがあるので、GCの仕組みと特性を生かした対処ができたらいいなと思いました。

参考

www.amazon.co.jp

LightshipARDKを使って初めてのAR開発

Lightship ARDKとは

ポケモンGOなどで知られているNiantic社のAR開発ツール。 Lightship ARDKの強みとしては

があります。

Lightship VPS

Visual Positioning Systemのこと。ある特定のスポットを特定、把握することでデバイスを現実の位置と同期させることができる。
例えば、ある場所にARオブジェクトを隠してそれを他のユーザーに見つけてもらう、みたいな宝探しゲームもできちゃったりする。

導入方法

  1. Lightshipアカウントを作る
  2. ARDKをダウンロードする
  3. Unityプロジェクトを作る
    ※UnityHubでAndroid Build Supportを入れておく
  4. 2でダウンロードしたARDKのunityパッケージをインポートする

APIキーの認証

  1. アカウントダッシュボードAPIキーを作る
  2. APIキーを認証する
    1. Resources/ARDKフォルダにArdkAuthConfigアセットを追加
    2. ArdkAuthConfigのインスペクタのApiKeyにさっき作ったAPIキーを入力する
    3. Unityを再起動

平面検知をしてオブジェクトを配置する

こんなものを作ります
(参考: チュートリアル: 基本の配置 — Niantic Lightship Augmented Reality Developer Kit release-2.4.1 ドキュメント)

www.youtube.com

カメラの設定

シーンを開いたらまずMainCameraに以下のコンポーネントをアタッチする

そしたらインスペクタのCameraのところにMainCameraをドラッグアンドドロップ

Cameraコンポーネントは以下のように設定する

セッションマネージャー

シーンに空のゲームオブジェクトを作って、名前をSessionManagerにします(名前はなんでもいい)。
SessionManagerには以下のコンポーネントをアタッチしていきます。

  • ARSessionManagerコンポーネント
    • ARセッションのセットアップを処理する
  • ARPlaneManager
    • シーン内のARオブジェクトを保存・トラッキングしてくれる
    • Planeに基づく配置が可能に
    • 配置したオブジェクトの保存
    • 配置したオブジェクトの固定(たぶんカメラを動かしたときに位置を一定に保つ)
  • AndroidPermissionRequester(Android向けのみ)
    • 実行時にユーザーに対してカメラ使用許可を求めるようになる
    • PermissionsにCameraを追加
  • ARCursorRenderer
    • カメラからRayみたいなのを飛ばして、物を検知するとそこにCursorObjectが表示される
  • ARHitTester
    • タップしたところにプレハブを配置する

ビルド

今回はAndroidでのビルドをしていきます。

設定

Project Settings

  • Player→Other Settings
    • GraphicsAPIsからVulkanを削除
    • Scripting BackendはIL2CPPを選択
    • Target ArchitecturesはARMv7とARM64を選択
  • Player → Publishing settings
    • Custom Main ManifestとCustom Base Gradle Templateにチェックを入れる
    • 追加されたAndroidManifest.xmlに以下を追記する

        <queries>
                <package android:name="com.google.ar.core" />
        </queries>
      

Gradleの設定

  • gradleをダウンロードして解凍(たぶん新しいので大丈夫)
  • 追加されたbaseProjectTemplate.gradle(Assets->Plugins->Androidの中)を編集
    • classpathを 'com.android.tools.build:gradle:4.2.0’にする
  • Preferences → External ToolsでGradle Installed with Unityのチェックを外してさっき解凍したフォルダを選択

ビルド

  1. スマホを開発者モードにする(「設定」アプリ内で「ビルド番号」を7回連続してタップ)
  2. スマホで開発者向けオプションのUSBデバッグをONにする
  3. PCとスマホをUSBで接続する
  4. UnityのBuild SettingsでSwitch platform
  5. Run Deviceで自分の端末を選択する
  6. Build And Runで実行!

動いた!

www.youtube.com

感想

まさかコードを書かずに動くとは...! 開発環境を整えるのが結構簡単だったのと、公式のチュートリアルも細かく説明してくれているのですぐに実機で動かせることができました。もっといろんな機能があるのでチュートリアルを進めながら試していきたいと思います。早く自由にARゲーム作れるようになりたいな~

最後にちょっと自分語り

ARやろうと思ったきっかけ

「誰でも楽しめるXRコンテンツを作りたい」という目標ができたのがきっかけです。最近いろいろあって親孝行したいなっていう感情が芽生えまして...。お金稼げるようになってからいろいろ買ってあげようとか考えてはいるんですが、大学生のうちからできることないかなーとか思ったんですよね。でもVRHMDが無いとできないし、慣れてないと疲れちゃうし...とか考えた結果、ARなら家族でも楽しめるコンテンツを作れるんじゃないか、ってことでAR開発を勉強することになりました。そこからいろいろ広がって、誰でも楽しめるXRコンテンツを作りたいという目標ができたわけです。
もちろんVR楽しいので今まで通りVR開発していきますが、ARのほうもちょっとずつやっていきたいなと思います。

IVRCに参加した話(~SEED stage編)

はじめに

この記事は投稿される2か月くらい前に書いたものです。一応Leapステージが終わってからのほうがいいのかなと思って温めておきました。
この時の僕はLeapステージに進出できるとは知る由もなかった...

IVRCとは

「学生を中心としたチームでインタラクティブ作品を企画・制作するチャレンジ」(公式より)
主にxR技術を用いた作品が出展されています。今回のSEED stageでは23チーム+復活枠4チームが出場しました。審査を通過するとLEAP stageに進むことができます。

制作したもの

僕の所属したチームでは『自宅でも遭難がしたい!』という作品を展示しました(どこかで聞いたことあるような...?)。この作品ではリアルな遭難を体験することができ、実際に登山をしないと気づかないような体の変化や危険を感じることができます。

www.youtube.com

やっぱり遭難という実際には体験できない(というかしたくない)ものでも簡単に体験できるのがVRの面白いところですよね~
ちなみにこのアイデアは、メンバーの中学校の時の先生が山で遭難して、暗闇の中石を投げることで方向を確認しながら自力で山を降りた、というぶっ飛んだエピソードから発案されました。

実装した機能

足踏みで移動

Viveトラッカーを2つ使い、足踏みでの移動を実装しました(本当はHaritoraを使いたかった)。実際に足を動かすことで没入感と疲労感を高めることができました。

疲労度に応じた身体の変化

1. 身体が重くなる

体験者にリュックを背負ってもらい、疲労度が溜まるとポンプによってリュックの中の容器に水が流れ、徐々に身体が重くなっていきます。
水を使うということもあり、何度かブルーシートが水浸しになったりもしました。また水が流れる速度や量は何度も調整しました。

2. 身体が冷えてくる

首に装着したペルチェ素子によって低体温症による身体の冷えを再現します。首元を冷やすだけで結構寒さを感じます(個人差あり)。
また低体温症による手の震えをモーターで再現しています。疲労度がしきい値を超えるとモーターが動き出します。

3. 目が見づらくなる

URPのPost processingを使って疲労度による視界の悪化を再現しています。Depth of fieldで目がぼやける感じを出し、Vignetteで視界が狭まる感じを表現しました。

4. 音がぼやけてくる

UnityのAudio Filterを使って高い周波数と低い周波数を削っていくことで音がぼやける感じを表現しています。

僕(にと)が担当した部分

僕たちのチームはソフト班とハード班に分かれて開発をしました。
僕は主に植物のグラフィック関係を担当しました。↓のような感じです。

  • 草のグラフィック

ShaderGraphを使ったリアルな草の作り方① ~Blenderでメッシュを作る~ - にとのーと

  • 草を手でかき分けたときの動き
  • URPのライティング設定
  • 虫のVFX
  • タイトルシーンのステージ作り
  • ステージのパフォーマンス改善

この他にも、出没動物のアニメーション、方向指示UI、アイテムの見た目、アイテムの取り出し、手のアニメーションなどを担当しました。

体験審査会

9月3日、東京のポートシティ竹芝で体験審査会がありました。先輩二人と僕の計三人で参加し、組み立てからアテンドまで協力して取り組みました。

いきなりトラブル発生...

最初の体験者でなぜかトラッカーが反応しなくなるというバグが発生。さらに二人目の体験者のときにはOculus Linkができなくなり、PCの再起動をすることになりました。正直ここで心折れかけました...。

なんとか持ち直した

その後は大きな不具合が起きることなく、順調に体験していただくことができました。毎回ペットボトルに入った水を容器に戻す作業があるので自分たちの疲労度も順調に溜まっていきました。

嬉しいことも

体験したあとに感想やフィードバックをいただけるんですが、そのときにハード部分はもちろんのこと、「草をかき分けるのが楽しい」や「山の雰囲気がリアル」など自分が携わった部分が褒められて泣きそうなくらい嬉しくなりました。

他チームの作品

審査が終わった後、他の参加チームの作品を体験することができました。僕が体験したのは『壁歩き体験~ヤモリになろう!~』という作品で、その名の通りヤモリになって床を這ったり壁を歩いたりするというものでした。バランスボールを回すことによって、確かに「登っている」という感覚があり、高いところに登ったときのスリルも味わえて楽しかったです。

感想

IVRCのような大学外のイベントに出場するのは初めてなのでとてもワクワクしながら開発に取り組むことができました。ハードウェア部分と連携した開発というのも初めてでしたが、VRと装置が連携して動いているのを見てVRの無限の可能性に感動しました。体験会では実際に体験してもらって感想やフィードバックをいただけたり、他の参加者との交流もあったりして良い経験になりました。また個人的なことを言うと、今までゲーム開発においてコードを書くことにしか興味がなかったのですが、今回「リアルな」体験を制作するにあたってグラフィック関連にもこだわることができたので楽しかったです。特にShaderGraphやVisualEffectGraphは今後のゲーム開発でも大きな武器になると感じました。

最後に

IVRCを運営していただいている方々、メンバーとして誘ってくれた先輩、一緒に開発に携わったメンバーに感謝。
LEAP stage通ってほしいな~

ShaderGraphを使ったリアルな草の作り方② ~風でなびかせる~

風でなびかせたい

↓の動画のように風でなびく感じをShaderGraphを使って表現していこうと思います。
youtu.be

前回は草のメッシュを作りました。 niton.hatenadiary.com

今回の記事は以下の動画を参考にしています www.youtube.com

1. ShaderGraphを使えるようにする

UnityでShaderGraphの機能が使うにはURPというレンダリングパイプラインを使用する必要があります。導入はとても簡単です。

Unityのプロジェクトを作成するときに3D(URP)を選択するだけです! ※既存のプロジェクトにURPを導入する方法はこちらの記事を参考にしてみてください。↓
【Unity】Unity 2021.2で変更されたURP設定方法まとめ|yugaki|note

2. ShaderGraphの基礎

では早速ShaderGraphを使ってみましょう。
Projectウィンドウで右クリックをして、Create->Shader Graph->URP->Lit Shader Graphを選択します。(Litにすると周りの光の影響を受け、Unlitは影響を受けません)

ウィンドウの見方

ShaderGraphを作成すると↓のような画面が出てきます

  • MasterStack…シェーダーへの最終的な出力
    • Vertexは頂点の操作を出力する
    • Fragmentは色やテクスチャなどを出力する
  • Blackboard…プロパティとキーワードのリスト
    • プロパティを追加するとインスペクタで編集できるようになる
    • ReferenceでC#で使うプロパティ名を変更できる
  • GraphInspector…ノードごとのインスペクタ
  • MainPreview…プレビュー

ノード

ウィンドウ内で右クリック -> Create Node、もしくはSpaceキーを押すとノードの種類がたくさん表示されます。ここから必要なノードを選んでShaderを作っていきます。

では試しにAddノードを作ってみましょう。上の検索欄で「Add」と入力すると簡単に見つけることができます。
Addを選択すると↓のようなノードが出てきます。

左側のAとBが入力で、右側のOutが出力です。この入出力の部分に他のノードを結びつけて作っていきます。

ではShaderGraphの基本的な使い方がわかったところで、今回の目的である「風になびく草」を作っていきましょう!

3. 全体像

今回は大きく3つのステップでShaderGraphを作っていきたいと思います。(参考動画より)

Step1. メッシュの頂点にワールド座標基準でUV座標を割り当て、UVスクロールする

Step2. ノイズテクスチャを適用して頂点を左右に揺らす

Step3. これだと草の根本も一緒に動いちゃうのでy軸にグラデーションをかけて根本の変化を0にする

4. 解説

準備

まずは前回作ったメッシュとテクスチャをインポートします。Projectウィンドウで右クリックをしてImport New Assetsを選択し、前回作ったメッシュとテクスチャをインポートします。

  • Sample Texture 2Dノードと、BaseTextureプロパティを作りGraph Inspectorでテクスチャを設定します。
  • ShaderGraphのプレビューもあるんですが、シーンのほうが動きがわかりやすいのでシーンに草を配置して確認できるようにします。
    Mesh FilterとMesh Rendererコンポーネントを追加し、画像のように前回作ったメッシュとShaderGraphを適用させたマテリアルを設定します。
  • このままでは後ろから見たときにテクスチャが表示されないので、ShaderGraphのウィンドウのGraphSettingでRender Faceにチェックを入れます。
    また、透過部分を表示しないように、Alpha Clippingにもチェックを入れます。

Step1. 頂点にUV座標を割り当て、UVスクロールする

このようにノードをつなげます。

この部分はUVスクロールのテンプレ的な感じですね。頂点にワールド座標基準でUV座標を割り当てて、それをスクロールしています。
Tiling And OffsetノードのOffsetにTimeノードを作用させることで時間によってUVがスクロールする動きをします。ここではBlackboardで「WindMovement」というVector2型のプロパティを作って時間と乗算することでスクロールの速度を調整しています。

Step2. ノイズテクスチャを使って頂点を左右に揺らす

3つのノードと2つのプロパティを追加します。先程作ったTiling And OffsetノードのOutからGradient NoiseノードのUVにつなげます。
Gradient Noiseはノイズテクスチャを生成してくれます。Scaleはノイズの大きさで、今回は風の密度?を決定しています。
Substractノードは値の引き算をします。ここで0.5を引いているのはおそらく白黒の割合の調整です。ちなみに値的には黒が0、白が1を表しています(結構大事かも)。
Multiplyノードは乗算をします。このノードによって白黒のメリハリを調整しています(大きい値を乗算するとメリハリが強くなる) 。ここではWindStrengthによって風の強さを決定しています。

ではついでに今の状態での出力までしてみましょう。

4つのノードをこのようにつなげて先ほどのMultiplyノードのOutをAddのAにつなげましょう。また、CombineのRGBA出力からVertexのPositionにつなげてみましょう。

Splitノードは入力ベクトルをR,G,B,Aに分割します。Positionを入力とした場合、RGBはそれぞれxyz軸を表します。ここではx成分だけを取り出して先程作ったゆらぎを加算しています。
CombineノードはRGBAの入力から新しいベクトルを作成します。ここではx成分の計算をした後に元のy,z成分をそのまま入力として受け取り、RGBAに合成しています。

今の状態だと↓のような動きになってしまいます。
youtu.be
根本まで一緒に動いていてちょっと気持ち悪いですね笑

Step3. 根元の方を動かさないようにする

では↓の赤線で囲まれている部分を追加していきましょう。

UVノードとSplitノードを組み合わせるとグラデーションを作ることができます。RGBのうちGを使った場合は縦方向のグラデーションになります。
Lerpノードは2つの入力の線形補完を計算します。ここでは縦方向のグラデーションを入力として、元の頂点座標とゆらぎを計算した頂点座標の間を線形補間しています。こうすることで根本に近いところでは元の頂点座標を採択し、葉っぱの先に近いところではゆらぎを計算した頂点の座標を採択します。

完成!

いっぱい配置してライティングを調整してみました。
youtu.be

ShaderGraphを使ったリアルな草の作り方① ~Blenderでメッシュを作る~

草を生やしたい

IVRCに向けた開発でリアリティのある植物を作る機会があったので、UnityのShaderGraphの勉強をしながら立体的で風になびく草を作ってみました。

youtu.be

やりたいこと

  • 軽量でリアリティのある草を生やす
  • 風で動いている感じ
  • プレイヤーが通った時に少し倒れる

1. メッシュを作る

まずは草の形を作っていきます。
Blenderを起動し、最初にあるCubeを削除したらShift+Aを押してPlaneを作成します。

Editモードに切り替えて移動、回転、拡大、縮小をしながら形を整えます。

これを繰り返してPlaneをいい感じに配置していきます

2. UV展開をしてテクスチャを張り付ける

※草の透過画像を用意しておく
こんな感じのやつ Ornamental Grass Clip Art - Tall Grass Clipart – Stunning free transparent png clipart images free download

まずblenderのウィンドウの上のほうにあるUV Editingに移動します

UVマッピングウィンドウ(左側)の上のほうでOpen Imageから草のテクスチャ画像を選択します

テクスチャが見えるように右のマテリアルタブから新しいマテリアルを作成し、BaseColorでImageTextureを選択します。

そうしたら先ほど選択した画像があるのでそれを選択します。

↓のように描画されれば成功です!
(テクスチャが見えないときはZキーを押してビューモードをMaterial Previewにしましょう)

もしテクスチャが逆向きになっていたら左のUVウィンドウで対象の面を回転させて調整しましょう。

3. FBXファイルをエクスポート

完成したらFile->Export->FBXを選択します

出てきたウィンドウの右側でExportの設定をします。

  • ObjectTypesをMeshのみにする
  • Apply Transformにチェックを入れる(一応)

    これでBlenderでの作業は終わりです。

次:niton.hatenadiary.com

ShaderGraphを使って風になびかせる