镜面反射,是指若反射面比较光滑,当平行入射的光线射到这个反射面时,仍会平行地向一个方向反射出来,这种反射就属于镜面反射,其反射波的方向与反射平面的法线夹角(反射角),与入射波方向与该反射平面法线的夹角(入射角)相等,且入射波、反射波,及平面法线同处于一个平面内。
Shader "ApcShader/DiffusePerVetex"
{
//属性
Properties{
_Diffuse("Diffuse", Color) = (1,1,1,1)
}
//子着色器
SubShader
{
Pass
{
//定义Tags
Tags{ "RenderType" = "Opaque" }
CGPROGRAM
//引入头文件
#include "Lighting.cginc"
//定义Properties中的变量
fixed4 _Diffuse;
//定义结构体:应用阶段到vertex shader阶段的数据,如果定义了
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
//定义结构体:vertex shader阶段输出的内容
struct v2f
{
float4 pos : SV_POSITION;
fixed4 color : COLOR;
};
//定义顶点shader
v2f vert(a2v v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//把法线转化到世界空间
float3 worldNormal = mul(v.normal, (float3x3)_World2Object);
//归一化法线
worldNormal = normalize(worldNormal);
//把光照方向归一化
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//根据兰伯特模型计算顶点的光照信息,dot可能有负值,小于0的部分可以理解为看不见,直接取0
fixed3 lambert = max(0.0, dot(worldNormal, worldLightDir));
//最终输出颜色为lambert光强*材质diffuse颜色*光颜色
o.color = fixed4(lambert * _Diffuse.xyz * _LightColor0.xyz, 1.0);
return o;
}
//定义片元shader
fixed4 frag(v2f i) : SV_Target
{
return i.color;
}
//使用vert函数和frag函数
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
//前面的Shader失效的话,使用默认的Diffuse
FallBack "Diffuse"
}
我们放置两个基本几何体,看一下shader的效果:
Shader "ApcShader/DiffusePerPixel"
{
//属性
Properties{
_Diffuse("Diffuse", Color) = (1,1,1,1)
}
//子着色器
SubShader
{
Pass
{
//定义Tags
Tags{ "RenderType" = "Opaque" }
CGPROGRAM
//引入头文件
#include "Lighting.cginc"
//定义Properties中的变量
fixed4 _Diffuse;
//定义结构体:应用阶段到vertex shader阶段的数据
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
//定义结构体:vertex shader阶段输出的内容
struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
};
//定义顶点shader
v2f vert(a2v v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//把法线转化到世界空间
o.worldNormal = mul(v.normal, (float3x3)_World2Object);
return o;
}
//定义片元shader
fixed4 frag(v2f i) : SV_Target
{
//归一化法线,即使在vert归一化也不行,从vert到frag阶段有差值处理,传入的法线方向并不是vertex shader直接传出的
fixed3 worldNormal = normalize(i.worldNormal);
//把光照方向归一化
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//根据兰伯特模型计算像素的光照信息,小于0的部分理解为看不见,置为0
fixed3 lambert = max(0.0, dot(worldNormal, worldLightDir));
//最终输出颜色为lambert光强*材质diffuse颜色*光颜色
fixed3 diffuse = lambert * _Diffuse.xyz * _LightColor0.xyz;
return fixed4(diffuse, 1.0);
}
//使用vert函数和frag函数
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
//前面的Shader失效的话,使用默认的Diffuse
FallBack "Diffuse"
}
还是一个立方体和一个圆柱体,采用了逐像素着色后的结果:
Shader "ApcShader/HalfLambert"
{
//属性
Properties{
_Diffuse("Diffuse", Color) = (1,1,1,1)
}
//子着色器
SubShader
{
Pass
{
//定义Tags
Tags{ "RenderType" = "Opaque" }
CGPROGRAM
//引入头文件
#include "Lighting.cginc"
//定义Properties中的变量
fixed4 _Diffuse;
//定义结构体:应用阶段到vertex shader阶段的数据
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
//定义结构体:vertex shader阶段输出的内容
struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
};
//定义顶点shader
v2f vert(a2v v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//把法线转化到世界空间
o.worldNormal = mul(v.normal, (float3x3)_World2Object);
return o;
}
//定义片元shader
fixed4 frag(v2f i) : SV_Target
{
//归一化法线,即使在vert归一化也不行,从vert到frag阶段有差值处理,传入的法线方向并不是vertex shader直接传出的
fixed3 worldNormal = normalize(i.worldNormal);
//把光照方向归一化
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//半兰伯特光照,将原来(-1,1)区间的光照条件转化到了(0,1)区间,既保证了结果的正确,又整体提升了亮度,保证非受光面也能有光,而不是全黑
fixed3 lambert = 0.5 * dot(worldNormal, worldLightDir) + 0.5;
//最终输出颜色为lambert光强*材质diffuse颜色*光颜色
fixed3 diffuse = lambert * _Diffuse.xyz * _LightColor0.xyz;
return fixed4(diffuse, 1.0);
}
//使用vert函数和frag函数
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
//前面的Shader失效的话,使用默认的Diffuse
FallBack "Diffuse"
}
看一下兰伯特光照模型和半兰伯特光照模型的对比:
Shader "ApcShader/DiffuseWithTex"
{
//属性
Properties{
_Diffuse("Diffuse", Color) = (1,1,1,1)
_MainTex("Base 2D", 2D) = "white"{}
}
//子着色器
SubShader
{
Pass
{
//定义Tags
Tags{ "RenderType" = "Opaque" }
CGPROGRAM
//引入头文件
#include "Lighting.cginc"
//定义Properties中的变量
fixed4 _Diffuse;
sampler2D _MainTex;
//使用了TRANSFROM_TEX宏就需要定义XXX_ST
float4 _MainTex_ST;
//定义结构体:应用阶段到vertex shader阶段的数据
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
//定义结构体:vertex shader阶段输出的内容
struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
//转化纹理坐标
float2 uv : TEXCOORD1;
};
//定义顶点shader
v2f vert(a2v v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//把法线转化到世界空间
o.worldNormal = mul(v.normal, (float3x3)_World2Object);
//通过TRANSFORM_TEX宏转化纹理坐标,主要处理了Offset和Tiling的改变,默认时等同于o.uv = v.texcoord.xy;
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
//定义片元shader
fixed4 frag(v2f i) : SV_Target
{
//unity自身的diffuse也是带了环境光,这里我们也增加一下环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Diffuse.xyz;
//归一化法线,即使在vert归一化也不行,从vert到frag阶段有差值处理,传入的法线方向并不是vertex shader直接传出的
fixed3 worldNormal = normalize(i.worldNormal);
//把光照方向归一化
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//根据半兰伯特模型计算像素的光照信息
fixed3 lambert = 0.5 * dot(worldNormal, worldLightDir) + 0.5;
//最终输出颜色为lambert光强*材质diffuse颜色*光颜色
fixed3 diffuse = lambert * _Diffuse.xyz * _LightColor0.xyz + ambient;
//进行纹理采样
fixed4 color = tex2D(_MainTex, i.uv);
return fixed4(diffuse * color.rgb, 1.0);
}
//使用vert函数和frag函数
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
//前面的Shader失效的话,使用默认的Diffuse
FallBack "Diffuse"
}
Shader "ApcShader/DiffuseWithTexX"
{
//属性
Properties{
_Diffuse("Diffuse", Color) = (1,1,1,1)
_MainTex("Base 2D", 2D) = "white"{}
}
//子着色器
SubShader
{
Pass
{
//定义Tags
Tags{ "RenderType" = "Opaque" }
CGPROGRAM
//引入头文件
#include "Lighting.cginc"
//定义Properties中的变量
fixed4 _Diffuse;
sampler2D _MainTex;
//使用了TRANSFROM_TEX宏就需要定义XXX_ST
float4 _MainTex_ST;
//定义结构体:应用阶段到vertex shader阶段的数据,如果定义了
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
//定义结构体:vertex shader阶段输出的内容
struct v2f
{
float4 pos : SV_POSITION;
fixed4 color : COLOR;
//转化纹理坐标
float2 uv : TEXCOORD1;
};
//定义顶点shader
v2f vert(a2v v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//unity自身的diffuse也是带了环境光,这里我们也增加一下环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Diffuse.xyz;
//把法线转化到世界空间
float3 worldNormal = mul(v.normal, (float3x3)_World2Object);
//归一化法线
worldNormal = normalize(worldNormal);
//把光照方向归一化
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//根据兰伯特模型计算顶点的光照信息,dot可能有负值,小于0的部分可以理解为看不见,直接取0
fixed3 lambert = 0.5 * dot(worldNormal, worldLightDir) + 0.5;
//最终输出颜色为lambert光强*材质diffuse颜色*光颜色
o.color = fixed4(lambert * _Diffuse.xyz * _LightColor0.xyz + ambient, 1.0);
//通过TRANSFORM_TEX宏转化纹理坐标,主要处理了Offset和Tiling的改变,默认时等同于o.uv = v.texcoord.xy;
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
//定义片元shader
fixed4 frag(v2f i) : SV_Target
{
return i.color * tex2D(_MainTex, i.uv);
}
//使用vert函数和frag函数
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
//前面的Shader失效的话,使用默认的Diffuse
FallBack "Diffuse"
}
// Transforms 2D UV by scale/bias property
#define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
如果我们使用了这个宏,就需要在shader中定义我们要采样的纹理的一个系数,命名方式为 纹理名_ST,float4类型。那么这个值是什么呢?