1. 程式人生 > >Unity Shader 之 基礎光照

Unity Shader 之 基礎光照

物體 lec 計算 我們 nor 技術分享 shade tco coord

攝像機是如何看這個世界的

  遊戲中攝像機所看到的世界與我們現實中所看到的幾乎是一樣的。

  • 首先,光線從光源中發射出來。
  • 然後,光線和場景中的一些物體相交(散射,吸收)。
  • 最後,攝像機吸收了一些光,產生一張圖像。

技術分享圖片

  光線與物體相交的結果有兩個:散射(scattering)和吸收(absorption)

  • 散射:只改變光線的方向,但不改變光線的密度和顏色,有兩種方向:內部與外部,對應折射與反射。
    • 折射(refraction):散射到物體內部,用漫反射(diffuse)模型來計算。
    • 反射(reflection):散射的物體外部,用高光反射(specular)模型來計算。
  • 吸收:只改變光線的密度和顏色,但不改變光線的方向。

  用不同的光照模型來計算兩種不同的散射方向:漫反射模型和高光反射模型。

  • 漫反射:表示有多少光線會被折射、吸收和散射出表面。
  • 高光反射:表示物體表面是如何反射光線的。

標準光照模型

  把進入到攝像機內的光線分為4個部分,每個部分使用一種方法來計算它的貢獻度。

  • 自發光(emissive):當給定一個方向時,一個表面本身會發射多少輻射量。(並不能照亮周圍的物體,只是顯得亮而已)
  • 高光反射(specular):當光線從光源照射到模型表面時,該表面會在完全鏡面反射方向散射多少輻射量。
  • 漫反射(diffuse):當光線從光源照射到模型表面時,該表面會向每個方向散射多少輻射量。
  • 環境光(ambient):描述其他所有的間接光照。

  自發光

  直接采用了該材質的自發光顏色。

  高光反射

  Phong模型公式

    specular = (light · shininess)max(0, v · r)^gloss

    • light:光源顏色
    • shininess:反光度  
    • v:物體到攝像機的方向向量  
    • r:光線的反射方向向量(利用法線方向和光線入射方向可以計算出來,公式為:r = 2(n · l)n - l)  
    • gloss:光澤度(數值越大亮點越小)

  Blinn模型公式

    specular = (light · shininess)max(0, v · h)^gloss

    • light:光源顏色  
    • shininess:反光度    
    • v:物體到攝像機的方向向量    
    • h:對vl取平均後再歸一化,公式:h = v + l / | v + l |
    • gloss:光澤度(數值越大亮點越小)  

  漫反射

  蘭伯特定律  

    diffuse = (light · diffuseColor)max(0, n · l)

    • light:光源顏色    
    • diffuseColor:材質漫反射顏色    
    • n:表面法線方向      
    • l:光源的單位矢量  

代碼示例(環境光+漫反射+高光反射)

Shader "Unity My Shader/Diffuse Light"
{
    Properties
    {
        _Color("Color", Color) = (1,1,1,1)
        _Specular("Specular", Color) = (1,1,1,1)
        _Gloss("Gloss", Range(8.0, 256)) = 20
    }
    SubShader
    {
        Pass
        {
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            fixed4 _Color;
            fixed4 _Specular;
            float _Gloss;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                float3 worldPos : TEXCOORD0;
                float3 worldNormal : TEXCOORD1;
            };
            
            v2f vert (a2v v)
            {
                v2f o;

                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex); // 模型坐標頂點轉換世界坐標頂點
                o.worldNormal = UnityObjectToWorldNormal(v.normal); // 模型坐標法線轉換世界坐標法線

                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed3 worldNormal = normalize(i.worldNormal); // 法線方向
                fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); // 光照方向
                fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); // 視角方向

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; //環境光

                fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0, dot(worldNormal, worldLightDir)); // 漫反射

                fixed3 halfDir = normalize(worldViewDir + worldLightDir); // Blinn模型 計算 h
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldViewDir, halfDir)), _Gloss); // 高光反射

                return fixed4(ambient + diffuse + specular, 1); // 相加後輸出顏色
            }
            ENDCG
        }
    }
}

Unity Shader 之 基礎光照