本日はShader勉強枠です。
今回はオブジェクトをスライスするShaderを書いてみます。
〇オブジェクトをスライスするとは?
オブジェクトの一部の描画をClippingすることでオブジェクトの見た目の形状を変えます。
今回Shaderを勉強する中の目標の一つであるMRTKStanderdShaderではEdgeを落として丸みを持たせることや、テクスチャのAlphaによってClippingする機能があります。
〇スライスを扱うShaderを書く
前回のExample/Diffuse Detailを基にスライスする機能を追加します。
//シンタックス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;
これは名前からも想像できるようにワールド座標を扱う宣言になります。
●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以下の値を取ります。
(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で見た場合次のようになります。
以上でスライスを扱うShaderが書けました。
次回はこのスライスを扱うShaderをアレンジしていきます。