Fresnel_SF
无黑盒:法线方向点积视角方向,得到一个中间白四周黑的效果,然后再用One Minus节点取反,用Power节点控制菲尼尔的强度
SF简易版连法:一个SIider控制强度,然后一个Fresnel节点。自己连的时候比较推荐使用这个简易连法
MatCap_SF(动起来有点假)
算法:将nDir从切线空间转到观察空间,取RG通道Remap到(0~1),作为uv对Matcap图采样;
叠加菲涅尔效果模拟金属和非金属不同质感
什么是CubeMap
简单理解就是全景图,很早期的CubeMap是存在六张贴图中,HDR图也是CubeMap映射后的结果
CubeMap_SF
实现:①SF中有现成CubeMap节点,实现起来并不复杂;注意两个输入节点
②第一个为vrDir,即观察方向的反射方向;注意vDir同样为观察反向的反方向;做reflect之前要乘-1
③Mip为Cubemap的Mipmap等级
④由于是环境的反射,根据物体的粗糙程度的不同反射程度也不同,所以用一个slide节点来控制强度
Matcap_Code
定义面板参数
Properties
{
_NormalMap ("法线贴图", 2D) = "bump" {}
_Matcap ("Matcap",2D) = "gary"{}
_FresnelPow ("FresnelPow",Range(0,10)) = 1
_EncSpecInt ("EnvSpecInt",Range(0,10)) = 1
}
输入结构,需要拿到顶点信息,法线信息,切线信息,UV信息
struct VertexInput {
float4 vertex : POSITION; //顶点信息
float3 normal : NORMAL; //法线信息
float4 tangent : TANGENT; //切线信息
float2 uv0 : TEXCOORD0; //UV信息
};
输出结构,需要拿到屏幕顶点位置,UV信息,世界空间顶点位置,世界空间法线方向,世界空间切线方向,世界空间副切线方向(后面需要构建TBN矩阵)
struct VertexOutPut{
float4 pos : SV_POSITION; //屏幕顶点位置
float2 uv0 : TEXCOORD0; //uv信息
float4 posWS : TEXCOORD1; //世界空间顶点位置
float3 nDirWS : TEXCOORD2; //世界空间法线方向
float3 tDirWS : TEXCOORD3; //世界空间切线方向
float3 bDirWS : TEXCOORD4; //世界空间负切线方向
};
顶点shader 下面的代码计算了世界空间中的法线、切线、副切线方向
VertexOutPut vert (VertexInput v)
{
VertexOutPut o = (VertexOutPut)0; //新建一个输出结构
o.pos = UnityObjectToClipPos(v.vertex); //屏幕空间下的顶点信息
o.uv0 = v.uv0; //传递UV信息
o.posWS = mul(unity_ObjectToWorld, v.vertex); //顶点位置 os>ws
o.nDirWS = UnityObjectToWorldNormal(v.vertex); //法线方向 os>ws
o.tDirWS = normalize( mul( unity_ObjectToWorld, float4( v.tangent.xyz, 0.0 ) ).xyz ); //切线方向os>ws
o.bDirWS = normalize(cross(o.nDirWS, o.tDirWS) * v.tangent.w); //根据nDir tDir 求bDir
return o; //将输出结构输出
}
像素Shader
//准备向量:采样法线贴图并解码,然后构建TBN矩阵,再把采样的贴图和TBN矩阵相乘并归一化
再计算视空间的法线方向,世界空间中的视方向
//准备中间变量:点乘世界空间中的视角和法线方向,remap matcap的UV
//光照模型:采样matcap那张图,计算菲涅尔,再将matcap的采样结果和菲涅尔以及环境高光强度相乘,并返回这个值
fixed4 frag (VertexOutPut i) : COLOR{
//准备向量
float3 nDirTS = UnpackNormal(tex2D(_NormalMap ,i.uv0)).rgb;//采样法线贴图并解码
float3x3 TBN = float3x3(i.tDirWS , i.nDirWS , i.bDirWS); //构建TNB矩阵
float3 nDirWS = normalize(mul(nDirTS,TBN)); //计算nDirWS 计算菲涅尔
float3 nDirVS = mul(UNITY_MATRIX_V,nDirWS); //计算MatcapUV
float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);//计算菲涅尔
// 准备中间变量
float vDotn = dot(vDirWS ,nDirWS);
float2 matcapUV = nDirVS.rg * 0.5 + 0.5;
// 光照模型
float3 matcap = tex2D(_Matcap , matcapUV);
float fresnel = pow(max(0.00,1.0 - vDotn),_FresnelPow);
float3 envSpecLighting = matcap * fresnel * _EncSpecInt;
return float4 (envSpecLighting,1.0);
}