Appearance
第10回 シェーダー連携1
前回: 第09回 UIエフェクト2 / 次回: 第11回 描画バッファとポストエフェクト
注意
この授業には提出課題があります
提出方法は 授業内で説明します
前回の振り返り
ゲージ UI を作りました
- 第09回では、ゲージ UI と
World Space Canvasを扱いました - 値の変化を視覚的に伝えるために、 マスクや
fillAmountを使いました - 今回は自作のシェーダーで 3D 空間上の斬撃エフェクトを作ります
今回作るもの
メッシュ上を走る斬撃
- リング状のメッシュを用意する
- シェーダーの計算で斬撃効果を移動させる
- マスクで斬撃の形を加工する
- ノイズを流して、内部の密度を変える
- 光る色と透明度を調整して仕上げる
今日のゴール
計算で形状を作り、パラメーターで動かす
- シェーダー側で、マスクやノイズを組み合わせて 斬撃が走ったように見せます
- 表示に使うメッシュの形は固定です 動いて見える効果は、シェーダー側の計算で作ります
メッシュを準備する
UV を斬撃の時間軸にする


リング状のメッシュにUVを割り当てた例 UVのUを動かせば斬撃が進むように見える
- メッシュを斬撃の通り道とします
UV.xを、斬撃が進む方向として使います- シェーダー側でUVを加工することで 「横長の画像の上を斬撃が進む」ように 扱います
最初の一歩
テクスチャーをスクロールさせる シェーダーを用意する

設定の例 作成した ShaderGraph のマテリアルを 3D メッシュに貼って テクスチャーが動いて見えることを確認します
URP Unlit Shader Graphをベースに ShaderGraph を作成します- プロパティに
Texture2Dを1つ追加floatを1つ追加します Sample Texture 2Dノードでテクスチャーを サンプリングして、UV をfloatでスクロール させます
このままテクスチャーで描いても構わないが
手続き的に絵を作る
- 斬撃の形をテクスチャーで描くのも悪くありませんが シェーダー側でマスクやノイズを組み合わせて 表現する方法もあります
- 計算で形状を操作できれば調整しやすく またアニメーション操作の幅が広がります
- こうした手続き的に表現を作る手法を プロシージャルと呼びます
計算でグラデーションを作る
UV の値からグラデーションを得る

ShaderGraphと適用例
UVの値は 0 から 1 の範囲で変化しますUV.xをそのまま使うと、左から右へUV.yを使うと、上下方向のグラデーションが 得られますUV.yからUV.xを引くと、左上から右下への グラデーションが得られます 今回はこれを斬撃の基本形状として使います
斬撃を動かす際の注意
計算の値は自動でラップしない

Modulo の使用例 1で割った余りを返すので、1を超えると0に戻る 負の値は今回の目的には使えないので注意
UVの値は自動でラップしません 0 から 1 の範囲を超えると、グラデーションは 消えたり真っ白になってしまったりします- 斬撃の位置を動かす場合は、
UVの値を 0 から 1 の範囲に収めるように計算する必要があります - ここでは
Moduloノードで値を折り返していますModuloは剰余(余り)を計算するノードで 値を 0 から 1 の範囲でラップするのに便利です
UV 計算のサブグラフ化
計算が複雑になってきたら


UV計算をサブグラフ化した例 ノイズ計算など複数のブロックにUVを引き回す際には サブグラフ化で整理すると便利
- UV に Phase を加えてModulo で折り返す計算は ShaderGraph 上では複雑な表示になります
- こうした計算は、サブグラフとしてまとめると 扱いやすくなります
- ある程度まとまった計算は、サブグラフにして 再利用しやすくしてみましょう
グラデーションに色を乗せる
SampleGradient の利用


SampleGradient の適用例 アルファも設定して、半透明描画で斬撃の端を 自然に消している
Sample Gradientノードを使うと、値を色に変換できますUVの計算で得たグラデーションをSample Gradientに入れるとことで、好みの着色が可能です- 透明度も同時に指定できます 斬撃の端を自然に消すために、アルファも設定してみましょう
注意
Sample Gradient は シェーダーのコードで 作られるので、 変更の際はShader Graph の 保存が必要です
パラメーターじゃなくて プログラムなのよ
さらに情報を載せる
ノイズの適用
- この状態でも最低限の斬撃表現にはなっていますが、内部に動きや密度の変化がないため、少し物足りない印象です
- ノイズを適用して、斬撃の内部にムラや流れを加えると、より勢いのある表現になります
- ノイズはテクスチャーを用意しても構いませんが、ShaderGraph の
Noiseノードを使って得ることも可能です ここではNoiseノードを使う方法を紹介します
ノイズを適用する
シンプルな乗算から


ノイズの適用例 単なる乗算でも一程度の効果が得られる
Noiseノードは、UV の値を元に ノイズの値を出力します- 斬撃のグラデーションにノイズを乗算するだけ でも最低限の効果は得られます
- ノイズ関数には
Gradient,Simple,Voronoiなどがあります 好みのものを選び、パラメーターを操作して みましょう
ノイズをスクロールさせる
斬撃の流れを作る

- ノイズのUVをスクロールさせると、斬撃の内部に流れが生まれます
Timeノードを使って、ノイズに与えるUVを動かしてみましょう- プロパティに
floatの値を追加して、TimeにMultiplyノードで乗算すれば ノイズの流れの速さを調整できます
濃度を制御する
Intensity プロパティを作る

- 斬撃エフェクトは出現してから消えるまでの 間に強さが変化するのが一般的です
- 斬撃の強さを制御するために
Intensityプロパティを作りグラデーションや ノイズに乗算してみましょう Intensityの値を操作することで、 斬撃の強さを時間変化させることができます
アニメーションさせる
スクリプトで制御する
PhaseやSpeed、Intensityなどのプロパティを スクリプトで操作してみましょうAnimationCurveを使って斬撃の出現から消滅までの強さを変化させると、より自然な表現になります
コード例 (1/2)
csharp
using UnityEngine;
[RequireComponent(typeof(MeshRenderer))]
public class CrescentSlash : MonoBehaviour
{
[Tooltip("自動でアニメーションを開始")]
[SerializeField] private bool playOnEnable = true;
[Tooltip("アニメーションの再生時間(秒)")]
[SerializeField, Min(0f)] private float lifeTime = 1f;
[Tooltip("ループ再生するかどうか")]
[SerializeField] private bool loop;
[Tooltip("シェーダー内部の Time に掛ける Speed 値")]
[SerializeField] private float speed = 1f;
[Tooltip("Phase の変化カーブ")]
[SerializeField] private AnimationCurve phaseCurve =
AnimationCurve.Linear(0f, 0f, 1f, 1f);
[Tooltip("Intensity の変化カーブ")]
[SerializeField] private AnimationCurve intensityCurve =
AnimationCurve.Linear(0f, 1f, 1f, 1f);csharp
private static readonly int SpeedPropertyId =
Shader.PropertyToID("_Speed");
private static readonly int PhasePropertyId =
Shader.PropertyToID("_Phase");
private static readonly int IntensityPropertyId =
Shader.PropertyToID("_Intensity");
private MeshRenderer _meshRenderer;
private MaterialPropertyBlock _propertyBlock;
private float _elapsedTime;
private bool _playing;
private void Awake()
{
_meshRenderer = GetComponent<MeshRenderer>();
_propertyBlock = new MaterialPropertyBlock();
}
private void OnEnable()
{
if (playOnEnable)
Play();
else
Apply(0f);
}コード例 (2/2)
csharp
private void Update()
{
if (!_playing)
return;
_elapsedTime += Time.deltaTime;
var normalizedTime = lifeTime <= 0f ?
1f :
Mathf.Clamp01(_elapsedTime / lifeTime);
Apply(normalizedTime);
if (normalizedTime < 1f)
return;
if (loop && lifeTime > 0f)
{
_elapsedTime %= lifeTime;
return;
}
_playing = false;
}csharp
public void Play()
{
_elapsedTime = 0f;
_playing = true;
Apply(0f);
}
public void Stop()
{
_playing = false;
}
private void Apply(float normalizedTime)
{
_meshRenderer.GetPropertyBlock(_propertyBlock);
_propertyBlock.SetFloat(SpeedPropertyId, speed);
_propertyBlock.SetFloat(PhasePropertyId,
phaseCurve.Evaluate(normalizedTime));
_propertyBlock.SetFloat(IntensityPropertyId,
intensityCurve.Evaluate(normalizedTime));
_meshRenderer.SetPropertyBlock(_propertyBlock);
}
}自由に作る
斬撃の形や色を調整する
- 斬撃の長さや速さ、ノイズの密度や流れの速さ、 色などはすべてノードで作られています 調整して、好みのエフェクトを作成しましょう
- ノイズも乗算するだけでなく、加算や
Lerpなどで組み合わせると さらに多様な表現が可能になります - 同時に複数のノイズやカラーを組み合わせるのも面白いでしょう 手元で自由に作成してみましょう
実習
斬撃を一つ完成させる
まずはやってみて
実習1:メッシュ上でテクスチャーをスクロール
まずはスクロールさせる
- リング状または三日月状のメッシュをシーンに配置する
URP Unlit Shader Graphを作成するTexture2DとPhaseプロパティを作るUV.x + Phaseを使ってテクスチャーをスクロールさせる- マテリアルをメッシュに貼り、
Phaseを変更して動くか確認する
- ここで動かない場合は、UV の向きやメッシュの UV 展開を確認します
実習2:グラデーションで形を作る
斬撃の基本形状を作る
UV.y - UV.xまたはUV.y + UV.xを使って斜めの値を作るModuloで 0 から 1 の範囲に折り返すSample Gradientで色と透明度を設定するPhaseを動かして、斜めの光が流れるか確認する- 端が不自然な場合は、Gradient の Alpha を調整する
- 斬撃の形は画像だけでなく、UV 計算でも作れます
実習3:ノイズを加える
斬撃の内部に情報量を足す
Noiseノードを追加する- ノイズ用の UV に
Time * Speedを足す - グラデーション結果とノイズを乗算する
Speedをプロパティ化して流れの速さを調整するIntensityを掛けて明るさを調整する
- ノイズは強すぎると斬撃の形に影響が出ます 最初は弱めにして、徐々に強くしてみましょう
実習4:スクリプトで再生する
Phase と Intensity を時間変化させる
CrescentSlashを斬撃メッシュに追加するPhaseの AnimationCurve を設定するIntensityの AnimationCurve を設定するlifeTimeを 0.2 から 0.6 秒程度にする- 再生して、出現から消滅までの流れを確認する
- 斬撃は長く残りすぎると重く見えます 短時間で出て、少し余韻を残して消してみましょう
課題の条件
以下を満たしてください
- メッシュに Shader Graph のマテリアルを適用している
Phaseなどの値で、斬撃が移動して見える- Gradient またはマスクで透明度を調整している
- ノイズを使って内部の密度や流れを表現している
Intensityなどで出現から消滅までの強さを変化させている- スクリーンショットまたは動画で提出する
余裕があれば挑戦
さらに斬撃らしくする
- 外側に薄い発光用のメッシュを重ねる
- 火花や小さな粒子を追加する
- 色を属性ごとに変える 炎、氷、雷、闇など
AddSubtractMultiplyLerpなどで複数のノイズを混ぜる- 剣のモーションに合わせて斬撃の位置や角度を調整する
提出時の説明
調整の意図を添えてください
- 何の斬撃を表現したか
- メッシュの形をどう決めたか
PhaseとSpeedをどう調整したか- ノイズをどの程度加えたか
Intensityの変化をどう設定したか- 改善したい点
今回のまとめ
斬撃はメッシュとシェーダーの組み合わせ
- メッシュは斬撃の通り道を決めます
- UV を加工すると、固定されたメッシュ上で 光が移動しているように見せられます
Sample Gradientを使うと、色と透明度をまとめて調整できます- ノイズを加えると、斬撃内部に流れや密度を作れます
Phase、Speed、Intensityを時間変化させることで ゲーム中で使える斬撃エフェクトになります