知識0からのUnityShader勉強

知識0からのUnityShader勉強

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

【UnityShader】ステンドグラス #11

前回の成果

soramamenatan.hatenablog.com

LOD、CGPROGRAM、ENDCG、#pragma target、FallBackについて理解しました。

今回やること

nn-hokuson.hatenablog.com

今回はステンドグラスのようなシェーダーを実装していきます。

前準備

f:id:soramamenatan:20190712142042p:plain

SceneにPlaneを置き、今回制作したMaterialのinspectorにステンドグラスの画像をアタッチします。

画像はこちらのサイト様よりDLさせて頂きました。

https://pixabay.com/ja/photos/%E3%82%B9%E3%83%86%E3%83%B3%E3%83%89-%E3%82%B0%E3%83%A9%E3%82%B9-%E7%AA%93%E3%81%8B%E3%82%89%E3%81%99-63204/pixabay.com

ソースコード

Shader "Custom/stainedGlass" {
    Properties {
        _MainTex("Texture", 2D) = "white" {}
    }

    SubShader {
            Tags { "Queue" = "Transparent" }
            LOD 200

            CGPROGRAM
            #pragma surface surf Standard alpha:fade
            #pragma target 3.0

            struct Input {
                float2 uv_MainTex;
            };

            sampler2D _MainTex;

            void surf (Input IN, inout SurfaceOutputStandard o) {
                fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
                o.Albedo = c.rgb;
                o.Alpha = ((c.r * 0.3f + c.g * 0.59f + c.b * 0.11f) < 0.2) ? 1 : 0.4f;
            }
             ENDCG
    }
    FallBack "Diffuse"
}

やっていることは、Albedoとアルファ値を変えているだけですが、

o.Alpha = (c.r * 0.3f + c.g * 0.59f + c.b * 0.11f) < 0.2) ? 1 : 0.4f;

これがマジックナンバーの嵐で、アルファ値をどうしたいのかわかりません。

c.r * 0.3f + c.g * 0.59f + c.b * 0.11f

これは何をしているのかを解説していきます。
結論から述べるとこれはグレースケールをする値となります。
なので今回のシェーダーのsurf関数を少しいじると

void surf (Input IN, inout SurfaceOutputStandard o) {
    fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
    o.Albedo = dot(c.rgb, float3(0.3f, 0.59f, 0.11f));
    o.Alpha = 1;
}

こんな感じでグレースケールになります。
f:id:soramamenatan:20190712143853p:plain

今回グレースケールを用いる理由

テクスチャの色はtex2Dで取得できます。
しかし、取得できる色はRGBAのカラー情報なので、黒色だったらアルファ値を1にするということができません。

ここでグレースケールにすることによって、明度で明るい色か暗い色かを判定することができるので使用しています。

? 1 : 0.4f

次は

o.Alpha = (c.r * 0.3f + c.g * 0.59f + c.b * 0.11f) < 0.2) ? 1 : 0.4f;

の? 1 : 0.4fについて解説していきます。

これは三項演算子というもので、簡単にいうとif文を短くするものです。
例えば、

int a = 10;

があって、aが10ならaを5に、10でないなら10にしたいとします。
これを普通に書くと、

int a = 10;
if (a == 10) {
    a = 5;
} else {
    a = 10;
}

このようになると思います。
しかし、これだと冗長なので、

int a = 10;
a = a == 10 ? 5 : 10;

このようにすることで、コードを短くすることができます。

構文はこのようになっています。

条件式 ? true : false

docs.microsoft.com

今回の場合ですと、グレースケールした値が0.2以下の場合はアルファ値を1に、0.2より大きい場合は透明度を0.4にしています。

結果

f:id:soramamenatan:20190712150530p:plain

お〜〜〜!ステンドグラスっぽくなってます!

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

Shader "Custom/stainedGlass" {
    // プロパティ
    Properties {
        // テクスチャのデータ
        _MainTex("Texture", 2D) = "white" {}
    }
    // Shaderの中身の記述
    SubShader {
            // 半透明オブジェクトを一番最後に描画する
            Tags { "Queue" = "Transparent" }
            // しきい値
            LOD 200

            // cg言語記述
            CGPROGRAM
            // 透過させる
            #pragma surface surf Standard alpha:fade
            // Shader Model
            #pragma target 3.0
            // input構造体
            struct Input {
                // テクスチャのデータ
                float2 uv_MainTex;
            };

            // テクスチャのデータ
            sampler2D _MainTex;

            // surf関数
            void surf (Input IN, inout SurfaceOutputStandard o) {
                // テクスチャのピクセルの色
                fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
                // ベースカラー
                o.Albedo = c.rgb;
                // グレースケールから透明度を決める
                o.Alpha = ((c.r * 0.3f + c.g * 0.59f + c.b * 0.11f) < 0.2) ? 1 : 0.4f;

                // グレースケール用
                // fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
                // グレースケールにする
                // o.Albedo = dot(c.rgb, float3(0.3f, 0.59f, 0.11f));
                // o.Alpha = 1;
            }
            // Shaderの記述終了
            ENDCG
    }
    // SubShaderに失敗した時に呼ばれる
    FallBack "Diffuse"
}

今回はこれで終了です。
次回もシェーダーへの理解を深めていこうと思います!