3D開發(fā)理論:光照,著色與材質(zhì)
我保證這是我目前寫過的所有科普教程中最不科普、***層、最不想被讀、最難理解、最晦澀的一篇。
但我也保證這是我目前寫過的所有科普教程中最專業(yè)、最珍貴、最耗時、最盡力,最精益求精的一篇。
以下正文。
做3D開發(fā)(尤其是建模相關(guān))的話,“材質(zhì)”一定是個會經(jīng)常遇到的概念,對于這個總在用的東西,你究竟了解多少呢?——至少我在不久前還是個只用參數(shù)不知原理的人。因此,今日特來與大家分享下我的學(xué)習(xí)心得和研究理解。
厭倦或者害怕晦澀枯燥的圖形學(xué)教科書嗎?不用擔(dān)心,在白藍(lán)紫的文章中不會出現(xiàn)那些過于嚴(yán)謹(jǐn)?shù)睦@口詞語——我只提供科普級別的讀物而已。So,Let's go!
首先,讓我們理清思路,看看這三者間的關(guān)系。
材質(zhì)是反映物體與光線互相作用,最終影響著色的屬性;因此要講什么是材質(zhì),就先要說說在實(shí)時渲染中是如何進(jìn)行著色的;而著色又是根據(jù)光照來計(jì)算的,因此要先梳理下光照。
【光照】
光照就是根據(jù)光學(xué)原理計(jì)算光強(qiáng)變化。
光學(xué)知識在初高中物理課上都講過,什么直線傳播啊,反射折射吸收啊,這些都是排在課本最前面幾章的入門知識,比力學(xué)電學(xué)容易得多,如果你不幸忘記了,可以敲開鄰居的門,請教一下人家孩子——或者問谷歌吧。
對于計(jì)算機(jī)渲染而言,我們有一些額外的說明,比如什么光線都是有顏色的,不考慮不可見光,光源分為點(diǎn)光源,體積光,平行光,聚光燈等等……有興趣的人可以——不用我說了吧?找一本以專業(yè)嚴(yán)謹(jǐn)和枯燥催眠而著稱的清華大學(xué)出版社的圖形學(xué)書籍啃吧!
【著色】
著色就是根據(jù)光線和材質(zhì)確定物體顏色的步驟啦。
首先要說明的一點(diǎn)是,光照模型——也就是模擬光效的計(jì)算方法——有很多種,而我只是針對實(shí)時渲染而言——你不想游戲跟3dsMax的渲染一樣,一幀等一小 時吧?——因此,這里以常用的像素級別的PHONG模型為準(zhǔn)(另一種常用的是頂點(diǎn)級別的GOURAUD模型,這兩種是目前可行而常用的模型,詳見最下面的 鏈接)
材質(zhì)對光線的影響有這些:
1、漫反射
眾所周知,這是由于表面粗糙不平所引起的,它的結(jié)果只與光源位置有關(guān)而與視點(diǎn)位置無關(guān),即:
物體表面相對于光源的角度決定它對來自光源的光的反射。表面越接近垂直于光線,被反射的漫射光線就越多。
根據(jù)lambert余弦定律可以這樣求出結(jié)果:
漫反射強(qiáng)度=材質(zhì)的漫反射系數(shù)×光源強(qiáng)度×(法線方向向量·入射光方向向量)
例如:0.5(反射一半)×1(***,白色)×cos0(入射光垂直于法線,夾角0)=0.5(半減,灰色)
*所有的“強(qiáng)度”“系數(shù)”都是和“顏色”是等價的,因?yàn)閷GB三個分量計(jì)算過后,合并的結(jié)果就是顏色而不再是強(qiáng)度了。即“漫反射顏色=材質(zhì)的漫反射顏色×光源顏色×(法線方向向量·入射光方向向量)”(下同)
*注意,“×”是數(shù)乘,而“·”則是點(diǎn)乘,也就是說***兩向量的點(diǎn)積表示的就是它們夾角的cos值。(下同)
*注意,所有向量都是單位向量,并且入射光向量由反射點(diǎn)指向平面外。(下同)
*圖示,L是入射光,N是發(fā)現(xiàn),R是反射光,eye是視點(diǎn)
2、鏡面反射
理想鏡面是不存在的,對一般的光滑表面而言,反射光會集中在一個范圍內(nèi),它的結(jié)果與視點(diǎn)有關(guān),即:
鏡面反射強(qiáng)度=材質(zhì)鏡面反射系數(shù)×光源強(qiáng)度×(法線方向向量·入射光與視點(diǎn)夾角一半的方向向量)^光澤度
例如:0.5(反射一半)×1(***,白色)×cos0(視點(diǎn)位于反射光方向上,夾角0)^1(加權(quán)1)=0.5(半減,灰色)
*“^光澤度”是“光澤度次方”,光澤度越大,高光的亮斑越小
*標(biāo)準(zhǔn)算法應(yīng)該是指向視點(diǎn)的光線和反射線的單位向量的點(diǎn)乘(即上圖中的α角),但為了節(jié)省計(jì)算,我們按blin模型用此代替。
*那個半向量=視點(diǎn)方向向量+入射光方向向量,如果按下圖的箭頭,那么就是視點(diǎn)方向向量-入射光方向向量
*圖示,H為半向量,它與eye的夾角等于它與L的夾角,這個角只是近似(你可以很容易的發(fā)現(xiàn),其實(shí)它少了一半),但對于實(shí)時渲染而言,這已經(jīng)足夠了。
3、環(huán)境反射
環(huán)境光是一種經(jīng)過多次反射平衡的光,它的強(qiáng)度是均勻的,并且分布是一樣的,即:
環(huán)境光沒有位置或方向上的特征,只有一個顏色亮度值,而且不會衰減,所以在所有方向和所有物體表面上投射的環(huán)境光的數(shù)量是恒定不變的。
因此,在局部光照明模型中(全局光照明包含對象間的作用,需要光線追蹤等算法。為了效率,實(shí)時渲染中可以忽略),我們用一個常量進(jìn)行計(jì)算:
環(huán)境反射強(qiáng)度=材質(zhì)環(huán)境反射系數(shù)×環(huán)境光強(qiáng)度
例如:0.5(反射一半)×1(***,白色)=0.5(半減,灰色)
4、自發(fā)光
自發(fā)光是指對象自己發(fā)出的光,即:
自發(fā)光只增加自身顏色,而不影響場景內(nèi)其他對象,因?yàn)樗皇枪庠?,自發(fā)光不參與光運(yùn)算。
通常來說,我們用一個常量代表自發(fā)光強(qiáng)度,但事實(shí)上為了節(jié)約計(jì)算,我們通常會忽略它,而改用漫反射系數(shù)代替,或者說,將它的結(jié)果融入漫反射系數(shù)中,最終合成我們的老朋友——貼圖。
5、各向異性的反射、菲涅爾效應(yīng)、焦散與色散、下表面散射
略,PHONG模型忽略它們,同時為了實(shí)時渲染效率我也忽略它們。想了解更多,請——這次換寂寞的百度吧。
***,讓我們來說重頭戲——PHONG模型。
PHONG模型就是漫反射、鏡面反射與環(huán)境反射的和,即:
像素顏色=環(huán)境反射色+漫反射色+鏡面反射色
很簡單吧?但也許你會問,既然是和,那么超過上限的怎么辦?最簡單的當(dāng)然是截?cái)嗖灰?,?dāng)作白色處理!但不管怎么說,畢竟是三個顏色相加,超過上限的幾率也太大了,這時候,你就需要分配權(quán)值再累加,比如說:
像素顏色=環(huán)境反射色×0.3+漫反射色×0.4+鏡面反射色×0.3
不過呢,一般來說這個權(quán)值已經(jīng)包含在材質(zhì)的反射系數(shù)里了,或者說,反射系數(shù)其實(shí)就是權(quán)值。
如果你理解了以上內(nèi)容,那么恭喜你,你的光學(xué)物理和向量數(shù)學(xué)過關(guān)了,所以——準(zhǔn)備好把高考不屑一顧的光學(xué)知識上升到一個新的高度,讓我們見識下真正用于程序中的計(jì)算方法吧!
不過在此之前,為了便于理解和自學(xué),還是讓我們先來了解一下這些之前被我隱藏掉的英文吧:
light=光
ambient=環(huán)境反射(光/色/強(qiáng)度/系數(shù))=陰影色
diffuse=漫反射(光/色/強(qiáng)度/系數(shù))=固有色
specular=鏡面反射(光/色/強(qiáng)度/系數(shù))=高光色
emissive=自發(fā)光(光/色/強(qiáng)度/系數(shù))=輻射色
shininess=rough=光澤度=鏡面反射加權(quán)系數(shù)n
ka=環(huán)境反射系數(shù)
kd=漫反射系數(shù)
ks=鏡面反射系數(shù)
N=法線方向單位向量
L=入射光方向單位向量
R=反射光方向單位向量
V=視點(diǎn)方向單位向量
H=半方向單位向量
通常而言,漫反射系數(shù)加上鏡面反射系數(shù)等于1,因?yàn)椴馁|(zhì)通常除了漫反射就是鏡面反射。另外,環(huán)境反射和漫反射的默認(rèn)值常為:
ambient=0x333333(顏色)=0.2(系數(shù))
diffuse=0xCCCCCC(顏色)=0.8(系數(shù))
如果你已經(jīng)暈了,那么請從頭對照著圖示和范例再看一遍,如果還沒有暈,那么做好暈的準(zhǔn)備——來迎接挑戰(zhàn)吧!
這就是經(jīng)典的openGL光照模型,很嚇人么?
——不?那你一定學(xué)過計(jì)算機(jī)圖形學(xué),或者是3D編程老鳥,或者是看了之前的內(nèi)容256遍,再或者是在滿嘴跑火車。
——是?那你需要的是學(xué)好英語,或者對應(yīng)之前講的理解,或者開始像德國boy那樣狂氣地毀鍵盤,再或者是……聽我講解?那么好吧,讓我們對照著這個嚇人的上古魔咒一句一句地翻譯,以找出破解2012末日詛咒的法術(shù)。
首先要補(bǔ)充一個概念,如你所見,這里計(jì)算的是頂點(diǎn)顏色(vertexcolor),原因是……嗯,這個一兩句話不好說明,但你應(yīng)該知道,像素的顏色是通過 插值得到的,因此我們需要先計(jì)算出頂點(diǎn)的顏色。同時,為了光滑著色(避免一塊一塊邊界分明)又不失效率,我們可以使用GOURAUD明暗處理,即雙線性光 強(qiáng)插值算法。具體算法大家可以自己谷歌——但我覺得,Stage3D已經(jīng)為我們選好了插值的方法,所以我們需要的只是計(jì)算出每個頂點(diǎn)的法線——注意,是頂 點(diǎn)法線而不是面法線!如果需要人工計(jì)算的話,頂點(diǎn)法向量可以用與其相鄰的所有多邊形法向量相加得出的均值來近似表示。
好了,讓我們開始翻譯這鬼畫符。
emission(material)指的是材質(zhì)的自發(fā)光顏色,如你所見,這個值是作為常量直接被加的——但為了速度省略它更好。
ambient(lightmodel)指的是全局環(huán)境光顏色,而ambient(material)則是材質(zhì)的環(huán)境反射系數(shù),與上面講的一樣,它們相乘 得出環(huán)境色的最終值。但請注意倒數(shù)第三行,這里也有個ambient(light)和ambient(material),這一對兒表示的是針對各個光源 的環(huán)境色,主要用于計(jì)算物體間的影響(比如說,把手靠近國旗就會被它染紅),但通常為了速度也會省略(畢竟很玄的效果與很炫的幀頻相比,還是后者更有吸引 力)。因此,我們只計(jì)算***行的全局環(huán)境光就好了——當(dāng)然你也可以省略計(jì)算,直接用一個常量代替它,視覺上并不會相差多少,但效率上卻會有所體現(xiàn)。
之后這個肥大的漢堡包就是各個光源的結(jié)果總和。如你所見,左邊的西格瑪(∑)代表求和,這相當(dāng)于是一個循環(huán)(for i=0;i<n-1;i++),按照右邊的公式計(jì)算出各個光源的結(jié)果,并將其累加——毫無疑問,只有一個光源是最快的,這就是當(dāng)年pv3d為什么只 能為一個對象賦予一個光源的原因!而事實(shí)也表明,我們通常不會需要那么多的動態(tài)光源——比起耗時的計(jì)算,我們更愿意將結(jié)果烘焙進(jìn)模型的頂點(diǎn)顏色中!
來看這個漢堡的***層:一個分式乘以點(diǎn)光源效果(spotlight_effect),再將其結(jié)果乘到后面的三層——PHONG模型——上面。這是做什么用的呢?是光線衰減。
顯而易見,對同一個光源而言,離得越近的物體越亮。這個點(diǎn)光源效果就是點(diǎn)光源強(qiáng)度的加強(qiáng)系數(shù)——忽略(視為1)也未嘗不可——而前面的分式則是距離比率。
這個分?jǐn)?shù)表示的是“光的衰減比例為傳播距離平方的倒數(shù)”這一光學(xué)定律,即1/(d^2)。但如你所見,這里的分母卻分明是(d+k)^2的展開式,為什么 除了距離d還多了一個系數(shù)k呢?很簡單,因?yàn)槟悴粫M鹍<1(特別是無限趨近于0)時,點(diǎn)光源的亮度變成無限大。因此,我們補(bǔ)上一個系數(shù)來確保分 式的結(jié)果不會大于1——也就是光源原本的亮度。
需要注意的是,這個衰減僅對點(diǎn)光源有效,因?yàn)槠叫泄馐菬o視距離的,它的分式永遠(yuǎn)是1,即不衰減,而環(huán)境光在***行就算過了,至于其它種類的光(比如聚光燈),在實(shí)時渲染中則很少見(速度***,影響速度的統(tǒng)統(tǒng)忽略?。?/p>
***,讓我們來看PHONG模型。
左邊的那個中括號“[”表示后面這三行的和,也就是三行累加的結(jié)果。
***行之前說過了,究竟是去是留請根據(jù)需求自便,略過不再提。
第二行是漫反射色,第三行則是鏡面反射色,與之前的公式完全一致,也不必多說,不過:
1、其中diffuse(light)漫反射光和specular(light)鏡面反射光可以用一個光源顏色表示以節(jié)約內(nèi)存——也更合理。
2、diffuse(material)材質(zhì)漫反射系數(shù)和specular(material)材質(zhì)鏡漫反射系數(shù)通常相加得1(0xFFFFFF),因此 你可以只記錄一個參數(shù),或者直接用通用的0.8(0xCCCCCC)與0.2(0x333333)常量來代替以加速計(jì)算。
3、向量乘法與之前所說的一樣,其中n是法向量,L是光線入射向量,s是半向量,shinine是光澤度。需要注意的是,這里對其結(jié)果做了一個與0取較大值的計(jì)算,這是為了避免處于背面還被光線照亮(即便顏色是負(fù)的)的緣故。
【材質(zhì)】
***,來看材質(zhì)。
材質(zhì)是記錄物體表面對光線影響的參數(shù)集合,如果你已經(jīng)理解了上面的一堆公式,那么,材質(zhì)所包含的參數(shù)也就顯而易見了。
雖然由于渲染引擎的不同(實(shí)時與非實(shí)時)和光照模型的不同(非實(shí)時光照模型會更細(xì)膩——也更耗時),材質(zhì)的參數(shù)會有多有少——這一點(diǎn)打開3dsMax的材質(zhì)編輯器就可以發(fā)現(xiàn)——但對于實(shí)時渲染而言,總有那么幾個參數(shù)是常見的,那就是:
ambientColor——環(huán)境色,材質(zhì)對環(huán)境光顏色RGB各分量的反射系數(shù)
diffuseColor——漫反射色,材質(zhì)對光源顏色RGB各分量的漫反射系數(shù)
specularColor——鏡面反射色,材質(zhì)對光源顏色RGB各分量的鏡面反射系數(shù)
emissiveColor——自發(fā)光色,材質(zhì)自身的顏色
shininess——光澤度,高光光斑的大小范圍
transparency——透明度,材質(zhì)的透明狀態(tài),與真透明不同,這里的透明與厚度沒有關(guān)系
*對于其他叫法,請參考之前的中英文對照表
That's all for today~
希望對大家(特別是渴望寫shader或引擎的人)有所幫助。
***,附贈另一種著色貼圖的公式:
最終顏色=漫反射貼圖(正常紋理)×光線貼圖×混合因子+反射貼圖×(1-混合因子)