- 高光原理:光线经物体的反射后的光线与视线夹角越小,高光越强,90度时,高光不存在。
用角度1计算高光:
Shader"Lesson/SpecDiffuse"
{
Properties{
_Diffuse("DiffuseColor",Color)=(1,1,1,1)
_ValveIndex("ValveIndex",Range(0.0,1.0))=0.5
_Specular("SpecularColor",Color)=(1,1,1,1)
_Gloss("Glossness",Range(1.0,256.0))=8.0
}
Subshader{
Pass{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM//运用CG
#pragma vertex vert
#pragma fragment frag //define name
#include "Lighting.cginc"
fixed4 _Diffuse;
fixed _ValveIndex;
fixed4 _Specular;
half _Gloss;
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f{
float4 Pos:SV_POSITION;
fixed3 worldNormal:TEXCOORD0;//0-7 储存一部分自定义的数据
float3 worldPos:TEXCOORD1;//世界坐标下的顶点位置
};
v2f vert(a2v v){
v2f o;
o.Pos=UnityObjectToClipPos(v.vertex);
o.worldPos=mul((float3x3)unity_ObjectToWorld,v.vertex);
o.worldNormal=normalize(mul((float3x3)unity_ObjectToWorld,v.normal));
return o;
}
fixed4 frag(v2f IN):SV_TARGET{
float3 lDir=normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse =_LightColor0*_Diffuse*max(0,(dot(IN.worldNormal,lDir)*_ValveIndex+(1-_ValveIndex)));//让所有的值都在0以上。
fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;
float3 vDir=normalize(_WorldSpaceCameraPos.xyz-IN.worldPos.xyz);//视线
float3 reflDir=normalize(reflect(-lDir,IN.worldNormal));//计算反射光线
fixed3 specular=_LightColor0*_Specular*pow(saturate(dot(vDir,reflDir)),_Gloss);//重点
fixed3 _color =ambient+diffuse+specular;
return fixed4(_color,1.0);
}
ENDCG
}
}
}
用角度2计算高光(省去了一步计算反射的过程,使最后的效果更平滑)
Shader"Lesson/HalfSpecDiffuse"
{
Properties{
_Diffuse("DiffuseColor",Color)=(1,1,1,1)
_ValveIndex("ValveIndex",Range(0.0,1.0))=0.5
_Specular("SpecularColor",Color)=(1,1,1,1)
_Gloss("Glossness",Range(1.0,256.0))=8.0
}
Subshader{
Pass{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM//运用CG
#pragma vertex vert
#pragma fragment frag //define name
#include "Lighting.cginc"
fixed4 _Diffuse;
fixed _ValveIndex;
fixed4 _Specular;
half _Gloss;
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f{
float4 Pos:SV_POSITION;
fixed3 worldNormal:TEXCOORD0;//0-7 储存一部分自定义的数据
float3 worldPos:TEXCOORD1;//世界坐标下的顶点位置
};
v2f vert(a2v v){
v2f o;
o.Pos=UnityObjectToClipPos(v.vertex);
o.worldPos=mul((float3x3)unity_ObjectToWorld,v.vertex);
o.worldNormal=normalize(mul((float3x3)unity_ObjectToWorld,v.normal));
return o;
}
fixed4 frag(v2f IN):SV_TARGET{
float3 lDir=normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse =_LightColor0*_Diffuse*max(0,(dot(IN.worldNormal,lDir)*_ValveIndex+(1-_ValveIndex)));//让所有的值都在0以上。
fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;
float3 vDir=normalize(_WorldSpaceCameraPos.xyz-IN.worldPos.xyz);//视线
float3 reflDir=normalize(reflect(-lDir,IN.worldNormal));//计算反射光线
float3 halfDir=normalize(lDir+vDir);
fixed3 specular=_LightColor0*_Specular*pow(saturate(dot(IN.worldNormal,halfDir)),_Gloss);//重点
fixed3 _color =ambient+diffuse+specular;
return fixed4(_color,1.0);
}
ENDCG
}
}
}
- Unity内置函数:
第一个函数 可以直接获得光源方向
可以将之前代码里获取lDir的方式改为:float3 lDir=normalize(UnityWorldSpaceLightDir(IN.worldPos));
- 阴影效果的实现:
光源Shadow Type设置为Soft Shadow,代码增添:FallBack "Specular" 意思是在我们的Shader中没有找到相应的阴影处理,就调用经典Specular的阴影处理。
- 延迟渲染发生在屏幕空间,不需要计算所有物体的光照,只计算能显示在屏幕上的像素光照信息。延迟渲染不允许我们渲染半透明物体。Unity处理不能渲染半透明物体的限制是通过使用在整个处理过程的结尾使用前向渲染来解决的。最后延迟渲染不支持关于纹理渲染器的接收阴影的标记。移动设备上延迟渲染的性能会比前向渲染的性能要差一些。
- 前向渲染:基础过程的结果就是把场景信息和一张渲染纹理填充在z buffer中。光照过程就是通过深度信息、法线信和specular power计算光照。光照在屏幕空间进行计算,所以消耗与需要计算的时间不取决于场景复杂程度。光照缓冲信息存在一张 ARGB32 Render Texture中,它包括漫反射光照在rgb通道,高光强度在a通道。所有物体再一次全部渲染,获取光照并与贴图和环境光混合计算。光照贴图也在最后一轮处理里面中使用。相机离得近的地方进行实时光照,只烘焙间接光照。相机离得远的地方,光全部烘。