新建網頁 1
圖形管道概述
我們將討論渲染一幅帶有基本光照的單個圖像的大體過程,這里不考慮動畫和全局光照,如陰影和輻射度。
此外,注意這里只從概念上講解通過圖形管道的數據流,其順序并不是固定的。實踐中,我們也許會為了性能的優化而并行或亂序執行一些任務。比如,考慮到不同的渲染API,我們可能首先變換和照明所有頂點,然后才進一步的處理(進行裁剪和剔除),或者會并行處理二者,也可能在背面剔除之后再進行光照會得到更高效率。
還有一個我們將不詳細討論的要點,即工作負擔如何在CPU與渲染硬件間分配。正確地組織渲染任務,以求得最大的并行效果對高效渲染是至關重要的。
考慮上述簡化,就得到了圖形管道中數據流的概況,如下所示:
(1)建立場景:開始渲染之前,需要預先設定對整個場景有效的一些選項。比如,要建立攝像機位置,或者更具體些,要選擇進行渲染的出發點---視點,渲染的輸出---視圖。還需要設定光照與霧化選項,同時準備z緩沖。
(2)可見性檢測:選好了攝像機,就必須檢測場景中哪些物體是可見的。可見性檢測對實時渲染極為重要,因為我們不愿意浪費時間去渲染那些根本看不到的東西。
(3)設置物體級的渲染狀態:一旦發現某物體潛在可見,就到了把它實際繪制出來的時候。每個物體的渲染設置可能是不同的,在渲染該物體的任何片元之前,首先要設置上述選項,最常見的此類選項是紋理映射。
(4)幾何體的生成與提交:接著實際向API提交幾何體,通常提交的數據是種種形式的三角形,或是獨立的三角形,或是索引三角網格與三角帶。此階段,我們可能會應用LOD,或者漸進式生成幾何體。
(5)變換與光照:一旦渲染API得到了三角形數據,由模型空間向攝像機空間的頂點坐標轉換與頂點光照計算即開始。
(6)背面剔除與裁剪:然后,那些背對攝像機的三角形被去除("背面剔除");三角形在視椎外的部分也被去除,稱作裁剪---這可能導致產生多于三個邊的多邊形。
(7)投影到屏幕空間:在3D裁剪空間中經裁剪產生的多邊形,被投影到輸出窗口的2D屏幕空間里。
(8)光柵化:當把裁剪后的多邊形轉換到屏幕空間后,就到了光柵化階段。光柵化指計算應繪制三角形上的哪些像素的過程,并為接下來的像素著色階段提供合理的插值參數(如光照和紋理映射坐標)。
(9)像素著色:最后,在管道的最后階段計算三角形的色彩,此過程稱作"著色"。接著把這些顏色寫至屏幕,這是可能需要alpha混合與z緩沖。
下面的偽代碼描述了渲染管道,為了達到概觀的目的,大量細節被省去了。同時,由于渲染平臺和API的不同,實踐中會有許多不同的形式。
Listing 15.1: Pseudocode for the graphics pipeline
// First, figure how to view the scene
setupTheCamera();
// Clear the zbuffer
clearZBuffer();
// Setup environmental lighting and fog
setGlobalLightingAndFog();
// Get a list of objects that are potentially visible
potentiallyVisibleObjectList = highLevelVisibilityDetermination(scene);
// Render everything we found to be potentially visible
for (all objects in potentiallyVisibleObjectList)
{
// Perform lower-level VSD using bounding volume test
if (!object.isBoundingVolumeVisible())
continue;
// Fetch or procedurally generate the geometry
triMesh = object.getGeometry()
// Clip and render the faces
for (each triangle in the geometry)
{
// Transform the vertices to clip space, and perform vertex-level lighting
clipSpaceTriangle = transformAndLighting(triangle);
// Is the triangle backfacing?
if (clipSpaceTriangle.isBackFacing()) continue;
// Clip the triangle to the view volume
clippedTriangle = clipToViewVolume(clipSpaceTriangle);
if (clippedTriangle.isEmpty())
continue;
// Project the triangle onto screen space and rasterize
clippedTriangle.projectToScreenSpace();
for (each pixel in the triangle)
{
// Interpolate color, zbuffer value, and texture mapping coords
// Perform zbuffering and alpha test
if (!zbufferTest())
continue;
if (!alphaTest())
continue;
// Shade the pixel.
color = shadePixel();
// Write to the frame buffer and zbuffer
writePixel(color, interpolatedZ);
}
}
}
設定視圖參數
渲染場景之前,首先必須建立攝像機和輸出窗口。即必須決定從哪個位置進行觀察渲染(視點位置、方向、縮放)以及把渲染結果送到哪里(屏幕上的目標矩形區域)。上述二者中,輸出窗口較為簡單,故先討論輸出窗口。
指定輸出窗口
我們不一定要把圖像渲染到整個屏幕。比如,一個分屏的多人游戲,每個玩家只占據顯示屏幕的一部分。輸出窗口即指輸出設備中圖像將要渲染到的那部分,如圖15.1所示:

窗口位置由左上角像素(winPosx,winPosy)給出,整數winResx、winResy是以像素為單位的窗口大小,如此定義,使用窗口大小而不是右下角的坐標,可避免整數像素坐標系帶來一些麻煩。同時要注意窗口的實際物體大小和像素大小的區別。
要知道我們不一定在屏幕上渲染,也許只是將渲染結果保存到一個TGA文件里,或是AVI的一幀,也許只是渲染到一個紋理上---作為主渲染器的一個子過程而已,因此,名詞"幀緩沖"一般指用來保存我們正渲染圖像的那塊內存。
像素縱橫比
不管是渲染到屏幕還是緩沖區,我們必須知道像素的縱橫比。它是像素高對寬的比值,一般為1("方形"像素),不過并非總是如此。下面給出其計算公式(公式5.1):

pixPhys指像素物理尺寸。一般來說,度量單位并無關系,比例才是重要的。devPhys是顯示設備的物理高與寬比,尺寸可能是英寸、英尺、picas等,但也只有比例才是重要的。比如,標準的桌面顯示器,尺寸各異但卻擁有相同的比值4:3---視區寬大于高約33%。另一個常見比例是高清晰電視和DVD上的16:9。整數devResx和devResy是x、y方向的像素比,如640 x 480指devResx=640,devResy=480。
如前所述,比值為1的方形像素最為常見。如標準桌面顯示器,有4:3的物理縱橫比,而許多常見解析度:320 x 240,640 x 480,800 x 600,1024x 768,1600 x 1200也都是4:3,因此像素是方形的。
注意計算中未用到窗口的尺寸及位置,這是合理的,窗口性質不影響像素的物理屬性。但是,窗口尺寸在視場問題中十分重要,而位置對攝像機到屏幕的映射是關鍵。
視錐
視錐是攝像機可見的空間體積,看上去像截掉頂部的金字塔,如圖15.2所示:

視錐是由6個裁剪面圍成的。構成視錐的4個側面稱為上、左、下、右面,它們對應著輸出窗口的四邊。為防止物體離攝像機過近,設置近剪面,從而去除金字塔形的頂端。同理,也設置了視野的遠端,因為太遠的物體實際上太小而不可見,故可有效而安全地去掉。
視場與縮放
攝像機同其他物體一樣有位置和朝向,同時它還具有"視場"這一額外的屬性。另一名詞"縮放"你也許已經很熟悉,直觀上,你早就知道放大和縮小。但拉近時,物體顯大;拉遠時,物體顯小,這太常見了。
視場是視錐所截的角。實際上需要兩個角:分別對應水平視場和垂直視場。這里只在2D中討論其中一個,圖15.3從上方顯示了視錐,精確的展示了水平視場角,坐標軸的標記用的是攝像機空間。

縮放表示物體實際大小和物體在90。視場中顯示大小的比。所以大比值表示放大,小比值表示縮小。比如,2.0的縮放表示物體在屏幕上比用90。視場時大兩倍。縮放的幾何解釋如圖15.4所示:

應用基本三角知識,就能推導出縮放和視場角之間的轉換公式:

在3D中,需要兩個縮放值,一個水平的,一個垂直的。可以隨意給值,但如果二者比例不恰當,圖像便像被拉伸過似的(好比寬銀幕電影在電視上播出)。為了維持恰當的比例,縮放要和輸出窗口的尺寸對應:

假設輸出為正常比例,許多渲染引擎允許僅用一個視場角(或zoom值)設定攝像機,然后自動計算另一個。例如,可以指定水平視場角,自動計算垂直視場角,反之亦然;或者指定視場角中較大的一個,自動計算較小的。