這章全面講述了用於實時陰影渲染中常見兩種流派之一的陰影體(shadow volumes)技術,又稱模板陰影(stencil shadows)技術,重點是得到正確的角度的情形,減少幾何圖形和填充率的消耗。
陰影體渲染建立乙個陰影體積,並僅在其外部的物體上處理照明,我們將使用模板緩衝區作為演算法的關鍵元件, 因此名稱 - stencil shadow volume。陰影體積演算法背後的想法是將光線減弱時建立的物件輪廓擴充套件到乙個volume中,然後使用一些簡單的模版操作將該volume對映到模板緩衝區中。 關鍵的想法是,當乙個物件在volume內(因此在陰影中)時,volume前面的多邊形會對物件的多邊形進行深度測試,並且該volume後部的多邊形將失效相同的測試,或者說不參與測試。
我們將根據稱為depth fail的方法設定模板操作,人們經常使用更直接的方法稱為depth pass來實現陰影體積技術,但是其致命缺點是當視點在陰影中時,會導致模板計數錯誤,而depth fail的方法修復了該錯誤。
我們在左下角有乙個燈泡,乙個綠色的物體(稱為遮擋物體),由於光而投下陰影, 在這個場景中也渲染了三個圓形的物件。 物件b被遮蔽,而a&c不是。 紅色箭頭限定陰影體積的區域(線的虛線部分不是它的一部分)。
我們首先將實際物件(a,b,c和綠色框)渲染到深度緩衝區中(從相機位置觀察的)。 當我們完成後,我們可以獲得最接近的畫素的深度。 然後我們乙個接乙個地遍歷場景中的物件,並為每個物件建立乙個陰影體積。 這裡的示例僅顯示綠色框的陰影體積,但在完整的應用程式中,我們還將為圓形物件建立volume,因為它們投射自己的陰影。 陰影體積是通過檢測它的輪廓來建立的並將其擴充套件到無限遠。 我們使用以下簡單規則將該volume渲染到模板緩衝區中:
1、如果在渲染陰影體積的背面多邊形時深度測試失敗,我們會增加模板緩衝區中的值。
2、如果在渲染陰影體積的前面多邊形時深度測試失敗,我們會減小模板緩衝區中的值。
3、在深度測試通過,模板測試失敗情況下,我們什麼都不做。
讓我們看看使用上述方案的模板緩衝區會發生什麼。
物體a:渲染陰影體的背面時深度測試失敗(由於a的阻擋),所以模板緩衝值加1.渲染陰影體的前面時深度測試失敗(由於a的阻擋),所以模板緩衝值減1,所以最後結果是對於物體a,起模板緩衝中的值為0.
物體b:渲染陰影體的背面時深度測試失敗(由於b的阻擋),所以模板緩衝值加1.渲染陰影體的前面時深度測試成功所以最後結果是對於物體b,起模板緩衝中的值為1.
物體c:渲染陰影體的背面時深度測試成功,渲染陰影體的前面時深度測試也成功所以最後結果是對於物體c,起模板緩衝中的值為0.
請注意,到目前為止,我們還沒有碰到色彩緩衝區。 當我們完成上述所有的操作後,我們再次使用標準的照明著色器渲染所有的物件,但是這次我們設定模板測試,使得只有模板值為零的畫素才會被渲染。 這意味著只有物件a&c才能使其在螢幕上顯示出來。
讓我們看看如何把這個知識付諸實踐。 正如我們前面所說,我們需要渲染當我們擴充套件遮擋物的輪廓時建立的體積。 我們所需要做的就是將輪廓邊緣延伸到乙個體積中, 這是通過為每個輪廓邊緣從gs發射四(或實際上四角形拓撲中的四個頂點)來完成的。 前兩個頂點來自剪影邊緣,當我們沿著從光照位置到頂點的向量將邊緣頂點延伸到無窮大時,生成其他兩個頂點。 通過延伸到無限遠,我們確保體積捕獲位於陰影路徑中的所有物體。 這個四邊形如下圖所示:
當我們重複這個從所有輪廓邊緣發射四邊形的過程時,會建立乙個體積。 夠了嗎? 當然不。 問題是這個體積看起來像乙個沒有蓋子的截錐體。 由於我們的演算法依賴於檢查體積的前後三角形的深度測試,所以我們可能會遇到乙個情況,即從眼睛到畫素的向量可能沒有通過正面或背面,如下圖這個狀況:
解決這個問題的方法是生成乙個在兩邊封閉的體積。 這是通過建立乙個正面和後面到體積(上圖中的虛線)完成的。 建立前蓋非常容易。 面向光的每個三角形都成為前蓋的一部分。後蓋需要將面向三角形的光的頂點延伸到無限遠(沿著從向量到每個頂點)並反轉它們的順序(否則所得到的三角形將指向體積內)。「無限」一詞在這裡已經提到過幾次,我們現在需要確切地說明這是什麼意思。 看看下面的:
我們看到的是從上面取出的截頭錐體的, 燈泡發出乙個穿過點p並繼續無限遠的光線。 換句話說,p擴充套件到無限遠。 顯然,在無窮遠處,點p的位置是簡單的(無窮大,無窮大,無窮大),但是我們不在乎。 我們需要找到一種光柵化陰影體積的三角形的方法,這意味著我們必須在投影平面上投影其頂點。 實際上這個投影平面是近平面。 雖然p沿著光向量延伸到無窮遠,但我們仍然可以在近平面上投射它。 這是通過從原點開始的虛線完成的,並在某處穿過光向量。 我們要找到xp,它是該向量穿過近平面的點的x值。
我們將光向量上的任何點描述為p + vt,其中v是從光源到點p的向量,t是從0到無窮大的標量。 從上圖和三角相似之處可以看出:
其中n是近平面的z值。 隨著t到無窮大,化簡公式如下所示:
所以這就是我們在近平面上如何找到「無限遠」的投影,根據上述我們只需要乘以向量(vx,vy,vz,0)(其中v是從光源到向量的點p的向量)來計算通過檢視/投影矩陣並應用透視分割、
總結一下 z-fail演算法(john carmack's reverse)
1. 先關閉光源,將整個scence渲染一遍,獲得深度值
2. 關閉深度寫,渲染陰影體的背面,深度測試失敗則模板值加1
3. 渲染陰影體的正面,深度測試失敗則模板值減1
4. 最後模板值不為0的面便處於陰影體中,開啟深度寫
5. 用模板手法重新渲染一次加光的scence即可,陰影部分不渲染色度
6. 注意,該演算法要求陰影體積是閉合的,即需要前後封口
7. 該方法不是沒有缺陷的,有可能因為z-far clip plane過近而導致模板計數錯誤
GPU Gems1 8 衍射的模擬
小尺度的表面細節引起反射波彼此干擾,這個現象就是衍射。首先,計算機繪圖的大多數表面反射模型都忽略自然光的波動效果。當表面的細節比光的波長 約1um 大許多時,不存在問題。但對於小尺寸的細節,例如乙個光碟的表面,波效應就不能忽略了。所以,對於小尺度的表面細節引起反射波彼此干擾的現象,即為衍射。衍射使這...
GPU Gems1 24 高質量的過濾
在一些應用中,高質量的過濾是至關重要的,可以用畫素shader 執行任何過濾。gpu著色程式不用於cpu的主要之處在於 一般來說,cpu數學操作比紋理訪問更快,而在gpu中恰恰相反。影象過濾的目的很簡單 對於給你的輸入影象a,我們想要建立新的影象b。把源影象a變換到目標影象b的操作就是影象濾波。最一...
有效的注釋
前言 隨著軟體技術的不斷發展,開發人員正日益重視設計模式和實現模式。然而有效的注釋也是 的重要組成部分。世界級軟體大師kent beck 大名鼎鼎的junit作者 在其著作implementation patterns中指出 programs are read more often than the...