因爲其餘項目中斷了幾天更新,繼續~~ 這一篇主要是講光照的(包含漫反射和高光以及多光源的處理) 仍是先來看看具體效果(多光源後面單獨展現)
有了基本的光照處理以後愈來愈有立體感了有不有 ╮(╯▽╰)╭
恩~~
此次咱們先來解釋下原理比較好
比較複雜的原理你們就自行百度吧,我這裏來簡單的解釋一下
光照在物體上面,而後將物體表面的顏色一塊兒反射到攝像機中
也就是光-->物體(顏色)-->攝像機
反射出來的亮度則是由物體表面和光線的夾角肯定的(實際上是物體表面的法線和光線的夾角)
好了基本概念就降到這裏,因此咱們須要: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