• 庄懂的TA笔记(九)<菲涅尔 + MatCap + CubeMap>


    庄懂的TA笔记(九)<菲涅尔 + MatCap + CubeMap>

    课程内容:

    1、菲涅尔

    0、效果展示、公式:

    菲涅尔现象:

     Fresnel(菲涅尔) 用到的两个向量  NdirWS(世界空间 法线向量)       VdirWS(世界空间 视角向量)  

     注意:VdirWS: 的默认为视角的反方向。如需取视角正方向,需 1 - ldotv。兰伯特点积视方向-1.

     菲涅尔:                           算法公式 :

                                                                    1-(N  dot   V)= Fresnel 

                                                                  Fresnel = Pow(1-ndotv , powVal);

                                                 ldotv     : 从眼睛发出的Lambert,中间亮,边缘暗 

                                                1- ldotv  : 黑白相反,中间暗,边缘亮  。    

                                                powVal  : 控制反射  高光次幂。

                                                   菲涅尔:反射中间弱,外部反射强。(以圆为例)

    金属    与    菲涅尔     相反                :反射中间强,外部反射弱。(以圆为例)

    1、FresnelSF中的使用:

    2、FresnelSL中的使用:

          Fresnel =  1- dot (ndir , vdir ) 

                                                                                    注意:vidr = vdir.xyz  -  posWS .xyz

     菲涅尔 SL 写法: 

    1. Shader "Unlit/Sc09_SL_Fresnel01"
    2. {
    3. Properties
    4. {
    5. _FresnelInt("菲涅尔强度",Range(0.1,5))=1
    6. }
    7. SubShader
    8. {
    9. Tags { "RenderType"="Opaque" }
    10. LOD 100
    11. Pass {
    12. Name "FORWARD"
    13. Tags {
    14. "LightMode"="ForwardBase"
    15. }
    16. CGPROGRAM
    17. #pragma vertex vert
    18. #pragma fragment frag
    19. #pragma multi_compile_instancing
    20. #include "UnityCG.cginc"
    21. #include "AutoLight.cginc"
    22. #include "Lighting.cginc"
    23. #pragma multi_compile_fwdbase_fullshadows
    24. #pragma target 3.0
    25. UNITY_INSTANCING_BUFFER_START( Props )
    26. // UNITY_DEFINE_INSTANCED_PROP( float4, _Color)
    27. UNITY_INSTANCING_BUFFER_END( Props )
    28. uniform float _FresnelInt;
    29. //输入结构
    30. struct VertexInput
    31. {
    32. float4 vertex : POSITION;
    33. float4 normal : NORMAL;
    34. };
    35. //顶点输出结构
    36. struct VertexOutput
    37. {
    38. float4 posCS : SV_POSITION;
    39. float3 posWS : TEXCOORD0;
    40. float3 nDirWS : TEXCOORD1;
    41. };
    42. //输出结构>>>顶点shader>>>输出结构
    43. VertexOutput vert (VertexInput v)
    44. {
    45. VertexOutput o = (VertexOutput)0;
    46. o.posCS = UnityObjectToClipPos(v.vertex);
    47. o.posWS = mul(unity_ObjectToWorld,v.vertex);
    48. o.nDirWS = UnityObjectToWorldNormal(v.normal);
    49. return o;
    50. }
    51. //色彩输出结构
    52. float4 frag(VertexOutput i) : COLOR
    53. {
    54. //准备向量
    55. float3 ndir = i.nDirWS;
    56. float3 vdir = normalize(_WorldSpaceCameraPos.xyz - i.posWS);
    57. float3 ldir = _WorldSpaceLightPos0.xyz;
    58. //点积结果
    59. float ndotl = dot(ndir,ldir);
    60. float ndotv = 1-dot(ndir,vdir); //菲涅尔 1 - n dot v
    61. //光照模型公式
    62. float Lambert = max(0,ndotl *0.5+0.5);
    63. float3 fresnel = pow(ndotv,_FresnelInt);
    64. //返回结果
    65. //return float4(Lambert,Lambert,Lambert,1.0f);//输出最终颜色
    66. return float4 (fresnel,1.0f);
    67. }
    68. ENDCG
    69. }
    70. }
    71. }

    2、MatCap

    0、效果展示:

            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、叠加菲涅尔,(通过滑条)以模拟金属和非金属不同质感。

    1、MatCapSF中的使用:

            MatCap图的状态如此,仅仅是一个预览。  关键词搜索:MatCap texture

    2、MatCapSL中的使用:

    重点:

    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代码段示例:

    1. Shader "Unlit/Sc09_MatCap02"
    2. {
    3. Properties
    4. {
    5. _MatCapMap("MacCapMap",2D) = "gray"{}
    6. }
    7. SubShader
    8. {
    9. Tags { "RenderType"="Opaque" }
    10. LOD 100
    11. Pass {
    12. Name "FORWARD"
    13. Tags {
    14. "LightMode"="ForwardBase"
    15. }
    16. CGPROGRAM
    17. #pragma vertex vert
    18. #pragma fragment frag
    19. #pragma multi_compile_instancing
    20. #include "UnityCG.cginc"
    21. #include "AutoLight.cginc"
    22. #include "Lighting.cginc"
    23. #pragma multi_compile_fwdbase_fullshadows
    24. #pragma target 3.0
    25. UNITY_INSTANCING_BUFFER_START( Props )
    26. // UNITY_DEFINE_INSTANCED_PROP( float4, _Color)
    27. UNITY_INSTANCING_BUFFER_END( Props )
    28. uniform sampler2D _MatCapMap;
    29. //输入结构
    30. struct VertexInput
    31. {
    32. float4 vertex : POSITION;
    33. float4 normal : NORMAL;
    34. float2 uv0 : TEXCOORD0;
    35. };
    36. //顶点输出结构
    37. struct VertexOutput
    38. {
    39. float4 pos : SV_POSITION;
    40. float2 uv :TEXCOORD0;
    41. float3 nDirWS : TEXCOORD1;
    42. };
    43. //输出结构>>>顶点shader>>>输出结构
    44. VertexOutput vert (VertexInput v)
    45. {
    46. VertexOutput o = (VertexOutput)0;
    47. o.pos = UnityObjectToClipPos(v.vertex);
    48. o.nDirWS = UnityObjectToWorldNormal(v.normal);
    49. o.uv = v.uv0;
    50. return o;
    51. }
    52. //色彩输出结构
    53. float4 frag(VertexOutput i) : COLOR
    54. {
    55. //准备向量
    56. float3 ndirWS = i.nDirWS;
    57. float3 ldir = _WorldSpaceLightPos0.xyz;
    58. //声明 得到视空间法线
    59. float3 ndirVS = mul(UNITY_MATRIX_V,ndirWS);
    60. //点积结果 / 中间变量
    61. //声明 matCap的UV ,并 赋值截断.
    62. float2 matCapUV = ndirVS.rg * 0.5 + 0.5;
    63. float ndotl = dot(ndirWS,ldir);
    64. //光照模型公式
    65. float Lambert = max(0,ndotl *0.5+0.5);
    66. //最终光照模型 图片类型 输出
    67. float3 matCap = tex2D(_MatCapMap,matCapUV);
    68. float3 finalRGB = Lambert * matCap;
    69. //返回结果
    70. return float4(finalRGB,1.0f);//输出最终颜色
    71. }
    72. ENDCG
    73. }
    74. }
    75. }

    复合的MatCap代码段示例:MatCap + NormalMap

    1. Shader "Unlit/Sc09_MatCap01"
    2. {
    3. Properties
    4. {
    5. _MainCol("MainCol",Color)=(1,1,1,1)
    6. _NormalMap("NormalMap",2D)="bump"{}
    7. _MatCap("MatCapMap",2D)="gray"{}
    8. }
    9. SubShader
    10. {
    11. Tags { "RenderType"="Opaque" }
    12. LOD 100
    13. Pass {
    14. Name "FORWARD"
    15. Tags {
    16. "LightMode"="ForwardBase"
    17. }
    18. CGPROGRAM
    19. #pragma vertex vert
    20. #pragma fragment frag
    21. #pragma multi_compile_instancing
    22. #include "UnityCG.cginc"
    23. #include "AutoLight.cginc"
    24. #include "Lighting.cginc"
    25. #pragma multi_compile_fwdbase_fullshadows
    26. #pragma target 3.0
    27. UNITY_INSTANCING_BUFFER_START( Props )
    28. // UNITY_DEFINE_INSTANCED_PROP( float4, _Color)
    29. UNITY_INSTANCING_BUFFER_END( Props )
    30. uniform float3 _MainCol;
    31. uniform sampler2D _NormalMap;
    32. uniform sampler2D _MatCap;
    33. //输入结构
    34. struct VertexInput
    35. {
    36. float4 vertex : POSITION;
    37. float4 normal : NORMAL;
    38. float2 uv0 : TEXCOORD0;
    39. float4 tangent : TANGENT;
    40. };
    41. //顶点输出结构
    42. struct VertexOutput
    43. {
    44. float4 pos : SV_POSITION;
    45. float2 uv : TEXCOORD0;
    46. float4 posWS : TEXCOORD1;
    47. float3 nDirWS : TEXCOORD2;
    48. float3 tDirWS : TEXCOORD3;
    49. float3 bDirWS : TEXCOORD4;
    50. LIGHTING_COORDS(5,6)
    51. };
    52. //输出结构>>>顶点shader>>>输出结构
    53. VertexOutput vert (VertexInput v)
    54. {
    55. VertexOutput o = (VertexOutput)0;
    56. o.uv = v.uv0;
    57. o.pos = UnityObjectToClipPos(v.vertex);
    58. o.posWS = mul(unity_ObjectToWorld,v.vertex);
    59. o.nDirWS = UnityObjectToWorldNormal(v.normal);
    60. o.tDirWS = normalize(mul(unity_ObjectToWorld,float4(v.tangent.xyz,0.0)).xyz);
    61. o.bDirWS = normalize(cross(o.nDirWS,o.tDirWS) * v.tangent.w);
    62. TRANSFER_VERTEX_TO_FRAGMENT(o)
    63. return o;
    64. }
    65. //色彩输出结构
    66. float4 frag(VertexOutput i) : COLOR
    67. {
    68. //准备向量
    69. float3 var_NormalMap = UnpackNormal(tex2D(_NormalMap,i.uv)).rgb; //法线解码 (法线,uv),取rgb值
    70. float3x3 TBN = float3x3(i.tDirWS,i.bDirWS,i.nDirWS); //矩阵
    71. float3 ndirWS = normalize(mul(var_NormalMap,TBN)); //取 世界空间下法线
    72. float3 ndirVS = mul(UNITY_MATRIX_V,ndirWS); //取 视 空间下法线
    73. float3 ldir = _WorldSpaceLightPos0.xyz; //取 世界空间下灯光位置
    74. float2 MatCapUV = ndirVS.rg * 0.5 + 0.5 ; //取 到 视 空间下法线rg通道,对应xy轴 >> 赋值截断.
    75. float4 var_MatCap = tex2D(_MatCap,MatCapUV); //声明 赋值,并取到类型为贴图的 matCap 图的变量名。
    76. //点积结果
    77. float ndotl = dot(ndirWS,ldir);
    78. //光照模型公式
    79. float Lambert = max(0,ndotl *0.5+0.5);
    80. float attenuation = LIGHT_ATTENUATION(i);
    81. float3 finalRGB = _MainCol * Lambert * var_MatCap * attenuation ;//混入 MatCap图(前提是模型分了xy的UV才能显示)。
    82. //返回结果
    83. return float4(finalRGB,1.0f);//输出最终颜色
    84. }
    85. ENDCG
    86. }
    87. }
    88. FallBack "Diffuse"
    89. }

    3、CubeMap

    0、效果展示  / 公式:       

      

    注意:        注意区分,理解,视方向的反方向      和     反射方向   的   不同。

                    先拿到  观察方向 的反方向 (真正的,从眼睛射出 的 光线)因为shader中观察方向vDir的默认方向是从物体射到 观察(眼睛)方向的

                    在用vDir观察方向,打到  对象 上,在从对象  反弹,反射出去。vrDir

                    顺序为:视方向,射到  对象,对象在反射到 CubeMap环境球 。

                    所以,需要取到,观察方向的反方向。

    1、CubeMapSF中的使用:

             环境球贴图的设置:

            因为HDRI高动态范围的环境球,在手机端,和多设备中,不支持

    所以需要讲高动态范围的环境球贴图,转为 LDRI 低动态范围 环境贴图。

            尽管转为LDRI但是还是保留了高动态范围的效果。(原理需要继续深入暂时不讲)

            先将贴图 在PS 中,转为  8位 通道:

       Mapping : >>  Latitude - Longitude  Layout (Cylindrical)==经纬度展开

         Mipmap(生成8张低级别递减清晰度图LOD)

         Convolution Type :>>Specular (Glossy Refiection) (变为金属平滑,否则会有格子像素)

         Fixup Edge Seams (修正接缝)

    2、CubeMapSL中的使用:

            理解公式:

               vrDir =(1-vDirWS)*  nDirWS.  >翻译> 视反射 =  (1 - 视角反方向)  * 世界空间法线向量.

            重要 代码段  实际写法:

            vrDir = reflect(-vDirWS , nDirWS);

            floa3  cubemap = texCUBElod (_Cubemap,float4(vrDirWS , _CubemapMip ));

           

     

    1、示例代码段:CubeMap + NormalMap + fresnel

    ... 

    2、示例代码拗断: CubeMap

    1. Shader "Unlit/Sc09_SL_CubeMap01"
    2. {
    3. Properties
    4. {
    5. _CubeMap("CubeMap",Cube)="Skybox"{}
    6. _CubeMapMip("CubeMap",Range(0,7))=0
    7. }
    8. SubShader
    9. {
    10. Tags { "RenderType"="Opaque" }
    11. LOD 100
    12. Pass {
    13. Name "FORWARD"
    14. Tags {
    15. "LightMode"="ForwardBase"
    16. }
    17. CGPROGRAM
    18. #pragma vertex vert
    19. #pragma fragment frag
    20. #pragma multi_compile_instancing
    21. #include "UnityCG.cginc"
    22. #include "AutoLight.cginc"
    23. #include "Lighting.cginc"
    24. #pragma multi_compile_fwdbase_fullshadows
    25. #pragma target 3.0
    26. UNITY_INSTANCING_BUFFER_START( Props )
    27. // UNITY_DEFINE_INSTANCED_PROP( float4, _Color)
    28. UNITY_INSTANCING_BUFFER_END( Props )
    29. uniform samplerCUBE _CubeMap;
    30. uniform float _CubeMapMip;
    31. //输入结构
    32. struct VertexInput
    33. {
    34. float4 vertex : POSITION;
    35. float4 normal : NORMAL;
    36. float2 uv0 : TEXCOORD0;
    37. };
    38. //顶点输出结构
    39. struct VertexOutput
    40. {
    41. float4 pos : SV_POSITION;
    42. float2 uv : TEXCOORD0;
    43. float4 posWS : TEXCOORD1;
    44. float3 nDirWS : TEXCOORD2;
    45. };
    46. //输出结构>>>顶点shader>>>输出结构
    47. VertexOutput vert (VertexInput v)
    48. {
    49. VertexOutput o = (VertexOutput)0;
    50. o.uv = v.uv0;
    51. o.pos = UnityObjectToClipPos(v.vertex);
    52. o.posWS = mul(unity_ObjectToWorld,v.vertex);
    53. o.nDirWS = UnityObjectToWorldNormal(v.normal);
    54. return o;
    55. }
    56. //色彩输出结构
    57. float4 frag(VertexOutput i) : COLOR
    58. {
    59. //准备向量
    60. float3 ldir = _WorldSpaceLightPos0.xyz;
    61. float3 ndirWS = i.nDirWS;
    62. float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS);
    63. float3 vrDirWS = reflect(-vDirWS,ndirWS); //重点:采样CubeMap
    64. //点积结果
    65. float ndotl = dot(ndirWS,ldir);
    66. //光照模型公式
    67. float Lambert = max(0,ndotl *0.5+0.5);
    68. //加载lod Cube类型的图像 并 通过mip控制参数,并取 rgb 变量数值
    69. float3 var_CubeMap = texCUBElod(_CubeMap,float4(vrDirWS,_CubeMapMip)).rgb;
    70. float3 finalRGB = Lambert * var_CubeMap;
    71. //返回结果
    72. return float4(finalRGB,1.0f);//输出最终颜色
    73. }
    74. ENDCG
    75. }
    76. }
    77. }

  • 相关阅读:
    MySQL基本操作之修改表结构
    【Redis】对象
    LeetCo
    40 个 SpringBoot 常用注解:让生产力爆表!
    如何实现浏览器多标签页tab之间的通信
    【性能测试】Linux下Docker安装与docker-compose管理容器(超细整理)
    弦截法及Python实现
    算法笔记(四)从暴力递归到动态规划
    [MAUI]实现动态拖拽排序网格
    Elasticsearch文档操作
  • 原文地址:https://blog.csdn.net/Allen7474/article/details/127711069