今回はUnityのVisual Effect Graphを使って銃の弾が当たった痕を作成し、それをゲーム内で使ってみたいと思います。
Visual Effect Graphについては
を参照してください。
この機能は以前作成し、記事にもしていますが、
上の記事では弾痕のプレハブを弾が当たった場所にインスタンス化し表示しているので、当たった場所のコライダの角度によっては弾痕が浮いて見えてしまいます。
そこで今回はVisual Effect Graphのゲームオブジェクトの表面に転写して出力するOutput Particle Forward Decalコンテキストを使ってエフェクトを出力し、ゲームオブジェクトの表面に弾痕を出力し、複数の面にまたがった弾痕を残せるようにします。
上の記事の弾痕と今回の記事の弾痕の違いは以下のようになります。
左が上の記事のように通常のプレハブの弾痕で、右が今回VFXを使って作ったプレハブの弾痕です。
右側だとテクスチャが面に合わせて転写されています。
ただ、銃に見立てたカメラ方向に合わせて弾痕の角度を変えていますので、綺麗に見えない場合もあります。
Visual Effect Graphで弾痕エフェクトを作成する
まずはVisual Effect Graphを使って弾痕エフェクトを作成していきますが、エフェクトと言ってもただ単にテクスチャを表示するだけのものです。
Visual Effect Graphの使い方については先ほどリンクした記事を参照してください。
まずはAssetsフォルダ内で右クリックからCreate→Visual Effects→Visual Effect Graphを選択しVisual Effect Graphのファイルを作成し、名前をBulletMarkとします。
ダブルクリックしてウインドウを表示します。
デフォルトで作成されているコンテキストやブロック等がありますが、Ctrl+Aキーを押して全部選択しDelキーを押して全て消します。
今回は一からコンテキストとブロックを作成していきます。
パーティクルの生成
まずはパーティクルを生成するSpawnコンテキストを作ります。
Spaceキーを押してContext→Spawnを選択します。
Spawnコンテキストを選択した状態でSpaceキーを押し、Spawn→Single Burstブロックを選択します。
Single Burstブロックはパーティクルを一度生成するブロックです。
今回のパーティクルはひとつだけ表示するのでCountに1を入力します。
これでパーティクルがひとつだけ生成されるようになります。
パーティクルの初期設定
Spawnコンテキストでパーティクルが一つ生成されるようになったので、次はそのパーティクルの初期設定をInitialize Particleコンテキストで行います。
Spawnコンテキストの下のSpawn Eventの部分をマウスで押し、下にドラッグしボタンを離して出てきたウインドウでInitialize Particleを選択します。
SpawnコンテキストのCapacityで1を入力し、1つのパーティクルのみが常に表示されるようにします(そもそもパーティクルひとつしか生成していませんが・・・)。
Boundsはパーティクルの表示範囲ですが、今回パーティクルは動かさないのでとりあえず中心が0で、範囲が1になるようにします。
Initialize Particleコンテキストを選択した状態でSpaceキーを押し、検索窓にset velocityと入力し、Set Velocityブロックを選択します(Spawnコンテキストの時と同じように項目を順番に選択してもいいのですが、数が多い為検索窓を使いました)。
Set VelocityではXYZ全てを0とし、パーティクルが生成されても速度が0で動かないようにします。
パーティクルの初期設定部分は以下のようになりました。
パーティクルの更新
Initialize Particleコンテキストの下のParticle部分をマウスの左ボタンで押し、下にドラッグしてボタンを離します。
Update Particleを選択します。
今回Update Particleでは何もしませんが、このコンテキストがないとパーティクルが表示されない為作成しています。
パーティクルを転写して出力
パーティクルをゲームオブジェクトに転写して表示するOutput Particle Forward Decalコンテキストを作成します。
Update Particleコンテキストの下のParticleをマウスの左ボタンを押してドラッグし、下に移動してボタンを離します。
Output Particle Forward Decalを選択します。
Output Particle Forward DecalのMain Textureには弾痕に使用するテクスチャを設定します。
以下のテクスチャは自由に使って頂いて構いません。
Output Particle Forward Decalコンテキストは以下のようになりました。
これで弾痕のエフェクトが出来ました。
弾痕プレハブの作成
弾痕のエフェクトが出来たので次はこれをプレハブにします。
Assetsフォルダに作成したVFXのBulletMarkファイルをヒエラルキーにドラッグ&ドロップします。
VFXの設定がされたゲームオブジェクトが出来ます。
BulletMarkゲームオブジェクトを他のゲームオブジェクトに重ねるとそのゲームオブジェクトの形状に合わせて転写されるのが確認出来ます。
弾痕の大きさはBulletMarkゲームオブジェクトのScaleを調整してサイズを変更します。
今回はわかりやすくする為にScaleは調整しません。
ヒエラルキーにあるBulletMarkゲームオブジェクトをAssetsフォルダにドラッグ&ドロップして弾痕のプレハブとします。
ヒエラルキー上のBulletMarkゲームオブジェクトはもういらないので削除します。
銃を撃った場所に弾痕を残す
弾痕のプレハブが出来たので後は銃を撃ったばしょに弾痕プレハブをインスタンス化しそこにゲームオブジェクトを残すだけです。
新しくBulletMarkScriptスクリプトを作成しカメラに取り付けます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.VFX; public class BulletMarkScript : MonoBehaviour { // 弾痕のVFXプレハブ [SerializeField] private GameObject bulletMarkPrefab = null; // レイを飛ばす距離 [SerializeField] private const float rayDistance = 1000f; // 弾痕を残す時間 [SerializeField] private float remaningTime = 10f; // Update is called once per frame void Update() { if(Input.GetMouseButtonDown(0)) { // メインカメラからマウスの位置にレイを飛ばす var ray = Camera.main.ScreenPointToRay(Input.mousePosition); // Fieldレイヤーが設定されたオブジェクトに接触したら if(Physics.Raycast(ray, out RaycastHit hit, rayDistance, LayerMask.GetMask("Field"))) { // 弾痕プレハブを接触面の向いている方向の角度に合わせてインスタンス化しremaningTime秒後に消す // ヒットした面の向きに合わせる場合 //Destroy(Instantiate<GameObject>(bulletMarkPrefab, hit.point, Quaternion.LookRotation(hit.normal), hit.transform), remaningTime); // ヒットした位置からカメラの方向を計算しその方向に向ける場合 Destroy(Instantiate<GameObject>(bulletMarkPrefab, hit.point, Quaternion.LookRotation(transform.position - hit.point), hit.transform), remaningTime); // 以前のプレハブをただ貼り付ける場合 //Destroy(Instantiate<GameObject>(bulletMarkPrefab, hit.point + hit.normal * 0.001f, Quaternion.FromToRotation(Vector3.up, hit.normal), hit.transform), remaningTime); } } } } |
bulletMarkPrefabはAssetsフォルダに作った弾痕のプレハブをインスペクタで設定します。
rayDistanceは対象のゲームオブジェクトを探す時に飛ばすレイの距離を指定します。
remaningTimeは弾痕を残す時間を設定します。
マウスの左ボタンを押したらTagにMainCameraが設定されたカメラからマウスの位置までのレイ情報をray変数に入れます。
Physics.Raycastを使ってレイの方向×rayDistanceまでレイを飛ばしFieldレイヤーが設定されたゲームオブジェクトにぶつかったらその情報をRaycastHit型のhitに入れます。
Instantiate
で弾痕プレハブをレイが衝突した位置とヒットした位置(hit.point)からカメラの位置(transform.position)の方向の角度(Quaternion.LookRotation(transform.position – hit.point))でインスタンス化し相手のゲームオブジェクトを弾痕のプレハブの親にします。
Destroyを使ってremainingTime後に弾痕ゲームオブジェクトを削除します。
今回はヒットした位置からtransform.positionの位置(今回の場合はメインカメラにスクリプトを取り付けているのでメインカメラの位置)までの方向を計算し、Quaternion.LookRotationを使ってその角度を計算しています。
弾痕をゲームオブジェクトの面の向きと合わせる場合は
Instantiate
を使います。
スクリプトを取り付けて確認する
作成したスクリプトはメインカメラに取り付けますが、今回はスタンダードアセットのFPSControllerプレハブをヒエラルキーに配置します。
インスペクタでFirst Person ControllerのMouse LookのLock Cursorのチェックを外しマウスカーソルが常に表示されるようにしておきます。
子要素のFirstPersonCharacterゲームオブジェクトにカメラが設定されているのでこれにBulletMarkScriptスクリプトを取り付け、BulletMarkPrefabに弾痕プレハブを設定します。
ついでにTagにMainCameraが設定されているのを確認しておきます。
弾痕を取り付けるのはFieldレイヤーを設定したゲームオブジェクトのみなので、ヒエラルキーに配置した建物等のゲームオブジェクトのレイヤーに新しくFieldレイヤーを作成し設定します。
また、ゲームオブジェクトには何らかのコライダが取り付けられている必要があります。
これで完成です。
あとはFPSControllerをキーボードの矢印キーで移動させながら、Fieldレイヤーを設定したゲームオブジェクトをマウスの左ボタンを押して確認してみましょう。
上のように弾痕がゲームオブジェクトの表面に転写されました。
終わりに
今回の機能を使えば人型キャラクターにも細かくコライダを設定すれば弾痕がうまく表示されるかもしれません。
ただあくまでコライダのヒットした位置にVFXの弾痕のプレハブのインスタンスを表示しているだけなので、実際のメッシュ部分にうまく表示させるのは難しいかもしれません。