實(shí)現(xiàn)漫反射光照模型
頂點(diǎn)/片元著色器的基本結(jié)構(gòu)
在著手寫Shader之前,需要對(duì)Unity Shader的基本結(jié)構(gòu)有一個(gè)認(rèn)知,基本上Unity Shader包含了Shader,Properties,SubShader, FallBack等語義塊
Subshader,Subshader可以理解為Shader中的一個(gè)渲染方案,即針對(duì)不同的渲染情況,需要編寫不同的Subshader,在普通情況下,Shader會(huì)從上自下根據(jù)以下優(yōu)先級(jí)選取合適的子著色器,第一個(gè)被選到的SubShader會(huì)用于渲染,其他的被忽略掉。
同樣的Pass也是子著色器中的不同的渲染方案,有所不同的是,所有的Pass會(huì)被依次執(zhí)行,Pass越多,計(jì)算復(fù)雜度越高,性能開銷也更大。
漫反射光照模型
1.逐頂點(diǎn)著色
上一節(jié)中,我們給出了漫反射部分的計(jì)算公式,主要有四個(gè)參數(shù) 入射光線的強(qiáng)度和顏色,材質(zhì)的漫發(fā)射系數(shù),表面發(fā)現(xiàn)n,以及光源方向I. 根據(jù)所得計(jì)算公式,漫反射光照模型代碼如下

這是本書學(xué)習(xí)中,我們寫下的第一個(gè)光照模型shader代碼,更需要對(duì)其逐行解析。
屬性之中的內(nèi)容為漫反射材質(zhì)的顏色,并且將其初始值設(shè)置為白色
UnityObjectToClipPos
頂點(diǎn)著色器最基本的任務(wù)就是把頂點(diǎn)位置從模型空間轉(zhuǎn)換到裁切空間,這里我們用的UnityObjectToCilpPos實(shí)現(xiàn)這個(gè)過程,同時(shí)有必要在這里了解一下shader學(xué)習(xí)中常用幾種空間
1.模型空間:建模的時(shí)候規(guī)定好的一系列坐標(biāo),通常情況寫Shader時(shí)需要獲取模型空間的法線,頂點(diǎn),紋理等等
2.世界空間:略
3.觀察空間:也叫做攝像機(jī)空間,其他的轉(zhuǎn)換情況以后再繼續(xù)了解
4.裁切空間:裁切過程中,位于空間的圖元被保留,位于空間之外的圖元被剔除,裁切的過程遵循正交投影和透視投影矩陣運(yùn)算
5.屏幕空間:將裁切空間坐標(biāo)投影到屏幕空間坐標(biāo),使用齊次除法
將法線從模型空間轉(zhuǎn)換到世界空間
從之前得到的漫反射計(jì)算公式中可知,計(jì)算漫反射時(shí),需要光照方向和法線的點(diǎn)乘,這里的點(diǎn)乘需要光照方向和法線處于同一坐標(biāo)空間的到的結(jié)果才有意義,我們通過_WorldSpaceLightPos0.xyz得到的光照方向位于世界空間,所以需要將發(fā)現(xiàn)從模型空間轉(zhuǎn)換到世界空間。有意思的是,這里用到的矩陣的名字是unity_WorldToObject,恰好相反。
實(shí)際上,將法線轉(zhuǎn)換從模型空間轉(zhuǎn)換到世界空間,需要對(duì)其進(jìn)行逆轉(zhuǎn)置矩陣左乘。這里只解釋為什么頂點(diǎn)可以使用常規(guī)的矩陣轉(zhuǎn)換,而法線不行。這是因?yàn)轫旤c(diǎn)與法線在齊次坐標(biāo)中的表示方法不一樣。頂點(diǎn)是(x, y, z, 1),而法線是(x, y, z, 0),法線的w值是0,表示這個(gè)點(diǎn)的位置無窮遠(yuǎn),因此法線是不具備位置信息的,只有方向信息。不像頂點(diǎn)同時(shí)具備方向和位置信息。
當(dāng)模型進(jìn)行平移、旋轉(zhuǎn)、平移,我們需要對(duì)頂點(diǎn)進(jìn)行矩陣轉(zhuǎn)換,需要用到4X4矩陣,這是因?yàn)?X3矩陣無法表達(dá)平移轉(zhuǎn)換,因此需要4X4矩陣來完成聯(lián)合矩陣操作。但如果對(duì)頂點(diǎn)和法線使用同樣的矩陣方法,會(huì)導(dǎo)致原來垂直于模型表面的法線,變換后不再垂直于表面。所以如果繼續(xù)用對(duì)頂點(diǎn)變化的方式來變換法線是不行的。請(qǐng)看下圖:

左邊是原本的狀態(tài),中間是將應(yīng)用在頂點(diǎn)上的模型變換矩陣應(yīng)用在法線上的結(jié)果,顯然是錯(cuò)的。在對(duì)法線進(jìn)行變換的時(shí)候,使用的是矩陣的逆矩陣的轉(zhuǎn)置矩陣。上文中的_World2Object,就相當(dāng)于一個(gè)逆矩陣,而在調(diào)用mul的時(shí)候把v.normal放在了左側(cè)代表著左乘。
通過以上的步驟,我們實(shí)現(xiàn)了一個(gè)逐頂點(diǎn)的漫反射光照模型,然而對(duì)于細(xì)分度較低的模型,逐頂點(diǎn)光照會(huì)出現(xiàn)一些視覺問題,例如光照交界處有一些鋸齒,為了解決這些問題,我們可以使用逐像素的漫反射光照。
1.逐像素著色/逐片元著色
實(shí)現(xiàn)逐像素的漫反射光照,只需要將漫反射的計(jì)算過程移到片元著色器中,首先需要修改片元著色器的輸入?yún)?shù),將法線的世界空間坐標(biāo)傳入,剩余部分大致不變。代碼如下

符合蘭伯特定律的漫發(fā)射光照模型的問題在于,光照無法照到的區(qū)域,模型的外觀通常為全黑,因?yàn)槲覀兺ㄟ^saturate使法線和光照方向點(diǎn)乘的結(jié)果大于等于0,這會(huì)使模型的背光區(qū)域看起來像一個(gè)平面一樣,失去了模型細(xì)節(jié)表面,為了解決這個(gè)問題,半蘭伯特模型被提了出來。
半蘭伯特模型
法線和光照方向點(diǎn)乘的結(jié)果值域?yàn)閇-1,1], 半蘭伯特模型沒有使用Max操作來防止點(diǎn)乘結(jié)果為負(fù)值,而是將點(diǎn)乘的結(jié)果從[-1,1]映射到[0,1]中,這樣背光面也可以有明暗變化,不同的點(diǎn)積結(jié)果會(huì)映射到不同的值上,需要注意的是半蘭伯特光照模型沒有任何的物理依據(jù),僅僅是一個(gè)視覺加強(qiáng)技術(shù)。
