ADSシェーダをテクスチャ対応させる
はじめに
以前にADSシェーダを作成しました。 今回はこのシェーダの拡散反射の色を単色ではなくテクスチャから指定するように改造します。
Unityのバージョン:2018.3.0b4
ソースコードの解説
全文
まずはソースコードを全文はります。
Shader "MyShader/PixelADSTexture"
{
Properties
{
[Header(Light)]
_LightDirection ("Light Direction", Vector) = (1.0, 1.0, -1.0, 1.0)
_Lambient ("Lambient", Vector) = (0.5, 0.5, 0.5, 1.0)
_Ldiffuse ("Ldiffuse", Vector) = (1.0, 1.0, 1.0, 1.0)
_Lspecular ("Lspecular", Vector) = (1.0, 1.0, 1.0, 1.0)
[Space]
[Header(Material)]
_MainTex ("Diffuse Texture", 2D) = "white" {}
_Kambient ("Kambient", Vector) = (0.1, 0.1, 0.1, 1.0)
_Kspecular ("Kspecular", Vector) = (0.5, 0.5, 0.5, 1.0)
_Shininess ("Shininess", float) = 150
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 normal : NORMAL;
float4 position : TEXCOORD0;
float2 uv : TEXCOORD1;
};
uniform float3 _LightDirection;
uniform float3 _Lambient;
uniform float3 _Ldiffuse;
uniform float3 _Lspecular;
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
uniform float3 _Kambient;
uniform float3 _Kspecular;
uniform float _Shininess;
void vert (in appdata v, out v2f o)
{
o.vertex = UnityObjectToClipPos(v.vertex);
o.normal = v.normal;
o.position = mul(UNITY_MATRIX_M, v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
}
void frag (in v2f i, out float4 col : SV_Target)
{
float3 normal = UnityObjectToWorldNormal(i.normal);
float3 l = normalize(_LightDirection);
float3 view = normalize(_WorldSpaceCameraPos - i.position);
float3 h = normalize(l + view);
float3 Iambient = _Lambient * _Kambient;
float3 tex = tex2D (_MainTex, i.uv);
float3 Idiffuse = _Ldiffuse * tex * max(dot(normal, _LightDirection), 0);
float3 Ispecular = _Lspecular * _Kspecular * pow(max(dot(normal, h), 0), _Shininess);
col = float4(Iambient + Idiffuse + Ispecular, 1);
}
ENDCG
}
}
}
プロパティ
プロパティと対応する変数の宣言の部分は次のとおりです。
Shader "MyShader/PixelADSTexture"
{
Properties
{
[Header(Light)]
_LightDirection ("Light Direction", Vector) = (1.0, 1.0, -1.0, 1.0)
_Lambient ("Lambient", Vector) = (0.5, 0.5, 0.5, 1.0)
_Ldiffuse ("Ldiffuse", Vector) = (1.0, 1.0, 1.0, 1.0)
_Lspecular ("Lspecular", Vector) = (1.0, 1.0, 1.0, 1.0)
[Space]
[Header(Material)]
_MainTex ("Diffuse Texture", 2D) = "white" {}
_Kambient ("Kambient", Vector) = (0.1, 0.1, 0.1, 1.0)
_Kspecular ("Kspecular", Vector) = (0.5, 0.5, 0.5, 1.0)
_Shininess ("Shininess", float) = 150
}
SubShader
{
Pass
{
CGPROGRAM
...
uniform float3 _LightDirection;
uniform float3 _Lambient;
uniform float3 _Ldiffuse;
uniform float3 _Lspecular;
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
uniform float3 _Kambient;
uniform float3 _Kspecular;
uniform float _Shininess;
...
ENDCG
}
}
}
前回と変わったのは_Kdiffuse
のかわりに_MainTex
を用意しているところですね。
_MainTex ("Texture", 2D) = "white" {}
がテクスチャのプロパティです。
"white"
でデフォルトのテクスチャを白にしています。
{}
の部分は昔のUnityでパラメータを渡すのに使われていたもののようです。
現在は使われていないようです。
テクスチャはsampler2D
型で受け取ります。
_MainTex
の他に_MainTex_ST
という変数が用意されています。
_MainTex_ST
という変数は_MainTex
を用意するとUnityによって裏で作られる変数です。
テクスチャのプロパティを用意すると、
テクスチャの変数の後ろに_ST
をくっつけた変数が宣言されます。
この変数にはテクスチャのタイリングとオフセットの値が入っています。
_ST
のxy成分がuvのスケーリングで、zw成分がuvの平行移動成分になっています。
構造体
頂点シェーダの入力の構造体は次のとおりです。
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
uv座標をTEXCOORD0
で受け取っています。
頂点シェーダからフラグメントシェーダへ渡す構造体は次のとおりです。
struct v2f
{
float4 vertex : SV_POSITION;
float3 normal : NORMAL;
float4 position : TEXCOORD0;
float2 uv : TEXCOORD1;
};
uv座標を受け渡すようにしています。
頂点シェーダ
頂点シェーダのコードは次のとおりです。
void vert (in appdata v, out v2f o)
{
o.vertex = UnityObjectToClipPos(v.vertex);
o.normal = v.normal;
o.position = mul(UNITY_MATRIX_M, v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
}
以前と比べてo.uv = TRANSFORM_TEX(v.uv, _MainTex);
の処理が追加されています。
TRANSFORM_TEX
はUnityが用意しているマクロの1つです。
これは次のような処理に展開されます。
o.uv = v.uv * _MainTex_ST.xy + _MainTex_ST.zw;
フラグメントシェーダ
void frag (in v2f i, out float4 col : SV_Target)
{
float3 normal = UnityObjectToWorldNormal(i.normal);
float3 l = normalize(_LightDirection);
float3 view = normalize(_WorldSpaceCameraPos - i.position);
float3 h = normalize(l + view);
float3 Iambient = _Lambient * _Kambient;
float3 tex = tex2D (_MainTex, i.uv);
float3 Idiffuse = _Ldiffuse * tex * max(dot(normal, _LightDirection), 0);
float3 Ispecular = _Lspecular * _Kspecular * pow(max(dot(normal, h), 0), _Shininess);
col = float4(Iambient + Idiffuse + Ispecular, 1);
}
float3 tex = tex2D (_MainTex, i.uv);
がテクスチャから色を読み出すところです。
読み出した色をdiffuseの色として使っています。
実行結果
テクスチャとして次の画像を与えます。
描画結果は次のようになります。
タイリングとオフセットを変化させてみます。
確かに変更されていることがわかります。
おわりに
今回は自作のシェーダにテクスチャを与えてみました。
ソースコードはこちらのリポジトリにおいてあります。