一.標(biāo)準(zhǔn)光照模型
OpenGL與Direct3D提供了幾乎相同的固定功能光照模型楣嘁。什么是固定功能光照模型?在過去只有固定繪制流水線的時候翎冲,該流水線被限制只能使用一個光照模型,也即是固定功能光照模型。該模型基于phong光照模型襟雷。在下面的這個例子里,我們使用一個“基本”模型對固定功能光照模型提供了簡化版本蛹找。這個基本模型的數(shù)學(xué)描述為高級公式為:
surfaceColor = emissive + ambient + diffuse + specular
從式子可以看出:物體表面的顏色是自發(fā)光(放射 emissive)肚豺、環(huán)境反射(ambient)、漫反射(diffuse)和鏡面反射(specular)等光照作用的總和谷异。每種光照作用取決于表面材質(zhì)性質(zhì)(例如亮度和材質(zhì)顏色)和光源的性質(zhì)(例如光的位置和顏色)分尸。
下面對這個基本模型的各個部分進(jìn)行講解,最后我們使用CG語言寫出該基本模型歹嘹。
1.)自發(fā)光(emissive)
自發(fā)光光照作用獨(dú)立于所有的光源箩绍。物體的自發(fā)光并不能照亮場景中的其他物體。換句話說尺上,物體自發(fā)光不能照亮其他物體或者投下陰影材蛛。因此圆到,一個放射性物體本身并不是一個光源。
另一個解釋放射項(xiàng)的方法:它是一種在計(jì)算完其他所有光照項(xiàng)后添加的顏色卑吭。
自發(fā)光的數(shù)學(xué)公式:emissive = Ke
其中Ke代表材質(zhì)的放射光顏色
2.)環(huán)境光(ambient)
環(huán)境光來自于四面八方芽淡,故環(huán)境放射光照項(xiàng)并不依賴于光源的位置。
1.環(huán)境放射項(xiàng)依賴:1.材質(zhì)的反射能力 2.照射到材質(zhì)上的環(huán)境光的顏色豆赏。
2.用于環(huán)境放射項(xiàng)的數(shù)學(xué)公式:
ambient = Ka * globalAmbient
其中ka是材質(zhì)的環(huán)境反射系數(shù)挣菲,globalAmbient是入射環(huán)境光的顏色。
ka= tex2D(_MainTex, i.uv.xy).rgb
globalAmbient=UNITY_LIGHTMODEL_AMBIENT.xyz
3.)漫反射項(xiàng)(diffuse)
蘭伯特(Lambert )光照模型是目前最簡單通用的模擬漫反射的光照模型掷邦,定義如下:模型表面的明亮度直接取決于光線向量(light vector)和表面法線(normal)兩個向量夾角的余弦值白胀。光線向量是指這個點(diǎn)到光從哪個方向射入,表面法線則定義了這個表面的朝向抚岗。
diffuse = kd * lightColor * max ( NL(點(diǎn)積) , 0 )
max ( NL(點(diǎn)積) , 0 )
規(guī)范化的向量N和L的點(diǎn)積是兩個向量之間夾角的一個度量或杠,夾角越小,P點(diǎn)受到更多的入射光照苟跪。而背向光源的表面將產(chǎn)生負(fù)數(shù)點(diǎn)積值廷痘,因此,公式*max ( NL(點(diǎn)積) , 0 )使得背向光源的表面的漫反射光為0件已,確保這些表面不會顯示漫反射光照笋额。
_WorldSpaceLightPos0這是一個表示世界做表中的光源的位置矢量或者方向矢量;
如果_WorldSpaceLightPos0.w為0篷扩,則表示該光源為平行光兄猩,_WorldSpaceLightPos0.xyz為此平行光的方向向量;
反之_WorldSpaceLightPos0.w不為0,則表示光源為點(diǎn)光源鉴未,_WorldSpaceLightPos0.xyz為此點(diǎn)光源.
半蘭伯特光照模型
半蘭伯特光照模型枢冤,解了決光照無法到達(dá)的區(qū)域, 背光面更亮一些
diffuse = kd * lightColor * (N * L *0.5 +0.5)
cos的值是-1到1之間,乘上0.5再加0.5后,值域是(0,1)
4.)鏡面反射項(xiàng)(specular)
Phong光照模型:
Ks:材質(zhì)的鏡面反射顏色
facing的取值為0或1:當(dāng)N* L大于0時為1铜秆,當(dāng)N *L小于0時為0
R = reflect(-worldLightDir, worldNormal) ;
BlinnPhong光照模型
BlinnPhong光照模型混合和了Lambert的漫反射和標(biāo)準(zhǔn)的高光淹真,渲染有時比Phong高光更柔和、更平滑连茧,此外它的處理速度相當(dāng)快核蘸,因此成為許多CG軟件中默認(rèn)的光照渲染方法。
specular = KslightColor pow(( dot(N,H), shininess )
其中H = (L + V) / | L+V |啸驯,實(shí)際就是normalize(L + V) , 計(jì)算H比計(jì)算反射向量R更快速客扎。
4.)UnityCG.cginc常用內(nèi)置函數(shù)
float3 WorldSpaceViewDir(float4 v) 輸入一個模型空間中的頂點(diǎn)位置,返回世界空間中從該點(diǎn)到攝像機(jī)的觀察方向罚斗。
float3 UnityWorldSpaceViewDir(float4 v) 輸入一個世界空間中的頂點(diǎn)位置徙鱼,返回世界空間中從該點(diǎn)到攝像機(jī)的觀察方向。
float3 ObjSpaceViewDir(float4 v) 輸入一個模型空間中的頂點(diǎn)位置针姿,返回模型空間中從該點(diǎn)到攝像機(jī)的觀察方向袱吆。
float3 WorldSpaceLightDir(float4 v) 僅可用于前向渲染中厌衙。輸入一個模型空間中的頂點(diǎn)位置,返回世界空間中從該點(diǎn)到光源的光照方向杆故。
float3 UnityWorldSpaceLightDir(float4 v) 僅可用于前向渲染中迅箩。輸入一個世界空間中的頂點(diǎn)位置溉愁,返回世界空間中從該點(diǎn)到光源的光照方向处铛。
float3 ObjSpaceLightDir(float4 v) 僅可用于前向渲染中。輸入一個模型空間中的頂點(diǎn)位置拐揭,返回模型空間中從該點(diǎn)到光源的光照方向撤蟆。沒有被歸一化。
float3 UnityObjectToWorldNormal(float3 norm) 把法線方向從模型空間轉(zhuǎn)換到世界空間中堂污。
float3 UnityObjectToWorldDir(flaot3 dir) 把方向矢量從模型空間變換到世界空間中家肯。
float3 UnityWorldToObjectDir(float dir) 把方向矢量從世界空間變換到模型空間中。
二.法線貼圖
逐像素計(jì)算光照時盟猖,我們每一個像素都會根據(jù)該點(diǎn)的法向量來計(jì)算最終該點(diǎn)的光照結(jié)果讨衣,那么,我們?nèi)绻軌蚋淖冞@個法線的方向式镐,不是就可以改變這個點(diǎn)的光照結(jié)果了呢反镇!那么,把紋理采樣的思想用在這里娘汞,我們直接用一張圖來存儲法線(或者法線偏移值歹茶,見下文),逐像素計(jì)算時你弦,在采樣diffuse貼圖的時候惊豺,再采樣一張法線的貼圖,就可以修改法線了禽作,進(jìn)而修改最終的效果尸昧。
什么是切線空間?
切線空間就是旷偿,基于模型上的一個頂點(diǎn)建立的坐標(biāo)空間烹俗,它的X軸是這個頂點(diǎn)在模型中的切線分量,Z軸是改點(diǎn)在模型上的法線狸捅,Y軸就是這個頂點(diǎn)的副切線衷蜓,因?yàn)樽鴺?biāo)空間XYZ三個面都是互相垂直的嘛,所以這個副切線我們是可以求出來的(以為同樣是與一個平面垂直的單位向量是有兩方向的尘喝,在Unity中模型會提供一個副切線的方向的數(shù)據(jù))磁浇。
來上一個圖,讓我們更好的理解這個所謂的切線空間朽褪。
我們的表面法線是單位向量, 位于范圍 -1.0 到 1.0 之間. 而RGB的值域是(0,1) , 我們可以通過把法線范圍轉(zhuǎn)換為 0.0 到 1.0之間來把法線向量(x, y, z)存儲到一個 RGB 紋理貼圖中.
Color.rgb = Normal.xyz / 2.0 + 0.5;
現(xiàn)在我們可以分析為什么tangent space法線貼圖是偏藍(lán)色了.因?yàn)檫@個面渲染時計(jì)算機(jī)認(rèn)為這個面的"彎曲"程度很小,即面上各個點(diǎn)插值得來的法線相互間偏差很小.基本跟整個面的垂直方向不會差太多.因此在tangent space里,這些法線都跟z軸偏差較小.而z軸是被保存在貼圖里的b字節(jié)處(藍(lán)色通道)里.所以貼圖顯示出來的顏色就偏藍(lán)了.
http://blog.csdn.net/candycat1992/article/details/41605257
三.(渲染路徑)Rendering Paths
1.Deferred Lighting置吓,延遲光照路徑无虚。3者中最高質(zhì)量地還原光照陰影。光照性能只與最終像素?cái)?shù)目有關(guān)衍锚,光源數(shù)量再多都不會影響性能友题。
2.Forward Rendering,前向渲染路徑戴质。能發(fā)揮出Shader全部特性的渲染路徑度宦,當(dāng)然也就支持像素級光照。最常用告匠、功能最自由戈抄,性能與光源數(shù)目*受光照物體數(shù)目有關(guān),具體性能視乎其具體使用到的Shader的復(fù)雜度后专。
3.Vertex Lit划鸽,頂點(diǎn)光照路徑。頂點(diǎn)級光照戚哎。性能最高裸诽、兼容性最強(qiáng)、支持特性最少型凳、品質(zhì)最差丈冬。
1.)前向渲染
根據(jù)影響物體的光源的不同,正向渲染路徑用單個或多個通道來渲染物體啰脚。在正向渲染中殷蛇,光源本身也會根據(jù)他們的設(shè)置和強(qiáng)度受到不同的對待。
在正向渲染中橄浓,影響物體的最亮的幾個光源使用逐像素光照模式粒梦。接下來,最多有4個點(diǎn)光源會以逐頂點(diǎn)渲染的方式被計(jì)算荸实。其他光源將以球面調(diào)和(Spherical Harmonics)的方式進(jìn)行計(jì)算匀们,球面調(diào)和技術(shù)計(jì)算很快但只能得到近似值。根據(jù)以下的規(guī)則判斷一個光源是否為逐像素光源:
?渲染模式被設(shè)置為不重要(Not Important)的光源以逐頂點(diǎn)或球面調(diào)和的方式進(jìn)行計(jì)算
?最亮的方向光源為像素光源
?渲染模式被設(shè)置重要(Important)的光源為像素光源
?如根據(jù)以上規(guī)則得到的像素光源數(shù)量小于質(zhì)量設(shè)置中的像素光源數(shù)量(Pixel Light Count)准给,為了減少亮度泄朴,會有更多的光源以逐像素的方式進(jìn)行渲染
Base Pass 基本通道
Base pass renders object with one per-pixel directional light and all SH/vertex lights. This pass also adds any lightmaps, ambient and emissive lighting from the shader. Directional light rendered in this pass can have Shadows. Note that Lightmapped objects do not get illumination from SH lights.
Note that when “OnlyDirectional” pass flag is used in the shader, then the forward base pass only renders main directional light, ambient/lightprobe and lightmaps (SH and vertex lights are not included into pass data).
需要在設(shè)置Pass的 Tags { "LightMode"="ForwardBase" }
定義宏#pragma multi_compile_fwdbase
Additional Passes附加通道
Additional passes are rendered for each additional per-pixel light that affect this object. Lights in these passes by default do not have shadows (so in result, Forward Rendering supports one directional light with shadows), unless multi_compile_fwdadd_fullshadows variant shortcut is used.
需要在設(shè)置Pass的 Tags { "LightMode"="ForwardAdd" }
定義宏#pragma multi_compile_fwdadd
https://docs.unity3d.com/Manual/RenderTech-ForwardRendering.html
四.投射陰影和接收陰影
1.)投射陰影
需要有平行光,且平行光開啟陰影
物體的renderer組件需要開啟Cast Shadow
物體的shader需要一個tags為”ShadowCaster”的pass來讓物體加入陰影貼圖的渲染內(nèi).可用FallBack "Specular"來讓Unity自動查詢可用的shader,注意透明物體需要特別指定.另外,如果有使用頂點(diǎn)動畫,則需要自己定義可用的shader
2.)接收陰影
Unity中,對于衰減露氮,主要是通過一張光照衰減紋理(_LightTexture0)的采樣得到,其采樣操作主要是在光照空間中進(jìn)行祖灰。對于陰影,一般不會采用實(shí)時陰影的方式(性能耗費(fèi)太高)畔规,但是現(xiàn)在隨著技術(shù)的發(fā)展局扶,越來越多的游戲采用的實(shí)時光照,當(dāng)然這是對整體的光照的優(yōu)化有一個極其高的情況下。一般情況下都是將場景烘培三妈,對模型自身添加相應(yīng)的光照設(shè)置畜埋。
在unity中,主要是通過一個shadowCaster的shader來實(shí)現(xiàn)對陰影的計(jì)算畴蒲,對于物體是否投射陰影可以在其自身的組件上設(shè)置悠鞍。而unity將陰影和衰減的計(jì)算合并在一起,主要通過三個基本的內(nèi)部操作來實(shí)現(xiàn):在a2v的結(jié)構(gòu)體中設(shè)置SHADOW_COORDS(n)模燥,在vert shader中進(jìn)行TRANSFER_SHADOW(o)咖祭,最后在frag shader中進(jìn)行 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos),此時得到的atten就是綜合了衰減和陰影的結(jié)果涧窒,可以用其來作為衰減和陰影的因子與最終的光照顏色相乘心肪。