4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

KLab EngineerAdvent Calendar 2019

Day 22

禍つヴァールハイトで実装された雪シェーダーを紹介します

Last updated at Posted at 2019-12-21

この記事は KLab Advent Calendar 2019 22日目の記事です。

はじめに

こんにちは、クライアントエンジニアのnorm81です。

禍つヴァールハイトではクリスマスイベントが絶賛開催中です。
今回はクリスマスイベントで実装された雪シェーダーを紹介します。
紹介する動作確認済み環境は Unity 2017.4.29f1 になります。

実装されたシェーダー

・地面に雪が積もるシェーダー
・天井に雪が積もるシェーダー
・スクリーンベースの雪が降るシェーダー

norm81が主に担当したのは地面に雪が積もるシェーダーですが
それ以外も各項で紹介します。

地面に雪が積もるシェーダー

snow1.gif
専用のマスクテスクチャを使ってマスクの白い部分から、
マテリアルに設定されたレンジ値を基に、順々に表示されています。
頂点ごとに接線と角度計算して屋根にも使っています。

マスクテクスチャ
マスクテクスチャ

プロパティ
snow1_prop.gif

関連箇所を抜き取ったシェーダー

snow1.shader
sampler2D _HeightmapTex; // マスクテクスチャ
half _Snow; // Snow Level: レンジ域
half _SnowOffset; // Snow Offset: レンジ基準値オフセット
half _SnowSmooth; // Snow Smooth: 境界値付近のアルファ値
half4 _SnowColor; // Snow Color: 対象を上書きする色
half4 _SnowDirection; // Snow Ditection: 角度差の基準とする法線

v2f vert(appdata_t v)
{
    v2f f;

    // 省略
    float3 worldSpaceNormal = mul(unity_ObjectToWorld, v.normal).xyz;
    worldSpaceNormal = normalize(worldSpaceNormal);

    // NOTE: fragで計算した方がレンジの反映精度が高いが、計算回数の省略目的とstep境界値付近のぼかしにv2fの補間を使っている。
    float theta = dot(worldSpaceNormal, _SnowDirection.xyz);
    float threshold = (0.5 - _Snow) * 2.0;
    f.snowalpha = _SnowColor.a * (1 - step(theta, threshold));
    // 省略
    return f;
}

half4 frag(v2f f) : COLOR
{
    half3 color = tex2D(_MainTex, f.uv);

    // 省略
    half3 Heightmap = tex2D(_HeightmapTex, f.uv.xy);
    float snowHeight = (1.0 - Heightmap.r) + _Snow + _SnowOffset;
    float snowAlpha = f.snowalpha * saturate((snowHeight - 1.0 + 0.0001) / (_SnowSmooth + 0.0001)); // 0.0001: Check division by zero.
    color = lerp(color, _SnowColor.rgb, snowAlpha * step(1.0, snowHeight));
    // 省略
    return half4(color, 1.0);
}

天井に雪が積もるシェーダー

snow2.gif
天井と記載しているのは、上面図のマスクテクスチャを使っているためです。
メリットとして可視範囲を上手くフォローできればテクスチャ最小1枚ですむので
メモリが節約できます。

マスクテクスチャ
マスクテクスチャ

スクリーンベースの雪が降るシェーダー

snow3.gif
下位互換のため、GPU インスタンシングではなく
必要なパーティクル数に分割した格子メッシュを用意します。

用意したメッシュの頂点入力について下記セマンテイクスを流用する形でベイクします。
・法線:座標変換前の基点座標
・カラー:アニメーション座標

マスクテクスチャ

あとは、自前シェーダーでパーティクル要件として座標変換・描画以外に
ビルボード処理などを行なっています。

おわりに

雪の足跡を作るとか、キャラクター形状に雪が積もるとか
某ステルスアクションゲームのような実装みたいなことをやってみたいです。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?