圖形學(xué) 光柵化詳解(Rasterization)

計(jì)算機(jī)的屏幕是二維的平面坐標(biāo),以左上角為原點(diǎn),x軸向右增加,y軸向下增加。

1920×1080屏幕

在3D圖形學(xué)中,物體是3維的,擁有X, Y, Z三個(gè)坐標(biāo),并且擁有R, G, B三種顏色,alpha透明度,U, V貼圖坐標(biāo),N法線(xiàn)。
三維物體在二維屏幕上的顯示,大致分為以下幾步:

  1. 坐標(biāo)變換(transform)
    將場(chǎng)景中的三維坐標(biāo)轉(zhuǎn)換為二維坐標(biāo),這個(gè)請(qǐng)參考我的文章坐標(biāo)系空間變換
  2. 顏色計(jì)算(shade)
    計(jì)算每個(gè)頂點(diǎn)的顏色,通過(guò)UV貼圖的顏色,結(jié)合光照,透明度等,計(jì)算出模型每個(gè)頂點(diǎn)的具體顏色(R, G, B)。這個(gè)在后面也會(huì)講,本期不做介紹。
  3. 光柵化(rasterization)
    假定屏幕分辨率為1920×1080,在二維屏幕渲染(光柵化)時(shí),內(nèi)存中frame buffer只保存著1920×1080個(gè)屏幕點(diǎn)的顏色,然后一個(gè)一個(gè)的畫(huà)到屏幕上。(它的實(shí)現(xiàn)方式是以一個(gè)1920×1080長(zhǎng)的一維數(shù)組儲(chǔ)存每個(gè)頂點(diǎn)的RGB顏色,然后遍歷數(shù)組畫(huà)出來(lái))
    什么X, Y, Z,什么alpha之類(lèi)的frame buffer都沒(méi)有的,在frame buffer里只有3個(gè)值:R, G, B。
    X, Y, Z, alpha等等屬性要在另外的地方存儲(chǔ)。
    光柵化,就是計(jì)算出1920×1080這么長(zhǎng)的RGB數(shù)組中,每一個(gè)RGB的值。

在第二步中,我們計(jì)算出了3D模型每個(gè)頂點(diǎn)的顏色,這個(gè)是基于3維坐標(biāo)的,頂點(diǎn)的三維坐標(biāo)可以是小數(shù)
但在屏幕渲染時(shí),屏幕是只有X,Y二維的,并且其像素點(diǎn)坐標(biāo)都是整數(shù)。1920×1080的屏幕只有1920×1080=2073600個(gè)像素點(diǎn)。所以光柵化的連點(diǎn)描邊是一個(gè)近似過(guò)程。

PR線(xiàn)段的屏幕近似

PS:
目前主流的面片分割是三角形分割,所以大家在3DS MAX或者M(jìn)AYA里看3D模型的網(wǎng)格,基本都是三角形網(wǎng)格,但也有以四邊形為最小分割的算法,這里不涉及,我們認(rèn)為3D模型的面片單元都是三角形。
那么一個(gè)三角形的顏色怎么規(guī)定呢?
(1)三個(gè)頂點(diǎn)顏色取平均值
(2)取某一個(gè)頂點(diǎn)的顏色
(3)三個(gè)頂點(diǎn)顏色的漸變
這三種方法都可以,根據(jù)實(shí)際情況自行斟酌。

光柵化主要有以下幾步:

  1. 讀取模型的頂點(diǎn),3個(gè)3個(gè)的讀,因?yàn)橐?huà)三角形。
  2. 將3個(gè)頂點(diǎn)兩兩連成線(xiàn),形成三角形。
  3. 計(jì)算屏幕像素點(diǎn)在三角形內(nèi)還是三角形外。在三角形內(nèi)部的,就上色(顏色是之前算出來(lái)的),在三角形外部的,就不上色。
    注意:如果一個(gè)三角形擋在另一個(gè)三角形前面,我們應(yīng)該只畫(huà)前面的三角形。所以這里還需要比較一下正準(zhǔn)備上色的這個(gè)像素點(diǎn)是不是已經(jīng)上過(guò)色了。如果這個(gè)像素點(diǎn)已經(jīng)上過(guò)色了,并且它是被Z=1的頂點(diǎn)上的色,而我們正準(zhǔn)備上色的這個(gè)頂點(diǎn)的Z=2(說(shuō)明這個(gè)頂點(diǎn)被擋在了后面),那么這個(gè)頂點(diǎn)就不應(yīng)該上色,因?yàn)樗潜粨踝〉狞c(diǎn)。)
  4. 不斷的循環(huán),直到畫(huà)完3D模型的所有三角形,這樣一個(gè)模型就出來(lái)了!

那么,假設(shè)我們已經(jīng)得到了3個(gè)頂點(diǎn)的坐標(biāo),并且已知這個(gè)三角形是紅色。
v1 (-1.5, 1.5, 1.5)
v2 (1.5, 1.5, 1.5)
v3 (0.2, 0.2, 0.2)
如何判斷屏幕的哪些像素點(diǎn)在該三角形內(nèi)部?
主流的算法有兩種:
1.LEE(Linear Expression Evaluation)
2.Scan Line
本期只講LEE,因?yàn)镾can Line我沒(méi)有親自搞過(guò)。
LEE大致原理如下:

  1. 首先因?yàn)槠聊恢挥卸S,所以判斷點(diǎn)和邊的位置關(guān)系的時(shí)候可以先不管Z,Z只是用來(lái)判斷前后遮擋的。
  2. 按照順時(shí)針(或者逆時(shí)針)的順序,連接v1v2, v2v3, v3v1,這樣就得到了三條邊。
  3. 假定邊的頭是(X+dX, Y+dY),尾是(X, Y)
    計(jì)算這3條邊的方程:E(x,y) = dY(x-X)-dX(y-Y)
    展開(kāi)之后是dY*x + (-dX)*y + (dX*Y-dY*X) = 0
    即Ax + By + C =0
    其中A = dY, B = -dX, C = dX*Y-dY*X
    我們把v1v2, v2v3, v3v1三條邊的A, B, C都求出來(lái),就得到了3條邊的方程E1, E2, E3。
  4. 將屏幕像素點(diǎn)的x,y帶入方程,A1x + B1y + C1 = E1,如果點(diǎn)在邊上,則E1=0,如果點(diǎn)不在邊上,則E1!=0。
  5. 最神奇的地方來(lái)了。
    如果點(diǎn)(x,y)帶入3個(gè)方程的結(jié)果E1, E2, E3同時(shí)大于0或者同時(shí)小于0,即同號(hào),則該點(diǎn)在三角形內(nèi),如果異號(hào),則在三角形外。
  6. 每次獲得3個(gè)點(diǎn)之后,取出其中的min_x, max_x, min_y, max_y構(gòu)成的四邊形,將屏幕像素點(diǎn)(x,y)中,在該范圍內(nèi)的點(diǎn)取出,帶入LEE公式比較結(jié)果。
    如果該點(diǎn)在三角形內(nèi),并且沒(méi)有被遮擋(需要對(duì)Z進(jìn)行判斷),則上色,否則不上色。不斷迭代,直到所有的三角形都被處理完成,3D模型也畫(huà)到了屏幕上。

需要注意的地方:

  1. 如何判斷遮擋,即得到三角形內(nèi)的點(diǎn)的Z值?
    答:我們知道了v1, v2, v3三個(gè)點(diǎn),可以求三角形平面方程,求出之后,只需要將某個(gè)點(diǎn)的(x,y)代入,即可求出z。
    平面方程一般式為:Ax + By + Cz + D = 0
    取E1, E2兩個(gè)邊向量,進(jìn)行叉乘,得到法向量N(A,B,C)
    沒(méi)錯(cuò),你沒(méi)看錯(cuò),N的X, Y, Z即是A, B, C。(數(shù)學(xué)真神奇)
    然后取v1(x, y, z)帶入方程,求出D,平面解析式就得到了。
    然后將想求z的點(diǎn)的x,y帶入,就可以求出z了。

  2. 屏幕的Z軸是朝里的,所以z越大說(shuō)明離我們?cè)竭h(yuǎn),z越小就里我們?cè)浇幍臅?huì)遮擋遠(yuǎn)處的。

  3. LEE的特殊情況
    由于多個(gè)三角形的邊和邊是互相挨著的,所以如果直接按上面的方法畫(huà),會(huì)有很多邊重復(fù)畫(huà)了2遍,為了提高渲染效率,我們需要保證每條邊只畫(huà)一遍
    怎么保證呢?
    答:只畫(huà)三角形的左邊和上邊

如何定義左邊和上邊?
由于重畫(huà)這個(gè)問(wèn)題只出現(xiàn)在邊上,對(duì)于三角形內(nèi)部的像素點(diǎn),都是只畫(huà)一次的,所以不用考慮內(nèi)部點(diǎn),只考慮三條邊上的點(diǎn)。

如圖所示:
1)假定三角形v1v2v3是這樣的,我們當(dāng)前要上色的像素點(diǎn)為P1(紅色),落到了v1v3這條邊上,那么就取不在這條邊上的頂點(diǎn)v2,計(jì)算過(guò)v2的水平線(xiàn)與v1v3的交點(diǎn)R1,如果R1在v2的右側(cè),即R1.x > v2.x,那么說(shuō)明P1是落在了右側(cè)的邊,所以不畫(huà)

2)假定我們當(dāng)前要上色的像素點(diǎn)為P2(綠色),落到了v2v3這條邊上,那么就取不在這條邊上的頂點(diǎn)v1,計(jì)算過(guò)v1的水平線(xiàn)與v2v3的交點(diǎn)R2,如果R2在v1的右側(cè),即R2.x > v1.x,那么說(shuō)明P2是落在了右側(cè)的邊,所以不畫(huà)

3)假定我們當(dāng)前要上色的像素點(diǎn)為P3(藍(lán)色),落到了v1v2這條邊上,那么就取不在這條邊上的頂點(diǎn)v3,計(jì)算過(guò)v3的水平線(xiàn)與v1v2的交點(diǎn)R3,如果R3在v3的右側(cè),即R3.x > v3.x,那么說(shuō)明P3是落在了右側(cè)的邊,但圖中是R3.x < v3.x,所以P3落在了左側(cè)邊,要畫(huà)

4)如果存在垂直邊或者水平邊,怎么判斷左右?
垂直邊和上面是一種情況,不用單獨(dú)拿出來(lái)考慮。
水平邊的畫(huà),只畫(huà)上方,即只畫(huà)左邊和上邊
還是看上圖,假定邊v2v3是水平的,那么我們?nèi)1,發(fā)現(xiàn)v1的y比較小,即v1在v2v3上方,那么邊v2v3就是下邊,所以不畫(huà),反之則畫(huà)。

可以參考的論文

  1. Siggraph 1985 - "Fast Spheres, Shadows, Textures, Transparencies, and Image Enhancements in Pixel-Planes," Henry Fuchs,et. al.

  2. 2000 Sig/Euro Workshop on Graphics Hardware - "Tiled Polygon Traversal Using Half-Plane Edge Functions," Joel McCormack, Robert McNamara

  3. Siggraph 1988 - "A Parallel Algorithm for Polygon Rasterization," Juan Pineda

  4. Siggraph 2005 - “Resolution-Independent Curve Rendering Using Programmable Graphics Hardware,” Charles Loop, Jim Blinn

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容