He aquí dos ejemplos de custom lighting models en Surface Shaders. Ejemplos generales del Surface Shader están en esta página.
Ya que Deferred Lighting no funciona bien con algunos modelos de iluminación personalizados por-material, en la mayoría de ejemplos a continuación nosotros hacemos que los sombreadores compilen a solamente Forward Rendering.
Vamos a comenzar con un sombreador que utilice el modelo integrado de iluminación Lambert:-
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"
}
He aquí cómo se ve con una textura y sin una textura (una directional light está en la escena):
Ahora, hagamos exactamente lo mismo, pero escribamos nuestro propio modelo de iluminación en vez de utilizar el Lambert integrado. Surface Shader Lighting Models son solo algunas funciones que necesitamos escribir. He aquí un Lambert sencillo. Tenga en cuenta que solamente la sección CGPROGRAM cambia; el código de sombreado(shader code) alrededor es exactamente el mismo:-
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);
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"
}
Entonces nuestro modelo de Iluminación Diffues simple es en función LightingSimpleLambert
. Este computa la iluminación utilizando el producto punto entre la normal de la superficie y la dirección de la luz, y luego aplica una atenuación de luz y color.
He aquí un Wrapped Diffuse - una modificación de Diffuse lighting, dónde la iluminación “wraps(envuelve) el alrededor” de los bordes de los objetos. Es útil para falsificar el efecto de dispersión del subsuelo. Debido a que es solo la sección CGPROGRAM la que cambia, una vez más, el código de sombreador alrededor es omitido:-
...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);
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...
He aquí un modelo de iluminación “Ramp” que utiliza una rampa de textura para definir cómo la superficie responde al ángulo entre la luz y la normal. Esto puede ser utilizado para una variedad de efectos, incluyendo Toon lighting.
...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;
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...
He aquí un modelo de iluminación especular simple. Es bastante sencillo a comparación de lo que el integrado BlinnPhong en realidad hace; nosotros simplemente lo colocamos aquí para ilustrar cómo es hecho.
...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;
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...
Nosotros vamos a comenzar con un sombreador que imita la decodificación lightmap integrada y utiliza la función integrada de Unity DecodeLightmap para decodificar información de datos almacenados en texturas lightmap y de la macro UNITY_DIRBASIS integrada definiendo vectores de base para Directional lightmaps:
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);
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_DirLightmap (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"
}
Ahora, agreguemos algún tone mapping para la luz almacenada en lightmaps:
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); 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_DirLightmap (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"
}