以下は Surface Shaders の Custom Lighting Model のサンプルです。 一般的なサーフェイスシェーダの例は,このページ にあります。
遅延ライティングは,カスタムのマテリアルごとのライティング モデルによってはうまく機能しないため,以下のほとんどの例では,シェーダにはフォワード レンダリングにのみコンパイルさせます。
組み込みランバート ライティング モデルを使用するシェーダから始めましょう。
Shader "Example/Diffuse Texture" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
以下は,テクスチャがある場合と,実際のテクスチャがない場合にどのように見えるかの例です (1 つのディレクショナル ライトがシーンにあります)。
まったく同じ事をしますが,組み込みのランバート ライティング モデルを使用する代わりに,_自身のライティング モデル_を記述します。 Surface Shader Lighting Models は,記述する必要のある関数です。 以下は簡単なランバート ライティング モデルです。 シェーダ部分 自体 (グレーの箇所) は変更されていないことに留意して下さい :
Shader "Example/Diffuse Texture" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf SimpleLambert
half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * 2);
c.a = s.Alpha;
return c;
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
そのため,ここでの簡単なデフューズ ライティング モデルは,LightingSimpleLambert
関数です。 表面法線と光方向間のドット積を行うことでライティングを計算し,光の軽減および色を適用します。
以下はラップされたデフューズ,デフューズ ライティングの変形で,照明がオブジェクトの端を ラップ します。 サブ表面散乱効果のフェークに便利です。 改めて言いますが,サーフェイスシェーダ自体はまったく変わっていません。別のライティング関数を使用しているだけです。
...ShaderLab code...
CGPROGRAM
#pragma surface surf WrapLambert
half4 LightingWrapLambert (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half diff = NdotL * 0.5 + 0.5;
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2);
c.a = s.Alpha;
return c;
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
...ShaderLab code...
以下は,表面が光と法線間の角度にどのように対応するかを定義するためにテクスチャを使用する Ramp ライティング モデルです。 これは,トゥーン ライティングなどの各種効果に使用できます。
...ShaderLab code...
CGPROGRAM
#pragma surface surf Ramp
sampler2D _Ramp;
half4 LightingRamp (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half diff = NdotL * 0.5 + 0.5;
half3 ramp = tex2D (_Ramp, float2(diff)).rgb;
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
c.a = s.Alpha;
return c;
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
...ShaderLab code...
以下は簡単なスペキュラ ライティング モデルです。 組み込みの BlinnPhong が実際に行うことを非常に簡単に行えます。ここでは,どのように行われるかを例示するためにこれを挿入します。
...ShaderLab code...
CGPROGRAM
#pragma surface surf SimpleSpecular
half4 LightingSimpleSpecular (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {
half3 h = normalize (lightDir + viewDir);
half diff = max (0, dot (s.Normal, lightDir));
float nh = max (0, dot (s.Normal, h));
float spec = pow (nh, 48.0);
half4 c;
c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * (atten * 2);
c.a = s.Alpha;
return c;
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
...ShaderLab code...
ビルトイン ライトマップのデコードして Unity ビルトイン 関数 DecodeLightmap を使用してライトマップテクスチャおよびビルトイン UNITY_DIRBASIS マクロを使用して方向性ライトマップの基本ベクトルを定義に格納されたデータのデコード,を再現するシェーダを始めてみます:
Shader "Example/Standard Lightmap Decoding" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Standard
half4 LightingStandard (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half4 c; c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * 2);
c.a = s.Alpha;
return c;
}
inline fixed4 LightingStandard_SingleLightmap (SurfaceOutput s, fixed4 color) {
half3 lm = DecodeLightmap (color);
return fixed4(lm, 0);
}
inline fixed4 LightingStandard_DualLightmap (SurfaceOutput s, fixed4 totalColor, fixed4 indirectOnlyColor, half indirectFade) {
half3 lm = lerp (DecodeLightmap (indirectOnlyColor), DecodeLightmap (totalColor), indirectFade);
return fixed4(lm, 0);
}
inline fixed4 LightingStandard_StandardLightmap (SurfaceOutput s, fixed4 color, fixed4 scale, bool surfFuncWritesNormal) {
UNITY_DIRBASIS
half3 lm = DecodeLightmap (color);
half3 scalePerBasisVector = DecodeLightmap (scale);
if (surfFuncWritesNormal)
{
half3 normalInRnmBasis = saturate (mul (unity_DirBasis, s.Normal));
lm *= dot (normalInRnmBasis, scalePerBasisVector);
}
return fixed4(lm, 0);
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
次に,ライトマップに格納されたトーンマッピングを追加してみます:
Shader "Example/Tonemapped Lightmap Decoding" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_Gain ("Lightmap tone-mapping Gain", Float) = 1
_Knee ("Lightmap tone-mapping Knee", Float) = 0.5
_Compress ("Lightmap tone-mapping Compress", Float) = 0.33
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Tonemapped
half4 LightingTonemapped (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half4 c; c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * 2); c.a = s.Alpha;
return c;
}
half _Gain;
half _Knee;
half _Compress;
inline half3 TonemapLight (half3 i) {
i *= _Gain;
return (i > _Knee)? (((i - _Knee)*_Compress)+_Knee): i;
}
inline fixed4 LightingTonemapped_SingleLightmap (SurfaceOutput s, fixed4 color) {
half3 lm = TonemapLight(DecodeLightmap (color));
return fixed4(lm, 0);
}
inline fixed4 LightingTonemapped_DualLightmap (SurfaceOutput s, fixed4 totalColor, fixed4 indirectOnlyColor, half indirectFade) {
half3 lm = TonemapLight(lerp (DecodeLightmap (indirectOnlyColor), DecodeLightmap (totalColor), indirectFade));
return fixed4(lm, 0);
}
inline fixed4 LightingTonemapped_StandardLightmap (SurfaceOutput s, fixed4 color, fixed4 scale, bool surfFuncWritesNormal) {
UNITY_DIRBASIS
half3 lm = TonemapLight(DecodeLightmap (color));
half3 scalePerBasisVector = DecodeLightmap (scale);
if (surfFuncWritesNormal)
{
half3 normalInRnmBasis = saturate (mul (unity_DirBasis, s.Normal));
lm *= dot (normalInRnmBasis, scalePerBasisVector);
}
return fixed4(lm, 0);
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffuse"
}