在光柵化和坐標(biāo)系空間變換里,我講了怎么讓圖形顯示在屏幕上并著色(shade)埃仪,但這個(gè)只是簡(jiǎn)單的純色乙濒,在現(xiàn)在的渲染引擎或游戲引擎里,讓畫(huà)面更加真實(shí)卵蛉,還需要光照和貼圖琉兜。本篇只講光照的實(shí)現(xiàn)。
首先毙玻,在物理學(xué)里我們知道,物體的顏色其實(shí)是它反射的光的顏色廊散。光是白色的桑滩,但它的白色是由許許多多不同顏色不同頻率的光混在一起呈現(xiàn)的,也就是光譜(spectrum)允睹。紅色的物體反射紅光比較多运准,藍(lán)光和綠光則被吸收。白色的衣服反射白光缭受,黑色的衣服吸收白光胁澳,這也是為什么夏天穿白衣服會(huì)稍微稍微涼快一點(diǎn)的原因。
而我們要實(shí)現(xiàn)光照米者,就要去模擬物體的反射光韭畸,讓物體有明暗關(guān)系宇智,有亮面有暗面。物體的反射光可以簡(jiǎn)單分為3種:
1. 漫反射(Diffuse)
當(dāng)光照射到物體上面胰丁,物體會(huì)反射自身的顏色随橘,這是最基本的反射,會(huì)根據(jù)光照方向產(chǎn)生明暗關(guān)系(明暗關(guān)系是有的地方亮有的地方暗锦庸,不是影子机蔗,影子是其他物體投射到你身上,你身上才有暗色的影子甘萧,本文不考慮投射影子萝嘁。因?yàn)橐粋€(gè)物體,比如正方體扬卷,不會(huì)自己讓自己產(chǎn)生影子牙言,只有在它前面放個(gè)球,球的影子才會(huì)映到正方體上)邀泉,反射方向完美情況下是向四面八方嬉挡,這也就是“漫”的由來(lái)。
我們?nèi)为?dú)一個(gè)切面進(jìn)行分析
N是物體的法線(xiàn)汇恤,L是入射光的方向向量庞钢,le是入射光的顏色,則反射光的顏色強(qiáng)度lj滿(mǎn)足:
lj = le Kd cos(θ) 或者 lj = le Kd (L·N)
其中因谎,Kd是物體本身的顏色基括,比如橘子就是橙色。
這個(gè)公式理解起來(lái)就是:你反射的顏色财岔,是你本來(lái)的顏色和照射你的光的顏色的混合风皿。
比如你穿了個(gè)白衣服但紅光照你,那反射的就是偏紅色匠璧。你的顏色和光的顏色的混合比例通過(guò)θ來(lái)確定桐款,當(dāng)θ為0,即光正對(duì)著使勁照你夷恍,那你就是很亮的紅色了魔眨,當(dāng)光正好和你平行擦著你過(guò)去,那你就沒(méi)顏色了酿雪,黑色的遏暴。光對(duì)你越正,你就越亮指黎,否則越暗朋凉。
注意: 本文所有的公式的光照方向向量和法線(xiàn)都必須是標(biāo)準(zhǔn)化了的。顏色向量的RGB范圍都是0~1
2. 高光(Specular)
這個(gè)是可有可無(wú)的醋安。
高光就是指光滑的物體會(huì)有一小部分特別亮的地方杂彭,趨近于鏡面反射墓毒。
上圖的小球,中間那塊圓形白色就是高光盖灸。同一個(gè)小球蚁鳖,左上偏亮右下偏暗,這樣的明暗關(guān)系是漫反射赁炎。
高光顏色強(qiáng)度公式為:
V是視角向量醉箕,因?yàn)楦吖夂鸵暯怯嘘P(guān)系,當(dāng)你繞著一個(gè)光滑球走時(shí)徙垫,你會(huì)發(fā)現(xiàn)它的高光鏡面反射的部位也會(huì)改變讥裤。 Ks就是物體鏡面反射的顏色,一般是白色姻报,當(dāng)然如果很魔幻你想讓物體高光發(fā)藍(lán)色也可以己英。 R是反射光的方向向量,就是L入射光關(guān)于法線(xiàn)N的對(duì)稱(chēng)向量吴旋。spec就是反射強(qiáng)度损肛,看上圖那3個(gè)小球做个。
這個(gè)公式的理解就是:鏡面反射(高光)的顏色是入射光的顏色和鏡面反射光的顏色的疊加粉楚。鏡面反射光的強(qiáng)度取決于視角以及spec爱榔。
當(dāng)V和R平行時(shí)肋联,即反射的光直射你的眼睛,會(huì)亮到爆炸旁瘫。到V和R垂直時(shí)绰咽,光照全都照不進(jìn)你的眼粹污,就沒(méi)有鏡面反射嚷掠,沒(méi)有高光捏检。
3. 環(huán)境光(Ambient Light)
假設(shè)場(chǎng)景里就一個(gè)球和一個(gè)光源,那么按照目前的公式算出來(lái)不皆,有光的地方有顏色贯城,亮。沒(méi)光的地方一片漆黑霹娄。
但有人覺(jué)得一片漆黑不太好能犯,應(yīng)該也能看見(jiàn)點(diǎn)東西,所以就加了一個(gè)環(huán)境光项棠,讓整體再亮一點(diǎn),從而使暗部呈現(xiàn)一些顏色挎峦。
環(huán)境光顏色計(jì)算公式為:
lj = la Ka
la是環(huán)境光的顏色香追,Ka是物體的環(huán)境光系數(shù),一般而言Ka = Kd = 物體本身的顏色坦胶,只有高光的Ks不是物體本身的顏色透典,而是偏白色晴楔。
光照計(jì)算公式
綜上,一個(gè)物體在光照下?lián)碛忻靼店P(guān)系之后的顏色公式如下:
就是所有光源的高光計(jì)算結(jié)果+所有光源的漫反射計(jì)算結(jié)果+環(huán)境光顏色
場(chǎng)景中的環(huán)境光只有一個(gè)峭咒,而發(fā)光光源可能有好幾個(gè)税弃,所以高光和漫反射每個(gè)光源都要算,然后加起來(lái)凑队。
這個(gè)公式的加標(biāo)示版本:
其中则果,E是視角向量,就是V漩氨。
注意:
- 我們算光照的時(shí)候是在相機(jī)坐標(biāo)系空間下計(jì)算的西壮,即image space(不懂空間變換的參考我的坐標(biāo)系空間變換)。所以E(視角向量)永遠(yuǎn)都是(0叫惊,0款青,-1),因?yàn)槲覀兺胺娇淳褪峭鵝=1的地方看霍狰,它的反向量就是 -1抡草。
為什么是相機(jī)空間?
因?yàn)楣庹沼?jì)算涉及方向向量L, E, N, R蔗坯,我們需要在仿射空間(affine space康震,即pre-perspective space, 包括model, world步悠, image 3個(gè)space)進(jìn)行變換签杈,因?yàn)閺膇mage變換到perspective空間會(huì)扭曲圖形損失信息。model, world, image 3個(gè)空間計(jì)算光照都行鼎兽,本文選image答姥。
在image空間下,法線(xiàn)等方向向量都要變換到image space谚咬,但要注意的是鹦付,法線(xiàn)的變換是只有旋轉(zhuǎn),沒(méi)有位移和縮放的T褙浴G贸ぁ!因?yàn)榉ň€(xiàn)如果位移秉继,即在法線(xiàn)向量上加一個(gè)位移向量祈噪,兩個(gè)向量如果不平行,那么和向量的方向會(huì)和原法線(xiàn)不一致尚辑! - 當(dāng)E和L不在一邊的時(shí)候辑鲤,即我們?cè)诳次矬w正面,光從物體背面照過(guò)來(lái)杠茬,我們是什么都看不見(jiàn)的月褥,是黑色弛随,這種情況就不計(jì)算,直接跳過(guò)宁赤。當(dāng)E和L在同一邊舀透,但法線(xiàn)N在另一邊的時(shí)候,算出來(lái)也是負(fù)的决左,不行愕够,所以要把法線(xiàn)取個(gè)反再算《吡總之就是保證最后的顏色RGB在0~1范圍內(nèi)链烈。
我們知道三角形三個(gè)頂點(diǎn)的光照顏色了,但屏幕像素中挚躯,落在三角形內(nèi)部的點(diǎn)的顏色怎么辦强衡?
答:插值。在光柵化里我們計(jì)算過(guò)平面方程用于三角形內(nèi)部點(diǎn)的Z插值码荔。那么其他的插值都可以按這個(gè)方法來(lái)漩勤。
根據(jù)插值方式的不同,shade又分為兩大類(lèi):
1. Gouraud Shading
三角形內(nèi)部點(diǎn)的顏色根據(jù)三個(gè)頂點(diǎn)的顏色插值得來(lái)缩搅,不用管內(nèi)部像素點(diǎn)的法線(xiàn)啊光照啊啥的越败,所以方便運(yùn)算,快硼瓣。但精度差了點(diǎn)究飞。比如光源正好位于三角形的正中央,那么3個(gè)頂點(diǎn)的顏色因?yàn)殡x光源遠(yuǎn)堂鲤,所以會(huì)比較暗亿傅,那么中間點(diǎn)的顏色插值出來(lái)也會(huì)暗。但實(shí)際上中間點(diǎn)離光源近瘟栖,應(yīng)該更亮才對(duì)葵擎!
上圖為顏色插值方法,即構(gòu)造3維平面方程半哟,把Z分別替換為R, G, B構(gòu)造3個(gè)平面酬滤,然后帶入像素點(diǎn)的x,y,求出3個(gè)Z(即R, G, B)寓涨。
2. Phong Shading
為了解決Gouraud的精度問(wèn)題盯串,我們可以在內(nèi)部像素每個(gè)像素點(diǎn)都重新算一遍光照顏色。所以我們需要計(jì)算出內(nèi)部像素點(diǎn)的法線(xiàn)N戒良,通過(guò)插值算体捏。然后帶入上面說(shuō)的光照方程算出該點(diǎn)的顏色。這樣是最準(zhǔn)確的,但是計(jì)算量稍微大一點(diǎn)译打。目前的主流引擎基本都是默認(rèn)的Phong。
法線(xiàn)插值就構(gòu)造3個(gè)平面方程拇颅,把Z分別換成法線(xiàn)N的x, y, z奏司。
帶入像素點(diǎn)的x,y,求出Nx, Ny, Nz樟插,就得到了該點(diǎn)的N韵洋。