
菲涅尔现象:
Fresnel(菲涅尔) 用到的两个向量 NdirWS(世界空间 法线向量) VdirWS(世界空间 视角向量)
注意:VdirWS: 的默认为视角的反方向。如需取视角正方向,需 1 - ldotv。兰伯特点积视方向-1.

菲涅尔: 算法公式 :
1-(N dot V)= Fresnel
Fresnel = Pow(1-ndotv , powVal);
ldotv : 从眼睛发出的Lambert,中间亮,边缘暗 。
1- ldotv : 黑白相反,中间暗,边缘亮 。
powVal : 控制反射 高光次幂。
菲涅尔:反射中间弱,外部反射强。(以圆为例)
金属 与 菲涅尔 相反 :反射中间强,外部反射弱。(以圆为例)


Fresnel = 1- dot (ndir , vdir )
注意:vidr = vdir.xyz - posWS .xyz
菲涅尔 SL 写法:
- Shader "Unlit/Sc09_SL_Fresnel01"
- {
- Properties
- {
- _FresnelInt("菲涅尔强度",Range(0.1,5))=1
- }
- SubShader
- {
- Tags { "RenderType"="Opaque" }
- LOD 100
- Pass {
- Name "FORWARD"
- Tags {
- "LightMode"="ForwardBase"
- }
- CGPROGRAM
- #pragma vertex vert
- #pragma fragment frag
- #pragma multi_compile_instancing
-
- #include "UnityCG.cginc"
- #include "AutoLight.cginc"
- #include "Lighting.cginc"
-
- #pragma multi_compile_fwdbase_fullshadows
- #pragma target 3.0
- UNITY_INSTANCING_BUFFER_START( Props )
- // UNITY_DEFINE_INSTANCED_PROP( float4, _Color)
- UNITY_INSTANCING_BUFFER_END( Props )
- uniform float _FresnelInt;
- //输入结构
- struct VertexInput
- {
- float4 vertex : POSITION;
- float4 normal : NORMAL;
- };
- //顶点输出结构
- struct VertexOutput
- {
- float4 posCS : SV_POSITION;
- float3 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;
- }
- //色彩输出结构
- float4 frag(VertexOutput i) : COLOR
- {
- //准备向量
- float3 ndir = i.nDirWS;
- float3 vdir = normalize(_WorldSpaceCameraPos.xyz - i.posWS);
- float3 ldir = _WorldSpaceLightPos0.xyz;
- //点积结果
- float ndotl = dot(ndir,ldir);
- float ndotv = 1-dot(ndir,vdir); //菲涅尔 1 - n dot v
- //光照模型公式
- float Lambert = max(0,ndotl *0.5+0.5);
- float3 fresnel = pow(ndotv,_FresnelInt);
- //返回结果
- //return float4(Lambert,Lambert,Lambert,1.0f);//输出最终颜色
- return float4 (fresnel,1.0f);
- }
- ENDCG
- }
- }
- }

PS:1、无视BRDF(双向反射分布函数) ,直接 取 参考 原型的图的 XY的-1到1 的 光照信息。
用View空间法线朝向,直接映射模型表面的流氓算法。
2、常用模拟环境反射。
PS:知识点:
1、未解码下 法线 的 状态: == Tangent 切线空间法线 的状态。>> nDirTS

2、 世界空间下法线 的 状态 : >> nDirWS
3、 本地空间下法线 的 状态: >> nDirTS or >> nDirLS

4、视 空间下 法线 的状态: >> nDirVS

Remap(0 -1)后,可看到,熟悉的,常用的那种法线色彩效果。

PS弹幕知识:顶点变化过程:模型空间=》世界空间=》观察空间=》裁剪空间=》屏幕空间
公式:
1、nDirWS 变换到(transforem) = nDirVS(观察空间法线Vive space)
2、取 nDirVS(观察空间法线) 的R,G通道,Remap到(0-1),作为uv对MatCap图采样。
3、叠加菲涅尔,(通过滑条)以模拟金属和非金属不同质感。
MatCap图的状态如此,仅仅是一个预览。 关键词搜索:MatCap texture




重点:
nDirVS = mul(UNITY_MATRIX_V,float4(nDirWS,0.0)); (矩阵:从WS世界空间,转到VS视空间)
matCapUV = nDirVS.rg * 0.5 +0.5;
(这里的 *0.5 +0.5 属于 remap 从-1 到 1 ,截断为 0 到 1)。
单纯的MatCap代码段示例:
- Shader "Unlit/Sc09_MatCap02"
- {
- Properties
- {
- _MatCapMap("MacCapMap",2D) = "gray"{}
- }
- SubShader
- {
- Tags { "RenderType"="Opaque" }
- LOD 100
- Pass {
- Name "FORWARD"
- Tags {
- "LightMode"="ForwardBase"
- }
- CGPROGRAM
- #pragma vertex vert
- #pragma fragment frag
- #pragma multi_compile_instancing
-
- #include "UnityCG.cginc"
- #include "AutoLight.cginc"
- #include "Lighting.cginc"
-
- #pragma multi_compile_fwdbase_fullshadows
- #pragma target 3.0
- UNITY_INSTANCING_BUFFER_START( Props )
- // UNITY_DEFINE_INSTANCED_PROP( float4, _Color)
- UNITY_INSTANCING_BUFFER_END( Props )
-
- uniform sampler2D _MatCapMap;
-
- //输入结构
- struct VertexInput
- {
- float4 vertex : POSITION;
- float4 normal : NORMAL;
- float2 uv0 : TEXCOORD0;
- };
- //顶点输出结构
- struct VertexOutput
- {
- float4 pos : SV_POSITION;
- float2 uv :TEXCOORD0;
- float3 nDirWS : TEXCOORD1;
-
- };
- //输出结构>>>顶点shader>>>输出结构
- VertexOutput vert (VertexInput v)
- {
- VertexOutput o = (VertexOutput)0;
- o.pos = UnityObjectToClipPos(v.vertex);
- o.nDirWS = UnityObjectToWorldNormal(v.normal);
- o.uv = v.uv0;
- return o;
- }
- //色彩输出结构
- float4 frag(VertexOutput i) : COLOR
- {
- //准备向量
- float3 ndirWS = i.nDirWS;
- float3 ldir = _WorldSpaceLightPos0.xyz;
- //声明 得到视空间法线
- float3 ndirVS = mul(UNITY_MATRIX_V,ndirWS);
-
- //点积结果 / 中间变量
- //声明 matCap的UV ,并 赋值截断.
- float2 matCapUV = ndirVS.rg * 0.5 + 0.5;
-
- float ndotl = dot(ndirWS,ldir);
- //光照模型公式
- float Lambert = max(0,ndotl *0.5+0.5);
-
- //最终光照模型 图片类型 输出
- float3 matCap = tex2D(_MatCapMap,matCapUV);
-
- float3 finalRGB = Lambert * matCap;
- //返回结果
- return float4(finalRGB,1.0f);//输出最终颜色
- }
- ENDCG
- }
- }
- }
复合的MatCap代码段示例:MatCap + NormalMap
- Shader "Unlit/Sc09_MatCap01"
- {
- Properties
- {
- _MainCol("MainCol",Color)=(1,1,1,1)
- _NormalMap("NormalMap",2D)="bump"{}
- _MatCap("MatCapMap",2D)="gray"{}
- }
- SubShader
- {
- Tags { "RenderType"="Opaque" }
- LOD 100
- Pass {
- Name "FORWARD"
- Tags {
- "LightMode"="ForwardBase"
- }
- CGPROGRAM
- #pragma vertex vert
- #pragma fragment frag
- #pragma multi_compile_instancing
-
- #include "UnityCG.cginc"
- #include "AutoLight.cginc"
- #include "Lighting.cginc"
-
- #pragma multi_compile_fwdbase_fullshadows
- #pragma target 3.0
- UNITY_INSTANCING_BUFFER_START( Props )
- // UNITY_DEFINE_INSTANCED_PROP( float4, _Color)
- UNITY_INSTANCING_BUFFER_END( Props )
-
- uniform float3 _MainCol;
- uniform sampler2D _NormalMap;
- uniform sampler2D _MatCap;
-
- //输入结构
- struct VertexInput
- {
- float4 vertex : POSITION;
- float4 normal : NORMAL;
- float2 uv0 : TEXCOORD0;
- float4 tangent : TANGENT;
- };
- //顶点输出结构
- struct VertexOutput
- {
- float4 pos : SV_POSITION;
- float2 uv : TEXCOORD0;
- float4 posWS : TEXCOORD1;
- float3 nDirWS : TEXCOORD2;
- float3 tDirWS : TEXCOORD3;
- float3 bDirWS : TEXCOORD4;
- LIGHTING_COORDS(5,6)
- };
- //输出结构>>>顶点shader>>>输出结构
- VertexOutput vert (VertexInput v)
- {
- VertexOutput o = (VertexOutput)0;
- o.uv = v.uv0;
- o.pos = UnityObjectToClipPos(v.vertex);
- o.posWS = mul(unity_ObjectToWorld,v.vertex);
- o.nDirWS = UnityObjectToWorldNormal(v.normal);
- o.tDirWS = normalize(mul(unity_ObjectToWorld,float4(v.tangent.xyz,0.0)).xyz);
- o.bDirWS = normalize(cross(o.nDirWS,o.tDirWS) * v.tangent.w);
- TRANSFER_VERTEX_TO_FRAGMENT(o)
- return o;
- }
- //色彩输出结构
- float4 frag(VertexOutput i) : COLOR
- {
- //准备向量
- float3 var_NormalMap = UnpackNormal(tex2D(_NormalMap,i.uv)).rgb; //法线解码 (法线,uv),取rgb值
- float3x3 TBN = float3x3(i.tDirWS,i.bDirWS,i.nDirWS); //矩阵
- float3 ndirWS = normalize(mul(var_NormalMap,TBN)); //取 世界空间下法线
- float3 ndirVS = mul(UNITY_MATRIX_V,ndirWS); //取 视 空间下法线
-
- float3 ldir = _WorldSpaceLightPos0.xyz; //取 世界空间下灯光位置
-
- float2 MatCapUV = ndirVS.rg * 0.5 + 0.5 ; //取 到 视 空间下法线rg通道,对应xy轴 >> 赋值截断.
- float4 var_MatCap = tex2D(_MatCap,MatCapUV); //声明 赋值,并取到类型为贴图的 matCap 图的变量名。
- //点积结果
- float ndotl = dot(ndirWS,ldir);
- //光照模型公式
- float Lambert = max(0,ndotl *0.5+0.5);
- float attenuation = LIGHT_ATTENUATION(i);
-
- float3 finalRGB = _MainCol * Lambert * var_MatCap * attenuation ;//混入 MatCap图(前提是模型分了xy的UV才能显示)。
- //返回结果
- return float4(finalRGB,1.0f);//输出最终颜色
- }
- ENDCG
- }
- }
- FallBack "Diffuse"
- }


注意: 注意区分,理解,视方向的反方向 和 反射方向 的 不同。
先拿到 观察方向 的反方向 (真正的,从眼睛射出 的 光线),因为,shader中,观察方向vDir的默认方向,是从物体射到 观察(眼睛)方向的。
在用vDir观察方向,打到 对象 上,在从对象 反弹,反射出去。vrDir
顺序为:视方向,射到 对象,对象在反射到 CubeMap环境球 。
所以,需要取到,观察方向的反方向。

环境球贴图的设置:
因为HDRI高动态范围的环境球,在手机端,和多设备中,不支持
所以需要讲高动态范围的环境球贴图,转为 LDRI 低动态范围 环境贴图。
尽管转为LDRI但是还是保留了高动态范围的效果。(原理需要继续深入暂时不讲)

先将贴图 在PS 中,转为 8位 通道:
Mapping : >> Latitude - Longitude Layout (Cylindrical)==经纬度展开
Mipmap(生成8张低级别递减清晰度图LOD)
Convolution Type :>>Specular (Glossy Refiection) (变为金属平滑,否则会有格子像素)
Fixup Edge Seams (修正接缝)


理解公式:
vrDir =(1-vDirWS)* nDirWS. >翻译> 视反射 = (1 - 视角反方向) * 世界空间法线向量.
重要 代码段 实际写法:
vrDir = reflect(-vDirWS , nDirWS);
floa3 cubemap = texCUBElod (_Cubemap,float4(vrDirWS , _CubemapMip ));


1、示例代码段:CubeMap + NormalMap + fresnel
...
2、示例代码拗断: CubeMap
- Shader "Unlit/Sc09_SL_CubeMap01"
- {
- Properties
- {
- _CubeMap("CubeMap",Cube)="Skybox"{}
- _CubeMapMip("CubeMap",Range(0,7))=0
- }
- SubShader
- {
- Tags { "RenderType"="Opaque" }
- LOD 100
- Pass {
- Name "FORWARD"
- Tags {
- "LightMode"="ForwardBase"
- }
- CGPROGRAM
- #pragma vertex vert
- #pragma fragment frag
- #pragma multi_compile_instancing
-
- #include "UnityCG.cginc"
- #include "AutoLight.cginc"
- #include "Lighting.cginc"
-
- #pragma multi_compile_fwdbase_fullshadows
- #pragma target 3.0
- UNITY_INSTANCING_BUFFER_START( Props )
- // UNITY_DEFINE_INSTANCED_PROP( float4, _Color)
- UNITY_INSTANCING_BUFFER_END( Props )
-
- uniform samplerCUBE _CubeMap;
- uniform float _CubeMapMip;
-
- //输入结构
- struct VertexInput
- {
- float4 vertex : POSITION;
- float4 normal : NORMAL;
- float2 uv0 : TEXCOORD0;
- };
- //顶点输出结构
- struct VertexOutput
- {
- float4 pos : SV_POSITION;
- float2 uv : TEXCOORD0;
- float4 posWS : TEXCOORD1;
- float3 nDirWS : TEXCOORD2;
-
- };
- //输出结构>>>顶点shader>>>输出结构
- VertexOutput vert (VertexInput v)
- {
- VertexOutput o = (VertexOutput)0;
- o.uv = v.uv0;
- o.pos = UnityObjectToClipPos(v.vertex);
- o.posWS = mul(unity_ObjectToWorld,v.vertex);
- o.nDirWS = UnityObjectToWorldNormal(v.normal);
- return o;
- }
- //色彩输出结构
- float4 frag(VertexOutput i) : COLOR
- {
- //准备向量
- float3 ldir = _WorldSpaceLightPos0.xyz;
- float3 ndirWS = i.nDirWS;
-
-
- float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS);
- float3 vrDirWS = reflect(-vDirWS,ndirWS); //重点:采样CubeMap
- //点积结果
- float ndotl = dot(ndirWS,ldir);
- //光照模型公式
- float Lambert = max(0,ndotl *0.5+0.5);
- //加载lod Cube类型的图像 并 通过mip控制参数,并取 rgb 变量数值
- float3 var_CubeMap = texCUBElod(_CubeMap,float4(vrDirWS,_CubeMapMip)).rgb;
-
- float3 finalRGB = Lambert * var_CubeMap;
- //返回结果
- return float4(finalRGB,1.0f);//输出最终颜色
- }
- ENDCG
- }
- }
- }