本日はshader学習枠です。
昨日はアルファクリップの基礎部分を作りました。
今回は画像を設定して画像をくりぬき表示できるシェーダーを作ります。
〇テクスチャのくりぬきシェーダー
まずはアルファクリップを行うための画像を使用するためにPropertiesブロックに_MainTexを追加します。
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_MainColor("Color" ,color) = (1,1,1,1)
_Alpha("Alpha" ,float) =1
_AlphaThreshold("AlphaThreshold",float)=0.5
}
これでマテリアル側でテクスチャを指定できるようになります。

次にHLSL文内部で定義した_MainTexを定義します。
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
float4 _MainColor;
float _Alpha;
float _AlphaThreshold;
ここではTEXTURE2Dという型で画像を定義しています。
またSAMPLERはサンプラーという意味でこれはテクスチャを描画するための構造体です。
これはCore.hlslで定義されており、URP専用の書き方になります。
ビルドインでは次のように定義します。
sampler2D _MainTex;
float4 _MainTex_ST;
Shaderではテクスチャを貼り付ける際にメッシュの持つテクスチャ座標を使用します。
これはUVと呼ばれるものでメッシュのどの部分にテクスチャのどの部分を貼り付けるか?というパラメータになっており、モデルに依存しています。

モデルの情報を扱うため構造体にuvを定義します。
struct appdata
{
float4 vertex : POSITION;
half3 normal: NORMAL;
float2 uv : TEXCOORD0;//追加
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 normalWS : TEXCOORD1;
float4 shadowCoord : TEXCOORD3;
float2 uv : TEXCOORD0;//追加
};
ここではTEXCOORD0というセマンティクスを使用しています。
これは2D座標を扱うものです。
〇頂点シェーダー
頂点シェーダーでは特に処理を行うことはなくテクスチャをサンプリングするフラグメントシェーダーにデータを渡します。
v2f vert (appdata v)
{
v2f o;
// o.vertex = TransformObjectToHClip(v.vertex);
//面の法線を取得、ライトの当たる向きを計算
VertexNormalInputs normal = GetVertexNormalInputs(v.normal);
o.uv = v.uv;//追加
o.normalWS = normal.normalWS;
VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
o.vertex = vertexInput.positionCS;
o.shadowCoord = GetShadowCoord(vertexInput);
return o;
}
〇フラグメントシェーダー
フラグメントシェーダーは次のようになります。
float4 frag (v2f i) : SV_Target
{
float4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv) *_MainColor;
//Light.hlslで提供されるUnityのライトを取得する関数
Light lt = GetMainLight(i.shadowCoord);
//ライトの向きを計算
float strength = dot(lt.direction, i.normalWS);
float4 lightColor = float4(lt.color, 1)*(lt.distanceAttenuation * lt.shadowAttenuation);
col = col* lightColor*strength;
col.a = (_AlphaThreshold<col.a)? 1:0;
return col;
}
SAMPLE_TEXTURE2D(画像, サンプラー, UV座標) の形で画像をサンプリングすることができます。
ここで最終出力のcolのα値が画像のα値になります。
_AlphaThresholdと比較して最終的なα値が0,1に分かれます。
col.a = (_AlphaThreshold<col.a)? 1:0;
これによってテクスチャのクリッピングが可能になります。

_AlphaThresholdの値を変えることで画像の持つα値のくりぬき範囲を調整できます。

本日は以上です。
〇コード
Shader "Unlit/TutorialShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_MainColor("Color" ,color) = (1,1,1,1)
_Alpha("Alpha" ,float) =1
_AlphaThreshold("AlphaThreshold",float)=0.5
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
AlphaToMask On
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct appdata
{
float4 vertex : POSITION;
half3 normal: NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 normalWS : TEXCOORD1;
float4 shadowCoord : TEXCOORD3;
float2 uv : TEXCOORD0;
};
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
float4 _MainColor;
float _Alpha;
float _AlphaThreshold;
v2f vert (appdata v)
{
v2f o;
// o.vertex = TransformObjectToHClip(v.vertex);
//面の法線を取得、ライトの当たる向きを計算
VertexNormalInputs normal = GetVertexNormalInputs(v.normal);
o.uv = v.uv;
o.normalWS = normal.normalWS;
VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
o.vertex = vertexInput.positionCS;
o.shadowCoord = GetShadowCoord(vertexInput);
return o;
}
float4 frag (v2f i) : SV_Target
{
float4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv) *_MainColor;
//Light.hlslで提供されるUnityのライトを取得する関数
Light lt = GetMainLight(i.shadowCoord);
//ライトの向きを計算
float strength = dot(lt.direction, i.normalWS);
float4 lightColor = float4(lt.color, 1)*(lt.distanceAttenuation * lt.shadowAttenuation);
col = col* lightColor*strength;
col.a = (_AlphaThreshold<col.a)? 1:0;
return col;
}
ENDHLSL
}
}
)