いんでぃーづ

ゲームいろいろ、いろいろ自由

Unity : エッジつきディゾルブシェーダーを自作する

前回 Shader Graph でディゾルブシェーダーを作りましたが、Shader Graph だと ComputBuffer に対応してなくて、
これだとやりたいことできへんやんということで結局コードを書くことにしました。

でせっかくなので紙が燃えるときのようなエッジのエフェクトを追加します。

f:id:sugar_affordance:20201130111032g:plain

シェーダーファイルの作成

プロジェクトウインドウで Create > Shader から適当にシェーダーを作ります。Unlit か Surface Shader ならいけると思います(試してない)。
自分は Universal Rendering Pipeline の Lit.hlsl をコピーして使いました。

プロパティの設定

Properties 欄にディゾルブ関係のプロパティを設定します。

    Properties
    {
        ....

        // Dissove Properties
        _DissoveTexture("Dissolve Texture", 2D) = "white" {}
        _EdgeColor("Edge Color", Color) = (1, 1, 1, 1)
        _EdgeTexture("Edge Texture", 2D) = "white" {}
        _DissolveThreshold("Dissove Threshold", Float) = 0.0
        _EdgeArea("Edge Area", Float) = 0.0
    }
  • _DissoveTexture
    どのように溶けていくかを指定する白黒のテクスチャです。黒い部分から消えていきます
  • _EdgeColor
    エッジ部分に合わせる色。なくてもいいです
  • _EdgeTexture
    エッジ部分に表示するテクスチャ
  • _DissolveThreshold
    スクリプトから設定して溶け具合を指定します
    マテリアルからこの値を設定すると、0 > 1 に向かって徐々に消えていきます
  • _EdgeArea
    端からどのくらいをエッジ部分とするかの値です

フラグメントシェーダー内でプロパティを参照できるようにする

HLSLPROGRAM の中で変数を定義します。プロパティと同名にすることで参照できるようになります。

            sampler2D _DissoveTexture;
            half4 _EdgeColor;
            sampler2D _EdgeTexture;
            half _DissolveThreshold;
            half _EdgeArea;

ディゾルブ効果の関数を作成する

Dissolve.hlsl という名前でファイルを作成し、以下のコードを作成。

ピクセルごとに

  • 通常の表面
  • エッジ部分
  • 透明部分(クリップ)

のどれを描画するかを計算しています。

half4 DissolveFragment(
    half4 color,
    half2 uv,
    half dissolveThreshold,
    sampler2D _DissoveTexture,
    half4 _EdgeColor,
    sampler2D _EdgeTexture,
    half _EdgeArea
)
{
    half albedoThreshold = clamp(dissolveThreshold + _EdgeArea, 0, 1);

    half4 dissoveTexture = tex2D(_DissoveTexture, uv);

    half albedoMask = ceil(clamp(dissoveTexture - albedoThreshold, 0, 1));
    half4 albedoColor = albedoMask * color;

    // Dissolve Edge
    half edgeThreshold = clamp(dissolveThreshold, 0, 1);
    half edgemask = ceil(clamp(dissoveTexture - edgeThreshold, 0, 1));
    half4 edgeColor = edgemask * abs(ceil(albedoMask) - 1) * tex2D(_EdgeTexture, uv) * _EdgeColor;

    color = albedoColor + edgeColor;

    clip(color.a - 0.001);

    return color;
}

clip 関数実行時に 0.001 を引いているのは、0だとクリップしてくれないのでゲタをはかせているかんじです。

フラグメントシェーダー内で関数を呼ぶ

            // 関数を使えるように include
            #include "Dissolve.hlsl"

           ...

                // フラグメントシェーダーの最後あたり
                color.rgb = MixFog(color.rgb, inputData.fogCoord);
                color.a = OutputAlpha(color.a);

                // ディゾルブ実行
                color = DissolveFragment(
                    color,
                    input.uv,
                    _DissolveThreshold,
                    _DissoveTexture,
                    _EdgeColor,
                    _EdgeTexture,
                    _EdgeArea
                );

                return color;
          }

マテリアルの設定

マテリアルは以下のようなかんじ

f:id:sugar_affordance:20201130114553p:plain


冒頭の動画で、出現させるときに球の表面に一部エッジが残っている部分がありますが、ディゾルブのテクスチャに漆黒(RGBが全部0)があるところが残っているのかなあと思うのでこれはテクスチャのほうでゲタはかせるのが一番簡単かも。

次はEmit効果を追加しようかな。


“Unity” and Unity logos are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere, and are used under license.


免責事項

当サイトの広告バナー、リンクによって提供される情報、サービス内容について、当サイトは一切の責任を負いません。

また、当サイトの情報を元にユーザ様が不利益を被った場合にも、当サイトは一切の責任を負いません。

すべて自己責任でお願いします。