柵格化

柵格化（英式英語：rasterisation、美式英語：rasterization），又稱光柵化，是將向量圖形格式表示的圖像轉換成點陣圖以用於顯示器或者印表機輸出的過程。

## 綜述

總體上來說，柵格化這個術語可以用於任何將向量圖形轉換成點陣圖的過程。

在通常的應用中，這個術語用來表示在電腦上顯示三維形狀的流行渲染演算法。柵格化目前是生成實時三維電腦圖形最流行的演算法。實時應用需要立即響應使用者輸入，並且通常需要至少每秒 24 幀的速率。

與輻射著色、光線跟蹤等其它渲染技術不同，柵格化的速度非常快，但是由於它不是根據光傳輸的物理規律進行處理的，所以無法正確模擬許多複雜真實光照環境，只能達到足夠欺騙人類眼睛的程度。

## 基本實現方法

最基礎的柵格化演算法將多邊形表示的三維場景渲染到二維表面。多邊形由三角形的集合表示，三角形由三維空間中的三個頂點表示。在最簡單的實現形式中，柵格化工具將頂點數據映射到觀察者顯示器上對應的二維坐標點，然後對變換出的二維三角形進行合適的填充。

### 變換

通常使用矩陣運算進行變換，另外也可以用四元數運算但那不是本文討論的範圍。在三維頂點中添加一個齊次變量成為四維定點然後左乘一個 4 x 4 的變換矩陣，通過這種方法就可以對三維頂點進行變換。主要的變換有平移、縮放、旋轉以及投射。

平移變換是點在三維空間中從一點移動到固定偏移的另外一點的過程，平移可以用下面的矩陣表示：

$$\begin{bmatrix} 1 & 0 & 0 & X \\ 0 & 1 & 0 & Y \\ 0 & 0 & 1 & Z \\ 0 & 0 & 0 & 1 \end{bmatrix}$$

X、Y 與 Z 分別是三維空間中的偏移。

縮放變換通過在頂點位置上乘以一個標量值實現，這樣就將頂點相對於原點的位置進行縮放。縮放變換可以用下面的矩陣表示：

$$\begin{bmatrix} X & 0 & 0 & 0 \\ 0 & Y & 0 & 0 \\ 0 & 0 & Z & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}$$

其中 X、Y 與 Z 是三維坐標中每一維所乘的數值。通過使用不同的 X、Y、Z 值可以實現不對稱縮放。

旋轉變換是繞著一個軸線對每點進行旋轉。

繞 X 軸旋轉：

$$\begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos{\theta} & - \sin{\theta} & 0 \\ 0 & \sin{\theta} & \cos{\theta} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}$$

繞 Y 軸旋轉：

$$\begin{bmatrix} \cos{\theta} & 0 & \sin{\theta} & 0 \\ 0 & 1 & 0 & 0 \\ - \sin{\theta} & 0 & \cos{\theta} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}$$

繞 Z 軸旋轉：

$$\begin{bmatrix} \cos{\theta} & -\sin{\theta} & 0 & 0 \\ \sin{\theta} & \cos{\theta} & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}$$

其中 θ 表示旋轉角度。

邏輯上一系列的平移、縮放、旋轉可以表示絕大多數的變換。通常柵格化系統使用變換棧將輸入頂點的數據流變換到指定位置，變換棧是保存矩陣的標準堆棧，輸入頂點與矩陣棧相乘進行變換。

為了說明如何使用變換棧，我們假設有一個簡單場景中只有一個人的模型。這個人在一個特定位置面向任意一個角度豎直站立，頭轉向另外一個方向。使用一系列的頂點與模型用來表示這個人物。首先，將一個變換矩陣壓到堆棧中將模型移到正確的位置；其次，將縮放矩陣壓到堆棧中將模型縮放到正確的尺寸；然後，表示身體的頂點數據流送到柵格化工具中；由於頭部面向另外一個方向，將旋轉矩陣從堆棧彈出，壓入一個繞 Y 軸旋轉一個不同角度的旋轉矩陣；最後，表示頭部的頂點數據流送到柵格化工具。

在所有點都已經變換到相對於觀察者的合適三維空間位置之後，就需要將它們變換到二維空間了。最簡單的投影方法正投影簡單地從變換的三維頂點中扔掉 Z 分量。正投影的特點是三維空間中的平行線在二維表示中仍然平行。但是，真實世界中的圖像都是透視圖像，離觀察者較遠的點之間的距離看起來要比較近點之間的距離近，這些點都要進行透視投影變換。

從概念上來講就是將透視體轉變成正視體。透視體是平截頭體，即被截去頭部的金字塔體。正視體是一個矩形盒，其中遠近兩個觀察面都與圖像平面平行。

透視投影變換可以用下面的矩陣表示：

$$\begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & (N+F)/N & -F \\ 0 & 0 & 1/N & 0 \end{bmatrix}$$

其中 F 與 N 分別是觀察面的遠近距離。四個結果向量是一個齊次變量不是 1 的向量。對向量進行齊次變換，或者乘以齊次變量的逆，齊次變量變為單位矩陣，這就是最終二維位置的 x 與 y 坐標。

### 裁剪

一旦三角形頂點轉換到正確的二維位置之後，這些位置可能位於觀察窗口之外，也可能位於螢幕之內。裁剪就是對三角形進行處理以適合顯示區域的過程。

最常用的技術是Sutherland-Hodgeman裁剪演算法。在這種方法中，每次測試每個圖像平面的四條邊，對於每個邊測試每個待渲染的點。如果該點位於邊界之外，就剔除該點。對於與圖像平的面邊相交的三角形邊，即邊的一個頂點位於圖像內部一個位於外部，那麼就在交叉點插入一個點並且移除外部的點。

### 掃描變換

傳統的柵格化過程的最後一步就是填充圖像平面中的二維三角形，這個過程就是「掃描變換」。

第一個需要考慮的問題就是是否需要繪製給定的像素。一個需要渲染的像素必須位於三角形內部、必須未被裁掉，並且必須未被其它像素遮擋。有許多演算法可以用於在三角形內進行填充，其中最流行的方法是掃描線演算法。

由於很難確定柵格化引擎是否會從前到後繪製所有像素，因此必須要有一些方法來確保離觀察者較近的像素不會被較遠的像素所覆蓋。最為常用的一種方法是深度緩存，深度緩存是一個與圖像平面對應的保存每個像素深度的二維數組。每個像素進行繪製的時候都要更新深度緩存中的深度值，每個新像素在繪製之前都要檢查深度緩存中的深度值，距離觀察者較近的像素就會繪製，而距離較遠的都被捨棄。

為了確定像素顏色，需要進行紋理或者濃淡效果計算。紋理圖是用於定義三角形顯示外觀的位圖。每個三角形頂點除了位置坐標之外都與紋理以及二維紋理坐標 (u,v) 發生關聯。每次渲染三角形中的像素的時候，都必須在紋理中找到對應的紋素，這是根據在螢幕上像素與頂點的距離在與紋理坐標相關聯的三角形頂點之間插值完成的。在透視投影中，插值是在根據頂點深度分開的紋理坐標上進行的，這樣做就可以避免透視縮減（perspective foreshortening）問題。

在確定像素最終顏色之前，必須根據場景中的所有光源計算像素上的光照。在場景中通常有三種類型的光源。「定向光」是在場景中按照一個固定方向傳輸並且強度保持不變的光。在現實生活中，由於太陽距離遙遠所以在地球上的觀察者看來是平行光線並且其衰減微乎其微，所以太陽光可以看作是定向光。「點光源」是從空間中明確位置向所有方向發射光線的光源。在遠距離的物體上的入射光線會有衰減。最後一種是「聚光燈」，如同現實生活中的聚光燈一樣，它有一個明確的空間位置、方向以及光錐的角度。另外，經常在光照計算完成之後添加一個環境光值以補償光柵化無法正確計算的全局照明效果。

有許多可以用於光柵化的濃淡演算法。所有的濃淡處理演算法都必須考慮與光源的距離以及遮蔽物體法向量與光照入射角。最快的演算法讓三角形中的所有像素使用同樣的亮度，但是這種方法無法生成平滑效果的表面。另外也可以單獨計算頂點的亮度，然後繪製內部像素的時候對頂點亮度進行插值。速度最慢也最為真實的實現方法是單獨計算每點的亮度。常用的濃淡模型有 Gouraud著色法 和 Phong著色法。

## 加速技術

為了在任何柵格化引擎中獲得最大的性能，只能往渲染工具中發送最少數量的多邊形。人們已經開發出了一些加速技術以剔除無法看到的物體。

### 後向剔除

最簡單的剔除多邊形之方法就是剔除所有背離觀察者的多邊形，這就是後向剔除。由於大多數三維物體都是封閉的，所以除非觀察者位於物體內部，背離觀察者的多邊形都會被面向觀察者的多邊形所遮擋。多邊形的方向由它的旋繞方向（winding）或者送到渲染工具的頂點順序所確定。一旦多邊形變換到螢幕空間之後，就可以檢查它是否位於相反的方向，一旦如此就丟棄這個多邊形。當然，後向剔除不適合於簡併的不封閉立體。

### 空間數據結構

許多先進的技術使用數據結構剔除觀察物體之外的物體或者被其它物體遮擋的物體，最為常用的數據結構有二元空間分割、八叉樹以及「Cell and Portal Culling」。

## 進一步改進

儘管基本的柵格化過程已經出現了數十年，許多當今的應用仍然在優化、增加柵格化渲染引擎的應用範圍。

### 紋理映射

紋理是在特定的解析度生成的，但是由於紋理覆蓋的表面與觀察者之間可能是任意的距離，所以紋理也可能最後圖像上有任意的尺寸。因此，螢幕上的一個像素通常並不直接對應於一個紋素，而是需要使用一些紋理濾波技術來生成任意距離的清晰圖像。有許多在圖像質量與計算的複雜性進行不同這種考慮的方法可以完成這項工作。

### 環境映射

環境映射是紋理坐標與觀察點相關的紋理映射形式。例如，其中一個常用的應用程式就是用來模擬鏡面反射，我們可以將整個房間內部環境映射到房間內的一個金屬杯上，當觀察者沿著杯子移動的時候，杯子頂點的紋理坐標也隨之變化，這樣就得到反射效果。

### 凸凹紋理映射

凸凹紋理映射是改變像素深度而不是顏色的另外一種紋理映射形式。尤其是與最新的陰影工具一起使用的時候，凸凹紋理映射使得表面顯現出與光照有關的凸凹不平，從而大幅度地提高真實感。

### 細節層次

在許多當今的應用中，任何場景中的多邊形數目都是非常大的，但是場景中的觀察者只能區分近距物體的細節。細節層次算法根據物體與觀察者的距離改變幾何圖形的複雜性。正對著觀察者的物體需要進行非常複雜的渲染，而距離遠的物體可以動態地簡化，甚至可以完全適用二維 sprite 替代。

### 陰影

傳統柵格化過程的光照計算沒有考慮物體遮擋的因素。陰影貼圖與陰影體是當今兩種生成陰影的普通技術。

## 硬體加速

從1990年代開始，用於消費型桌面電腦的硬體加速開始變得普通。圖形程式設計師早期依賴於手工編寫彙編程序以改善程序的運行速度，現在大多數的程序已經使用現有的圖形 API 驅動專用的圖形處理器。

目前的圖形處理器已普遍帶有幾乎完全是可程式化的 繪圖管線，包含對各個頂點及片段進行處理，並有多種圖形API來幫助開法者使用這些管線，如 OpenGL 和 Vulkan 等。

## 外部連結

- Michael Abrash’s articles on computer graphics
- 微軟 DirectX API
- OpenGL API
- Matrices (including transformation matrices) from MathWorld
- OpenGL對於其所提供圖形管線API的說明