今回はUnityに関する話題で、タイトルの通り
マテリアルのプロパティの値をC#スクリプトから変更する方法
をサンプル付きで丁寧にご紹介するという内容になっております。
Unityでゲームを作っていると、例えば
- ダメージを受けた敵キャラの色を一瞬だけ変えたい
- 倒した敵キャラが一瞬で消えるのではなく、徐々に消えるようにしたい
といった要望が出てきますよね。これはマテリアルのプロパティの値をゲーム中に変更することで実現できるのですが、やり方が分かりづらいので初心者の方からしたらどうやればいいのかよく分からないと思います。
そこでここではその辺のやり方の基本についてサンプルスクリプトを使いながら解説しますね。
【サンプル】ゲーム中にマテリアルの値を変更するC#スクリプト
まずはサンプルスクリプトを掲載します。下記スクリプトのChangeValue関数を呼び出すと、マテリアルの色が指定した色になります。
using UnityEngine;
public class MaterialValueChanger : MonoBehaviour
{
[SerializeField]
MeshRenderer meshRenderer;
[SerializeField]
string targetPropertyName = "_BaseColor";
[SerializeField]
Color targetColor = Color.white;
int targetPropertyId;
Material targetMaterial;
void Start()
{
// プロパティ名→IDに変換(高速化)
targetPropertyId = Shader.PropertyToID(targetPropertyName);
// メッシュレンダラーからマテリアルを取得
targetMaterial = meshRenderer.material;
}
public void ChangeValue()
{
// 色変更
targetMaterial.SetColor(targetPropertyId, targetColor);
}
}
サンプルスクリプトを使ったマテリアルの色変更の例
サンプルスクリプトの使い方
適当なゲームオブジェクトに上記のスクリプトをアタッチして必要な設定を行い、好きなタイミングでChangeValue関数を呼び出してください。
なお上記のデフォルト設定はURPのLitシェーダーを使った場合に上手く動作するようにしてあるので、別のシェーダーを使ったマテリアルで動作させたい場合は後述する方法を使ってシェーダーのプロパティ名を調べ、それをtargetPropertyName変数に設定するようにしてください。
【解説】マテリアルの値を変更するスクリプトの処理手順
では上記のサンプルスクリプトで行っている処理の解説をしようと思います。主な手順は次の4つです。
- マテリアルに使われているシェーダーのプロパティ名と型を確認する
- (任意)Shader.PropertyToID関数でプロパティ名をIDに変換する
- 値を変更するマテリアルを取得する
- 値の変更処理を行う
それぞれ詳しく見ていきましょう。
手順1:マテリアルに使われているシェーダーのプロパティ名と型を確認する
はじめに、マテリアルのプロパティの値を変更するためには
- マテリアルに使われているシェーダーのプロパティ名
- ↑のプロパティの型(float, Color等)
の2つを知らないと変更しようがないのでそれらを確認しておきましょう。
ただ「確認しましょう」といっても初心者の方はそもそもプロパティ名等の確認方法が分からないと思うのでその点についてもご説明します。まずインスペクターでマテリアルの情報を表示し、「Shader」ドロップダウンの右側にある「Edit」ボタンを押します。
そうするとVisual Studio等のエディタが起動してシェーダーのコードが表示されるので、その「Properties」ブロック内に書かれているプロパティから目的のプロパティを探しましょう。
例えばURP標準のLitシェーダーの場合、色を変化させたいなら「_BaseColor」が対象のプロパティとなります。型はColor型ですね。
なお当然ですがプロパティ名や型はシェーダーごとに異なります。お使いのシェーダーの各プロパティがどういった表現に対応しているかはシェーダーのマニュアル等を見て確認しましょう。
手順2(任意):Shader.PropertyToID関数でプロパティ名をIDに変換する
次にC#スクリプトでは、Start関数などのタイミングで
変更対象のプロパティ名をIDに変換する
という処理を行い、そのIDを使って値を変更することで処理を高速化できます(※任意)。何度も処理を呼び出す場合はプロパティ名をIDに変換しておいた方がいいでしょう。
プロパティ名→IDへの変換はShader.PropertyToID関数を使えば簡単に行うことができます。
targetPropertyId = Shader.PropertyToID(targetPropertyName);
手順3:値を変更するマテリアルを取得する
そうしたら次は値を変更するマテリアルを取得します。マテリアルが1つだけの場合はメッシュレンダラー等のmaterial変数を参照すればOKです。
targetMaterial = meshRenderer.material;
もしメッシュレンダラーに使われている複数のマテリアルの値を一気に変更したい場合は配列を用意しておき、materials変数から一括で取得しましょう。
手順4:値の変更処理を行う
最後に実際に値の変更処理を行います。値の変更にはそれぞれの型に対応した関数が用意されているのでそれを使いましょう。例えば
- float型のプロパティ:SetFloat関数
- Color型のプロパティ:SetColor関数
- Vector4型のプロパティ:SetVector関数
などです。これを使うと値が瞬時に切り替わります。
もし値を滑らかに変化させたいなぁという場合はDOTween等のアセットを使うといいと思います(DOTweenにはマテリアルの値を滑らかに変更できるDOFloat関数などが用意されています)。DOTweenの使い方は下記の記事で詳しくご説明していますので、ご興味がありましたら併せてご覧ください。
おわりに
以上、マテリアルの値をC#スクリプトから変更する方法をサンプル付きでご紹介しました。
シェーダーのプロパティ名を確認する手順がちょっと難しいかもしれませんが、慣れれば何となくどれを指定すればいいのかがわかるようになると思います。いずれにしてもマテリアルの値をゲーム中に変更できると表現の幅が広がって便利なのでぜひ試してみてください。
この記事がゲーム開発のお役に立てば幸いです。