夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

UnityでShaderを勉強する その⑩ スライスを扱うShaderを書く

本日はShader勉強枠です。

今回はオブジェクトをスライスするShaderを書いてみます。

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

〇オブジェクトをスライスするとは?

 オブジェクトの一部の描画をClippingすることでオブジェクトの見た目の形状を変えます。

 f:id:Holomoto-Sumire:20200426115534j:plain

 今回Shaderを勉強する中の目標の一つであるMRTKStanderdShaderではEdgeを落として丸みを持たせることや、テクスチャのAlphaによってClippingする機能があります。

 f:id:Holomoto-Sumire:20191227180548j:plain

f:id:Holomoto-Sumire:20191024184914j:plain

〇スライスを扱うShaderを書く

 前回のExample/Diffuse Detailを基にスライスする機能を追加します。

redhologerbera.hatenablog.com

//シンタックスShaderの名前と格納場所
Shader "Example/Diffuse Detail"{

    Properties{
        _MainTex("Texture",2D) = "white"{}
        _BumpMap("Bumpmap", 2D) = "bump"{}
        _RimColor("Rim Color", Color) = (0.26,0.19,0.0)
            //リムpowerのレンジ defaultでは3に設定される。
            _RimPower("Rim Power", Range(0.5,8.0)) = 3.0
            //SecondryTexture
            _Detail("Detail", 2D) = "gray"{}
    }
        //Shaderの中身サブシェーダーではレンダリングパスの一覧を定義し、任意のオプションとしてすべてのパスに共通の State (状態)を設定します。追加で、サブシェーダーの特定の Tag を設定できます。
        SubShader{
        //RenderingType
            Tags{"RenderType" = "Opaque"}
            CGPROGRAM
            #pragma surface surf Lambert
        //Input構造体はテクスチャ座標として扱うものを記述します。
       struct Input {
           float2 uv_MainTex;
           float2 uv_BumpMap;
           float3 viewDir;
           float2 uv_Detail;
       };
       sampler2D _MainTex;
       sampler2D _BumpMap;
       float4 _RimColor;
       float _RimPower;
       sampler2D _Detail;
       void surf(Input IN, inout SurfaceOutput o) {
           o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
           //_Detailのrgbをo.Albedoに乗算
           o.Albedo *= tex2D(_Detail, IN.uv_Detail).rgb * 2;
           o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
           //rim = 1.0 -viewDirの正規化したものとノーマルマップの内積(0~1の値を取る)
           half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal));
           //Emissionに代入 propertyのRimColorの値(RGB)× rim^_RimPower= 0~1の値を取る 参考https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-pow 
           o.Emission = _RimColor.rgb * pow(rim, _RimPower);
       }
       ENDCG
    }
        Fallback "Diffuse"
}
●Properties

 スライス機能はテクスチャなどを別途用意するものではないのでPropertiesでは追加するパラメータはありません。

●Input構造体
Input{
 float2 uv_MainTex;
 float2 uv_BumpMap;
 float3 viewDir;
 float2 uv_Detail;
 float3 worldPos;
};

 ここで追加したものは以下の一文です。

float3 worldPos;

 これは名前からも想像できるようにワールド座標を扱う宣言になります。

docs.unity3d.com

●surfメソッド
        void surf (Input IN, inout SurfaceOutput o) {
             o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
           //Clipping
           clip (frac((IN.worldPos.y+IN.worldPos.z*0.1) * 5) - 0.5);
           //_Detailのrgbをo.Albedoに乗算
           o.Albedo *= tex2D(_Detail, IN.uv_Detail).rgb * 2;
           o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
           //rim = 1.0 -viewDirの正規化したものとノーマルマップの内積(0~1の値を取る)
           half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal));
           //Emissionに代入 propertyのRimColorの値(RGB)× rim^_RimPower= 0~1の値を取る 参考https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-pow 
           o.Emission = _RimColor.rgb * pow(rim, _RimPower);
        }

ここで追加されたのは以下の一文です。

clip (frac((IN.worldPos.y+IN.worldPos.z*0.1) * 5) - 0.5);

[clip()]では与えられた因数が0より小さい場合描画を行いません。 

frac()では()内の小数値の少数部分を返します。(例:frac(2.33331) =0.3331) この値は0以上1以下の値を取ります。

docs.microsoft.com

 (IN.worldPos.y+IN.worldPos.z*0.1)はワールド座標yと0.1倍されたzの和です。

clip (frac((IN.worldPos.y+IN.worldPos.z*0.1) * 5) - 0.5);

 は

 ワールド座標yと0.1倍されたzの和×5の少数部分から-0.5したものをマスクせよ

という処理になります。

ここまでのShaderは以下になります。

//シンタックスShaderの名前と格納場所
Shader "Example/Diffuse Detail"{

    Properties{
        _MainTex("Texture",2D) = "white"{}
        _BumpMap("Bumpmap", 2D) = "bump"{}
        _RimColor("Rim Color", Color) = (0.26,0.19,0.0)
            //リムpowerのレンジ defaultでは3に設定される。
            _RimPower("Rim Power", Range(0.5,8.0)) = 3.0
            //SecondryTexture
            _Detail("Detail", 2D) = "gray"{}
    }
        //Shaderの中身サブシェーダーではレンダリングパスの一覧を定義し、任意のオプションとしてすべてのパスに共通の State (状態)を設定します。追加で、サブシェーダーの特定の Tag を設定できます。
        SubShader{
        //RenderingType
            Tags{"RenderType" = "Opaque"}
            CGPROGRAM
            #pragma surface surf Lambert
        //Input構造体はテクスチャ座標として扱うものを記述します。
       struct Input {
           float2 uv_MainTex;
           float2 uv_BumpMap;
           float3 viewDir;
           float2 uv_Detail;
           float3 worldPos;
       };
       sampler2D _MainTex;
       sampler2D _BumpMap;
       float4 _RimColor;
       float _RimPower;
       sampler2D _Detail;
       void surf(Input IN, inout SurfaceOutput o) {
           o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
           //_Detailのrgbをo.Albedoに乗算
           o.Albedo *= tex2D(_Detail, IN.uv_Detail).rgb * 2;
          clip (frac((IN.worldPos.y+IN.worldPos.z*0.1) * 5) - 0.5);
           o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
           //rim = 1.0 -viewDirの正規化したものとノーマルマップの内積(0~1の値を取る)
           half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal));
           //Emissionに代入 propertyのRimColorの値(RGB)× rim^_RimPower= 0~1の値を取る 参考https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-pow 
           o.Emission = _RimColor.rgb * pow(rim, _RimPower);
       }
       ENDCG
    }
        Fallback "Diffuse"
}

これをUnityで見た場合次のようになります。

f:id:Holomoto-Sumire:20200426123648j:plain

 以上でスライスを扱うShaderが書けました。

次回はこのスライスを扱うShaderをアレンジしていきます。