庄懂的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 写法: 

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
        }
    }
}

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

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"
}

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

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
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Allen7474/article/details/127711069