UnityShader快速上手指南(四)

簡介

因爲其餘項目中斷了幾天更新,繼續~~
這一篇主要是講光照的(包含漫反射和高光以及多光源的處理)
仍是先來看看具體效果(多光源後面單獨展現)

這裏寫圖片描述

有了基本的光照處理以後愈來愈有立體感了有不有 ╮(╯▽╰)╭

最基本的漫反射

原理

恩~~
此次咱們先來解釋下原理比較好
比較複雜的原理你們就自行百度吧,我這裏來簡單的解釋一下
光照在物體上面,而後將物體表面的顏色一塊兒反射到攝像機中
也就是光-->物體(顏色)-->攝像機
反射出來的亮度則是由物體表面和光線的夾角肯定的(實際上是物體表面的法線和光線的夾角)
好了基本概念就降到這裏,因此咱們須要:html

光(方向和強度),物體的顏色,物體表面的法向量

下面開始看代碼app

代碼

Shader "LT/Lesson4_Lighting"
{
    Properties
    {
         _Color ("Diffuse Color", Color) = (1, 1, 1, 1) 
    }
    SubShader
    {
        Pass {
            Tags { "LightMode" = "ForwardBase" } 
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            uniform float4 _LightColor0; 
            uniform float4 _Color;

            appdata_base vert ( appdata_base input)
            {
                float3 normalDirection = normalize( mul(float4(input.normal, 0.0), _World2Object).xyz );
                float3 lightDirection;
                float attenuation;

                if (0.0 == _WorldSpaceLightPos0.w) {
                    attenuation = 1.0; 
                    lightDirection = normalize(_WorldSpaceLightPos0.xyz); 
                } else {
                    float3 vertexToLightSource = (_WorldSpaceLightPos0 - mul( _Object2World , input.vertex)).xyz; 
                    float distance = length(vertexToLightSource);
                    attenuation = 1.0 / distance; 
                    lightDirection = normalize(vertexToLightSource); 
                }
                
                float3 diffuseReflection = float3(_LightColor0.xyz ) * _Color.xyz * max(0.0, dot(normalDirection, lightDirection)); 

                input.texcoord = float4(diffuseReflection, 1.0);
                input.vertex  = mul(UNITY_MATRIX_MVP, input.vertex );
                return input;
            }

            fixed4 frag (appdata_base input) : COLOR
            {
                return input.texcoord;
            }
            ENDCG
        }
    }
}

代碼一共就50行,並且不少都是熟悉的,好比用appdata_base 中的不用字段來儲存顏色呀,外接漫反射要用的顏色屬性啥的就很少作贅述了
而後這個光照顏色實際上是在lighting.cginc中 ,可是咱們要是用的話,仍是要再次聲明一下,實際上是unity內置的一個外接參數(想一想也知道辣,光照的屬性確定是從unity傳進來的,shader本身確定不知道燈光的信息啊).net

uniform float4 _LightColor0;

直擊核心代碼翻譯

float3 normalDirection = normalize( mul(float4(input.normal, 0.0), _World2Object).xyz );
                // 單位化(有些地方也翻譯成歸一化)物體的法向量

                float3 lightDirection;
                // 光照方向
                float attenuation;
                // 光線衰減量

                if (0.0 == _WorldSpaceLightPos0.w) {
                    // _WorldSpaceLightPos0.w = 0 表示這個光是平行光,
                    // 不是平行光的話這個值爲1,(好比點光源啥的)
                    attenuation = 1; 
                    // 設置衰減爲1(相似於給個默認值)
                    lightDirection = normalize(_WorldSpaceLightPos0.xyz); 
                    // 設置光照方向
                } else {
                    float3 vertexToLightSource = (_WorldSpaceLightPos0 - mul( _Object2World , input.vertex)).xyz; 
                    float distance = length(vertexToLightSource);
                    // 計算光源和頂點之間的距離

                    attenuation = 1.0 / distance; 
                    // 經過距離計算衰減(距離越大,衰減越大)
                    lightDirection = normalize(vertexToLightSource); 
                    // 設置光照方向
                }
 
                float3 diffuseReflection = float3(_LightColor0.xyz ) * _Color.xyz * max(0.0, dot(normalDirection, lightDirection)); 
                // 計算漫反射顏色和亮度(就是前面說的,
                // 用物體的顏色和光的顏色混合做爲漫反射的顏色,
                // 而後法向量和光照的夾角算出光的強度)

恩,而後Pass後面還跟了個Tags { "LightMode" = "ForwardBase" },放到後面一塊兒解釋code

下面來說高光orm

來一點點高光

原理

仍是先來原理,跟前面同樣,漫反射是360無死角的反射,其實無論攝像機在哪(由於漫反射是360度的嘛,無論攝像機在哪都能反射進去),高光呢就能夠理解成針對攝像機的位置,再反射一次光線(增強一次顏色,能夠本身設定,通常來講是白色,RBG各類顏色混在一塊兒就是白色了撒,固然也可使用燈光顏色讓他本身去混合)
以上是爲了圖方便亂吹的啊,具體複雜的原理仍是自行百度去吧
下面開始看代碼htm

代碼

Shader "LT/Lesson4_Lighting"
{
    Properties
    {
         _Color ("Diffuse Color", Color) = (1, 1, 1, 1) 
         _SpecColor ("Specular Color", Color) = (1, 1, 1, 1) 
         _Shininess ("Shininess", Float) = 10 
    }
    SubShader
    {
        Pass {
            Tags { "LightMode" = "ForwardBase" } 
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            uniform float4 _LightColor0; 
            uniform float4 _Color;
            uniform float4 _SpecColor;
            uniform float _Shininess;

            appdata_base vert ( appdata_base input)
            {
                float3 normalDirection = normalize( mul(float4(input.normal, 0.0), _World2Object).xyz );
                float3 viewDirection = normalize( (float4(_WorldSpaceCameraPos, 1.0) - mul( _Object2World, input.vertex)).xyz ); 
                float3 lightDirection = normalize( _WorldSpaceLightPos0.xyz );
                float attenuation;

                if (0.0 == _WorldSpaceLightPos0.w) {
                    attenuation = 1.0; 
                    lightDirection = normalize(_WorldSpaceLightPos0.xyz); 
                } else {
                    float3 vertexToLightSource = (_WorldSpaceLightPos0 - mul( _Object2World , input.vertex)).xyz; 
                    float distance = length(vertexToLightSource);
                    attenuation = 1.0 / distance; 
                    lightDirection = normalize(vertexToLightSource); 
                }
                float3 ambientLighting = UNITY_LIGHTMODEL_AMBIENT.xyz * _Color.xyz;
 
                float3 diffuseReflection = float3(_LightColor0.xyz ) * _Color.xyz * max(0.0, dot(normalDirection, lightDirection)); 

                float3 specularReflection; 
                if (dot(normalDirection, lightDirection) < 0.0) {
                    specularReflection = float3(0.0, 0.0, 0.0); 
                } else {
                    specularReflection = attenuation * _LightColor0.xyz * _SpecColor.xyz * 
                    pow(max(0.0, dot(reflect(-lightDirection, normalDirection),viewDirection)),
                     _Shininess); 
                }

                input.texcoord = float4(ambientLighting  + diffuseReflection + specularReflection, _Color.w);
                input.vertex  = mul(UNITY_MATRIX_MVP, input.vertex );
                return input;
            }

            fixed4 frag (appdata_base input) : COLOR
            {
                return input.texcoord;
            }
            ENDCG
        }
    }
}

此次代碼多了10行左右,大部分代碼前面都講了,咱們來直擊沒講過的核心代碼吧~~blog

float3 normalDirection = normalize( mul(float4(input.normal, 0.0), _World2Object).xyz );
                float3 viewDirection = normalize( (float4(_WorldSpaceCameraPos, 1.0) - mul( _Object2World, input.vertex)).xyz ); 
                // 單位化攝像機的方向
                float3 lightDirection = normalize( _WorldSpaceLightPos0.xyz );
                float attenuation;

                if (0.0 == _WorldSpaceLightPos0.w) {
                    attenuation = 1.0; 
                    lightDirection = normalize(_WorldSpaceLightPos0.xyz); 
                } else {
                    float3 vertexToLightSource = (_WorldSpaceLightPos0 - mul( _Object2World , input.vertex)).xyz; 
                    float distance = length(vertexToLightSource);
                    attenuation = 1.0 / distance; 
                    lightDirection = normalize(vertexToLightSource); 
                }
                float3 ambientLighting = UNITY_LIGHTMODEL_AMBIENT.xyz * _Color.xyz;
                // 計算環境光(其實能夠不要,可是高光都有了,沒環境光太寒蟬了,能夠自行去掉..)
 
                float3 diffuseReflection = float3(_LightColor0.xyz ) * _Color.xyz * max(0.0, dot(normalDirection, lightDirection)); 

                float3 specularReflection; 
                // 定義高光!
                if (dot(normalDirection, lightDirection) < 0.0) {
                    specularReflection = float3(0.0, 0.0, 0.0); 
                    // 若是光源夾角<0了,說明看不高光了,全0
                } else {
                    specularReflection = attenuation * _LightColor0.xyz * _SpecColor.xyz * 
                    pow(max(0.0, dot(reflect(-lightDirection, normalDirection),viewDirection)),
                     _Shininess); 
                    // 根據光線顏色,高光顏色,距離衰減,光照角度,法線方向等信息計算高光區域,
                    // 這些其實都是公式,須要去看看資料吧
                }

                input.texcoord = float4(ambientLighting  + diffuseReflection + specularReflection, _Color.w);
                // 將各類顏色加起來賦值給顏色

恩,沒什麼須要過多解釋的了吧,代碼裏面都註釋了
而後下面進入多光源圖片

多光源的簡單處理

試過上面的代碼的童鞋能夠嘗試下,再在場景中增長一個燈光(若是加的是點光源,注意點光源的參數範圍是否能夠照到物體),而後會發現後面增長的光源沒有任何效果,這是爲神馬捏
這裏就要引入咱們前面跳過的一個概念了文檔

Tags { "LightMode" = "ForwardBase" }

這裏的LightMode是與渲染路徑配合使用的
咱們先來科普下unity支持的各類渲染路徑:
這裏寫圖片描述
看着有四種,其實就三個(好吧,實際上是我只在官方文檔裏面看到三個)
Deferred(延遲渲染,最好的效果),Forward(正向渲染),Vertex(頂點光照,效果最差,默認只有一個光照),還有就是,shader沒有寫專門支持Deferred的就會自動尋找Forward,沒有Forward就尋找Vertex(Vertex是最基本的,若是尚未,就不顯示了,通常是不會發生的,由於你不聲明LightMode模式默認都是支持Vertex的)
因此對應下來有:

Always: Always rendered; no lighting is applied.
ForwardBase: Used in Forward rendering, ambient, main directional light, vertex/SH lights and lightmaps are applied.
ForwardAdd: Used in Forward rendering; additive per-pixel lights are applied, one pass per light.
Deferred: Used in Deferred Shading; renders g-buffer.
ShadowCaster: Renders object depth into the shadowmap or a depth texture.
PrepassBase: Used in legacy Deferred Lighting, renders normals and specular exponent.
PrepassFinal: Used in legacy Deferred Lighting, renders final color by combining textures, lighting and emission.
Vertex: Used in legacy Vertex Lit rendering when object is not lightmapped; all vertex lights are applied.
VertexLMRGBM: Used in legacy Vertex Lit rendering when object is lightmapped; on platforms where lightmap is RGBM encoded (PC & console).
VertexLM: Used in legacy Vertex Lit rendering when object is lightmapped; on platforms where lightmap is double-LDR encoded (mobile platforms).

英文就不翻譯了,還有10分鐘要去吃飯了~~看名字大概就看的出來了
這裏Always(一直渲染),ShadowCaster(產生陰影),ShadowCollector(接受陰影)是獨立於渲染路徑存在的(Unity裏面設置的)
講的有點拼遠了,這裏咱們的ForwardBase只會包含一個光源信息(最重要的的光源),而後在ForwardAdd中再將其餘光源(不那麼重要的光源)渲染出來
因此咱們這裏須要添加一個Pass,像這樣(看後面,多了一個Pass)

Shader "LT/Lesson4_Lighting"
{
    Properties
    {
         _Color ("Diffuse Color", Color) = (1, 1, 1, 1) 
         _SpecColor ("Specular Color", Color) = (1, 1, 1, 1) 
         _Shininess ("Shininess", Float) = 10 
    }
    SubShader
    {
        Pass {
            Tags { "LightMode" = "ForwardBase" } 
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            uniform float4 _LightColor0; 
            uniform float4 _Color;
            uniform float4 _SpecColor;
            uniform float _Shininess;

            appdata_base vert ( appdata_base input)
            {
                float3 normalDirection = normalize( mul(float4(input.normal, 0.0), _World2Object).xyz );
                float3 viewDirection = normalize( (float4(_WorldSpaceCameraPos, 1.0) - mul( _Object2World, input.vertex)).xyz ); 
                // 單位化攝像機的方向
                float3 lightDirection = normalize( _WorldSpaceLightPos0.xyz );
                float attenuation;

                if (0.0 == _WorldSpaceLightPos0.w) {
                    attenuation = 1.0; 
                    lightDirection = normalize(_WorldSpaceLightPos0.xyz); 
                } else {
                    float3 vertexToLightSource = (_WorldSpaceLightPos0 - mul( _Object2World , input.vertex)).xyz; 
                    float distance = length(vertexToLightSource);
                    attenuation = 1.0 / distance; 
                    lightDirection = normalize(vertexToLightSource); 
                }
                float3 ambientLighting = UNITY_LIGHTMODEL_AMBIENT.xyz * _Color.xyz;
                // 計算環境光(其實能夠不要,可是高光都有了,沒環境光太寒蟬了,能夠自行去掉..)
 
                float3 diffuseReflection = float3(_LightColor0.xyz ) * _Color.xyz * max(0.0, dot(normalDirection, lightDirection)); 

                float3 specularReflection; 
                // 定義高光!
                if (dot(normalDirection, lightDirection) < 0.0) {
                    specularReflection = float3(0.0, 0.0, 0.0); 
                    // 若是光源夾角<0了,說明看不高光了,全0
                } else {
                    specularReflection = attenuation * _LightColor0.xyz * _SpecColor.xyz * 
                    pow(max(0.0, dot(reflect(-lightDirection, normalDirection),viewDirection)),
                     _Shininess); 
                    // 根據光線顏色,高光顏色,距離衰減,光照角度,法線方向等信息計算高光區域,
                    // 這些其實都是公式,須要去看看資料吧
                }

                input.texcoord = float4(ambientLighting  + diffuseReflection + specularReflection, _Color.w);
                // 將各類顏色加起來賦值給顏色
                input.vertex  = mul(UNITY_MATRIX_MVP, input.vertex );
                return input;
            }

            fixed4 frag (appdata_base input) : COLOR
            {
                return input.texcoord;
            }
            ENDCG
        }

        Pass {
            Tags { "LightMode" = "ForwardAdd" } 
            Blend One One

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

            uniform float4 _LightColor0; 
            uniform float4 _Color;
            uniform float4 _SpecColor;
            uniform float _Shininess;

            appdata_base vert ( appdata_base input)
            {
                float3 normalDirection = normalize( mul(float4(input.normal, 0.0), _World2Object).xyz );
                float3 viewDirection = normalize( (float4(_WorldSpaceCameraPos, 1.0) - mul( _Object2World, input.vertex)).xyz ); 
                float3 lightDirection = normalize( _WorldSpaceLightPos0.xyz );
                float attenuation;

                if (0.0 == _WorldSpaceLightPos0.w) {
                    attenuation = 1.0; 
                    lightDirection = normalize(_WorldSpaceLightPos0.xyz); 
                } else {
                    float3 vertexToLightSource = (_WorldSpaceLightPos0 - mul( _Object2World , input.vertex)).xyz; 
                    float distance = length(vertexToLightSource);
                    attenuation = 1.0 / distance; 
                    lightDirection = normalize(vertexToLightSource); 
                }
                float3 ambientLighting = UNITY_LIGHTMODEL_AMBIENT.xyz * _Color.xyz;
 
                float3 diffuseReflection = float3(_LightColor0.xyz ) * _Color.xyz * max(0.0, dot(normalDirection, lightDirection)); 

                float3 specularReflection; 
                if (dot(normalDirection, lightDirection) < 0.0) {
                    specularReflection = float3(0.0, 0.0, 0.0); 
                } else {
                    specularReflection = attenuation * _LightColor0.xyz * _SpecColor.xyz * 
                    pow(max(0.0, dot(reflect(-lightDirection, normalDirection),viewDirection)),
                     _Shininess); 
                }

                input.texcoord = float4(ambientLighting  + diffuseReflection + specularReflection, _Color.w);
                input.vertex  = mul(UNITY_MATRIX_MVP, input.vertex );
                return input;
            }

            fixed4 frag (appdata_base input) : COLOR
            {
                return input.texcoord;
            }
            ENDCG
        }
    }
}

這裏咱們還啓用了Blend One One
由於其餘光源反射的顏色須要徹底與原來的光照信息混合,因此用1:1混合
來看看效果:
這裏寫圖片描述
這裏高光的效果很明顯,能夠看到兩個高光點( 視圖中也能夠看到有兩個光源)
而後使用Tags { "LightMode" = "ForwardAdd" }的好處還能夠適應質量調節(好比Android打包的時候選成Vertex,高於Vertex的Pass就不會執行啥的)

總結

還有兩分鐘吃飯
光照啥的代碼其實很簡單,最主要是理清楚順序,好比先渲染啥後渲染啥,也就是Pass的順序,不光是光照,後續不少效果都須要多個Pass進行疊加啥的
不懂得,歡迎聯繫QQ:821580467
吃飯去咯~~~~

轉載請註明出處 http://blog.csdn.net/ghostwolfliu/article/details/51596911
轉載請註明出處 http://www.cnblogs.com/coldcode/p/5564687.html

相關文章
相關標籤/搜索