知識0からのUnityShader勉強

知識0からのUnityShader勉強

UnityのShaderをメインとして、0から学んでいくブログです。

【UnityShader】テクスチャのブレンド #13

前回の成果

soramamenatan.hatenablog.com

uvスクロールができるようになった。

今回やること

nn-hokuson.hatenablog.com

テクスチャのブレンドをしていきます!

事前準備

f:id:soramamenatan:20190729124159p:plain

SecneにPlaneを置いて、カメラから見えるようにしてください。

テクスチャのブレンドでは、

  • メインテクスチャ
  • サブテクスチャ
  • Mask画像

の3つが必要となるので用意してください。

今回使用した画像サイト様です。

メインテクスチャ publicdomainq.net

サブテクスチャ frame-illust.com

マスク画像 tearslabnscr.blog.fc2.com

ソースコード

Shader "Custom/textureBlend" {

    Properties {
        _MainTex ("Main Texture", 2D) = "white" {}
        _SubTex ("Sub Texture", 2D) = "white" {}
        _MaskTex ("Mask Texture", 2D) = "white" {}
    }
    SubShader {
        Tags { "RenderType" = "Opaque"}
        LOD 200

        CGPROGRAM
        #pragma surface surf Standard fullforwardshadows
        #pragma target 3.0

        struct Input {
            float2 uv_MainTex;
        };

        sampler2D _MainTex;
        sampler2D _SubTex;
        sampler2D _MaskTex;

        void surf (Input IN, inout SurfaceOutputStandard o) {
            fixed4 mainPixel = tex2D (_MainTex, IN.uv_MainTex);
            fixed4 subPixel = tex2D (_SubTex, IN.uv_MainTex);
            fixed4 mask = tex2D (_MaskTex, IN.uv_MainTex);
            o.Albedo = lerp (mainPixel, subPixel, mask);
        }
        ENDCG
    }
    FallBack "Diffuse"
}

今回行なっていることは、各テクスチャのピクセルの色情報を元に、Albedoを変更しているように見えます。

マスク画像

マスク処理は、特定の部分のみを表示(抽出)し、それ以外の部分を表示しない(黒色画像または白色画像)ようにする画像処理のことをいいます。

マスク処理を行うためには、表示(抽出)したい部分は、どこなのかを表す基準画像をあらかじめ用意する必要があります。:リモートセンシング画像処理>マスクより引用

とあります。
今回の場合では、特定の部分のみ抽出したいのでこのマスク画像を使用します。

今回はこのような

f:id:soramamenatan:20190729113726p:plain

【画像処理】マスク処理とマスク画像 | 技術雑記:より引用

くっきりとしたマスク画像ではなく、徐々に変化していくマスク処理を行いたいため、マスク画像をこのような

f:id:soramamenatan:20190729114657j:plain 少しぼやけた画像にしています。

ぼやけた画像にすることによって、その明度からメインテクスチャとサブテクスチャのブレンドをする割合を調整することができます。

これは以前行なったグレースケールと同じです。
グレースケールについてはこちらを参照してください。

soramamenatan.hatenablog.com

Lerp

この関数はTimeと同じでShader側で予め定義されている関数になります。
これは数学の線形補間と同じもので、

// start ... 始点
// end   ... 終点
// time  ... 割合
lerp (start, end, time);

となっています。
timeで、startとendの間を補間し、timeは0~1の範囲に固定されています。
この0~1というのは、startを0、endを1として、現在の割合を示しています。

これを利用して、メインテクスチャとサブテクスチャの割合をグレースケールで補間しています。

qiita.com

アタッチ

Scene上においた、Planeに対して、今回制作したShaderをアタッチします。
そして、

f:id:soramamenatan:20190729124852p:plain

上の図のように、

  • Main TextureにレンガのTexture
  • Sub Textureに模様のTexture
  • Mask Textureにマスク画像

をアタッチしてください。

今回の成果

f:id:soramamenatan:20190729125438p:plain

マスク画像のように合わせてテクスチャのブレンドができました。

このテクスチャブレンドを時間によって変化させます。

上記のソースコードのAlbedoの部分を

o.Albedo = lerp (mainPixel, subPixel, mask);

このように、* abs(_SinTime.w)を追加します。

o.Albedo = lerp (mainPixel, subPixel, mask) * abs(_SinTime.w));

こうすることで、

f:id:soramamenatan:20190729142548g:plain

このように、時間によってテクスチャブレンドをしてくれるようになります。

どうしてこうなるのか

absは#7で行なった、絶対値のことです。

soramamenatan.hatenablog.com

不明なのは、_SinTime.wの方だと思います。

SinTime

このSinTimeは時間の正弦のことを表しています。

名称 用途
_SinTime.x time/8
_SinTime.y time/4
_SinTime.z time/2
_SinTime.w time

Timeとは異なっているので、気をつけてください。

f:id:soramamenatan:20190729152733p:plain

Top - nagatabi-p ページ!:より引用

SinTimeは上記の緑色の線で示されている、0~1を往復する波(正弦波)を描きます。
このままだと、マイナスの値になってしまうので、abs関数を使用しています。

ソースコードにコメントを付与

Shader "Custom/textureBlend" {
    // プロパティ
    Properties {
        // メインtexture
        _MainTex ("Main Texture", 2D) = "white" {}
        // サブtexture
        _SubTex ("Sub Texture", 2D) = "white" {}
        // マスク画像
        _MaskTex ("Mask Texture", 2D) = "white" {}
    }
    // Shaderの中身の記述
    SubShader {
        // 一般的なShaderを使用
        Tags { "RenderType" = "Opaque"}
        // しきい値
        LOD 200

        // cg言語記述
        CGPROGRAM
        // フォワードレンダリング
        #pragma surface surf Standard fullforwardshadows
        // Shader Model
        #pragma target 3.0

        // Input構造体
        struct Input {
            // テクスチャのuv座標
            float2 uv_MainTex;
        };

        // メインtexture
        sampler2D _MainTex;
        // サブtexture
        sampler2D _SubTex;
        // マスクtexture
        sampler2D _MaskTex;

        // surf関数
        void surf (Input IN, inout SurfaceOutputStandard o) {
            // メインtextureのピクセルの色
            fixed4 mainPixel = tex2D (_MainTex, IN.uv_MainTex);
            // サブtextureのピクセルの色
            fixed4 subPixel = tex2D (_SubTex, IN.uv_MainTex);
            // マスクtextureのピクセルの色
            fixed4 mask = tex2D (_MaskTex, IN.uv_MainTex);
            // マスクの色から時間で変化するテクスチャブレンドをする
            o.Albedo = lerp (mainPixel, subPixel, mask * abs(_SinTime.w));
        }
        // Shaderの記述終了
        ENDCG
    }
    // SubShaderが失敗した時に呼ばれる
    FallBack "Diffuse"
}

今回はこれで終了です。
ご視聴ありがとうございました!