いきなりまとめ
- Amplify Shader を使ってローカル座標のある高さ以下のピクセルに水色をブレンドする
- 高さの閾値をプロパティにしてUdon Sharp からアクセスできるようにしておく
- スクリプトからマテリアルを取得するにはGetComponent
().material - マテリアルのプロパティへのアクセスにはmaterial.GetFloat()とmaterial.SetFloat()を使う
まずはモデルを用意
いきなりですが水鉄砲のモデルを用意します。といっても私には無理なので三分クッキング張りに友人に作ってもらいました。 テクスチャも込みで作ってもらったのでとりあえずAlbedo(ベースカラー)もあらかじめ用意されてる体で行きましょう。
必要なコンポーネントを付与
インスペクター上のAdd Componentから以下のコンポーネントを付与しておきます
- VRC Pickup
- Rigidbody(VRC Pickup を付与すると自動的に付与される)
- Mesh Collider (Box Collider 等でも可)
- Udon Behaviour
また、VRC Pickup のAuto HoldとMesh ColliderのConvexを有効にしておきましょう。 後述しますが、VRC Pickup のExact Gripの設定をしておくとよさげです。
Amplify Shaderでシェーダーを作る
プロジェクトウインドウ->右クリック->Create で新規のMaterialを作成しましょう。同様に、プロジェクトウインドウ->右クリック->Create->Amplify Shader で新規のSurfaceを作成します。Surfaceを作成した直後Amplify Shaderのノードエディタが開くと思うので、次の画像のようにシェーダーを設定します。 簡単にシェーダーの説明をすると、stepノードを用いてWaterAmmount以下の部分だけ水色をブレンドするという感じです。このWaterAmmountの値ですが、自分で用意したモデルごとにいい感じの値を設定してください。
ノードを選択した状態で左上の灰色の四角ボタンを押すと設定の詳細を開くことが出来るので、赤枠で囲まれたノードの設定をしましょう。左側のFloatノードは水鉄砲の水量を表すFloatノードです。このノードを選択したのちに左上の詳細ボタンを押してTypeをPropertyにしておきます。こうすることでスクリプトからアクセスすることが出来るようになります。また、NameもWaterAmmountとしておきましょう。
次に、右側のOutputノードを選択してRender TypeとRender QueueをどちらもTransparentにします。
ちなみに、stepノードに入力するローカル座標がy座標ではなくz座標にしたのは、モデルの鉛直方向のローカル座標軸がz軸であったためです。
ここまでやればほぼ完成です。このシェーダーを適用したマテリアルを水鉄砲のゲームオブジェクトに付与すると次のように水が入ったような半透明の水鉄砲が出来ているはずです。
これだけでもそれっぽいですが、クリックごとに変化を持たせるためにスクリプトの力を借ります。
スクリプト実装する
スクリプトを実装といっても、クリックするごとにWaterAmmountの値を増減させるだけです。マテリアルのプロパティへのアクセス方法が分からず少し時間を溶かしましたが、(いきなりまとめにもあるように)ゲッターとセッターを通して行うようです。
using UdonSharp; using UnityEngine; using VRC.SDKBase; using VRC.Udon; public class watergun : UdonSharpBehaviour { private Material mt; private float wa; private float ini; void Start() { mt = GetComponent<Renderer>().material; //アンダーバーを忘れないように wa = mt.GetFloat("_WaterAmmount"); ini = wa; } public override void OnPickupUseDown() { //1/10ずつ水位が下がる wa -= ini/10.0f; mt.SetFloat("_WaterAmmount",wa); } public override void OnDrop() { //オブジェクトを落とすと元の水位に戻る mt.SetFloat("_WaterAmmount", ini); wa = ini; } }
material.GetFloat()やmaterial.SetFloat()はAmplify Shaderに特有なのかと思ったのですが、ちゃんとUnityの公式スクリプトリファレンスに書かれてました。
Exact Grip の設定
以上でほぼほぼ完成なのですが、実際にVRChatに持ってくると水鉄砲の向きが意図してない方向になります。 なのでVRC Pickup コンポーネントの設定に戻ってExact Grip を登録しましょう。Exact Grip にTransform を指定するとオブジェクトをピックアップした時にそのTransformの場所を手に握るようになります。水鉄砲のゲームオブジェクトの子要素にEmptyを追加して、そのEmptyのTransformをグリップの位置に設定しましょう。 これで大丈夫なはず、いざ鎌倉! うーん、水鉄砲が下を向いていますね。ということでEmptyのtransformのRotationをいじり、z軸が正面を向くようにしてやりましょう。 これで今度こそ水鉄砲になりました。 streamable.com