一、常用向量
- nDir:法线方向;
- LDir:光照方向;
- vDir:观察方向;
- rDir:光反射方向;
- hDir:半角方向(Halfway),LDir和vDir的中间角方向;
二、所在空间
- OS:ObjectSpace物体空间,本地空间;
- WS:WorldSpace世界空间;
- VS:ViewSpace观察空间;
- CS:HomogenousClipSpace齐次剪裁空间;
- TS:TangentSpace切线空间;
- TXS:TextureSpace纹理空间。
例如:nDirWS:世界空间下的法线方向。
三、镜面反射——Specular
- 因其反射有明显方向性,所以观察者的视角决定了反射光线的有无,明暗;
- 实现方式:
- Phong(r dot v):即光反射方向和视角方向越重合,反射越强;
- Blinn-Phong(n dot h):即法线方向和半角方向越重合,反射越强;
四、实现方式
1)Phong(r dot v)
光反射方向计算:rDir=Reflect(-LDir,nDir);
a.ShaderForge节点:
b.脚本实现
//镜面反射——Phong
Shader "Shader/U3D_003" {
Properties {
_MainColor("颜色",COLOR)=(1.0,1.0,1.0,1.0)
_SpecualrPow("高光次幂",range(1,90))=30
}
SubShader {
Tags {
"RenderType"="Opaque"
}
Pass {
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
uniform float3 _MainColor;
uniform float _SpecualrPow;
//输入结构
struct VertexInput {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
//输出结构
struct VertexOutput {
float4 posCS : SV_POSITION;
float4 posWS:TEXCOORD0;
float3 nDirWS:TEXCOORD1;
};
//输入结构>>>顶点Shader>>>输出结构
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.posCS = UnityObjectToClipPos( v.vertex );
o.posWS=mul(unity_ObjectToWorld, v.vertex);
o.nDirWS=UnityObjectToWorldNormal(v.normal);
return o; //将输出结构 输出
}
//输出结构>>像素Shader
float4 frag(VertexOutput i) : COLOR {
//准备向量
float3 nDir=i.nDirWS;
float3 lDir=normalize(_WorldSpaceLightPos0.xyz);
float3 rDir=reflect(-lDir,nDir);
float3 vDir=normalize(_WorldSpaceCameraPos.xyz-i.posWS.xyz);
//准备点积结果
float rDotv=dot(rDir,vDir);
float nDotl=dot(nDir,lDir);
//光照模型
float Phong=pow(max(0.0,rDotv),_SpecualrPow);
float lambert=max(0.0,nDotl);
float3 finalRGB=_MainColor*lambert+Phong;
return float4(finalRGB,1.0); //输出其最终颜色
}
ENDCG
}
}
FallBack "Diffuse"
CustomEditor "ShaderForgeMaterialInspector"
}
2)Blinn-Phong(n dot h)
a.ShaderForge节点:
b.脚本实现:
//镜面反射-Blinn-Phong Shader
Shader "Shader/U3D_002" {
Properties {
//暴露参数:高光次幂,基本颜色属性
//格式:_名称("面板标签",类型(参数,可无))=默认值
_MainColor("颜色", COLOR) =(1.0,1.0,1.0,1.0)
_SpecularPow("高光次幂", range(1,90)) =30
}
SubShader {
Tags {
"RenderType"="Opaque"
}
Pass {
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
//参数声明 先声明才能使用
//规则:要和Properties段定义的参数一一对应
// 适当选取数据类型
//修饰字 a.uniform 共享于vert,frag
// b.attribute 仅用于vert
// c.varing 用于vert,frag传数据
uniform float3 _MainColor;
uniform float _SpecularPow;
//输入结构
struct VertexInput {
float4 vertex : POSITION; //顶点信息 Get✔
float3 normal : NORMAL; //法线信息 Get✔
};
//输出结构
struct VertexOutput {
float4 posCS : SV_POSITION; //屏幕空间 顶点位置
float4 posWS : TEXCOORD0; //世界空间 顶点位置
float3 nDirWS:TEXCOORD1; //世界空间 法线方向
};
//输入结构>>>顶点Shader>>>输出结构
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0; //新建输出结构
o.posCS = UnityObjectToClipPos( v.vertex ); //变换顶点位置 OS>CS
o.posWS=mul(unity_ObjectToWorld, v.vertex); //变换顶点位置 OS>WS
o.nDirWS=UnityObjectToWorldNormal(v.normal); //变换法线方向 OS>WS
return o; //返回输出结构
}
//输出结构>>像素Shader
float4 frag(VertexOutput i) : COLOR {
//准备向量
float3 nDir=i.nDirWS; //获取nDir
float3 lDir=_WorldSpaceLightPos0.xyz; //获取IDir
float3 vDir=normalize(_WorldSpaceCameraPos.xyz-i.posWS.xyz); //获取vDir
float3 hDir=normalize(vDir+lDir); //获取hDir
//准备点积结果
float nDotl=dot(nDir,lDir); //nDir点乘IDir
float nDotH=dot(nDir,hDir); //nDir点乘HDir
//光照模型
float lambert=max(0.0,nDotl); //截断负值
float blinnPhong=pow(max(0.0,nDotH),_SpecularPow); //获取blinnPhong值
float3 finalRGB=_MainColor*lambert+blinnPhong; //混合颜色
//返回结果
return float4(finalRGB,1.0); //输出其最终颜色
}
ENDCG
}
}
FallBack "Diffuse"
CustomEditor "ShaderForgeMaterialInspector"
}
3)区别对比
a.计算过程上:Phong比Blinn-Phong更消耗性能一点
b.效果上:差不多,在逆光上Phong会更好看。