表面着色器光照示例
下面的这些例子是表面着色器(Surface Shaders)中的自定义光照模式(custom lighting models)。普通光照模式的表面着色器在这页。
因为延时光照(Deferred lighting)不能与一些自定义 per-material 光照模式(lighting model)很好的运行,在下面大部分例子中我们只在着色器的正向渲染(Forward Rendering)中编译。
Diffuse 漫反射
Diffuse = 直射光颜色 * max(0,cos夹角(光和法线的夹角) )
Tip:cosθ = 光方向· 法线方向
我们从内置的Lambert光照模式(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"
}
下面是效果一个有纹理(texture)和一个没有真实的纹理(texture)。(在场景中有一个方向光):
image image现在,让我们来做一个完全一样的。但,是我们自己编写的光照模式(lighting model)而不是使用内置的Lambert。 表面着色器光照模式(Surface Shader Lighting Models)仅仅是需要我们编写的一些函数。下面是一个简单的Lambert。注意:"着色器部分"自身并没有改变(即下面的灰色部分)。
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) {
fixed diff = max (0, dot (s.Normal, lightDir));
fixed4 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
}
Fallback "Diffuse"
}
就这样我们这个点单的漫反射光照模式(Diffuse lighting model)是一个名叫LightingSimpleLambert的函数。它计算的是表面法线(surface normal)与灯光方向(light direction)的点积。然后应用于光线衰减和颜色。
Diffuse Wrap 漫反射遮蔽
下面是遮蔽的漫反射-漫反射光照的一种改进。照明"环绕(wraps around)"在物体的边缘。它对于假冒子表面(subsurface)散射效果(scattering effect)非常有用。同样的"着色器部分"自身并没有改变(即下面的灰色部分)。我们仅仅用了不同的光照函数(黑体字部分)。
Shader "Example/Diffuse Wrapped" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
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
}
Fallback "Diffuse"
}
image
image
Toon Ramp 卡通渐变
下面是一个"渐变(Ramp)"光照模式。他使用一个纹理(texture)定义渐变怎样在表面做出反应,反应角度通过光照方向和法线求得。导入卡通光照(Toon lighting)可以实现多种效果。
Shader "Example/Toon Ramp" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_Ramp ("Shading Ramp", 2D) = "gray" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
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,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
}
Fallback "Diffuse"
}
image
image
image
Simple Specular 简单的高光
Specular = 直射光*pow(max(cosθ,0),高光的参数)
Tips: θ:是反射光方向和视野方向的夹角
Tips: θ:是半角向量与法线向量的夹角
下面是一个简单的高光光照模式(specular lighting model)。它是内置的BlinnPhong,实际上做起来非常简单。放在这里仅仅是为了说明它是如何工作的。
Shader "Example/Simple Specular" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf SimpleSpecular
half4 LightingSimpleSpecular (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {
half diff = max (0, dot (s.Normal, lightDir));
//phong模型
//光线的反射方向.点到摄像机
// half3 reflectDir = normalize(reflect(-lightDir, s.Normal));
// float nh = max (0, dot (reflectDir, viewDir));
//Blinn-phong
//半角向量.发线向量
//1.半角向量:求(点到光源+点到摄像机)的单位向量,他们的中间平均值
half3 h = normalize (lightDir + viewDir);
//2.高光底数【半角向量与法线向量的余弦值】
float nh = max (0, dot (s.Normal, h));
//3.高光系数:根据高光低数和高光指数求得
float spec = pow (nh, _Spec);
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
}
Fallback "Diffuse"
}
image
image
网友评论