Shadow Volume( 陰影體)渲染技術的實現細節及感覺(一)之 陰影體生成

  首先貼一個連接,該連接內有大量基於OpenGL的渲染技術教程和Code Sample,本文基本上在其Tutorial 40的基礎上進行了翻譯,並加入了部分本身的理解。原文在此:html

  http://ogldev.atspace.co.uk/index.htmlapp

  

  Shadow Volume,即陰影體技術。是CG中很是常見的陰影渲染技術。在本身動手實現以前,也看了好多原理上的東西。可是紙上得來終覺淺,絕知此事要躬行啊! 以此文記錄下Shadow Volume實現過程當中的種種。spa

  簡單地講,光線照射空間幾何物體,被物體遮擋住的空間沒有不能受到光源光線的直射,這個空間一樣能夠用一個幾何體表示,這個幾何體就是所謂的Shadow Volume(如下簡稱SV),即陰影體。位於SV裏的物體的即爲被陰影包圍的物體。翻譯

  實現時的一些關鍵點:3d

  一、SV的生成。code

  二、Z-Fail Stencil Test.htm

  三、陰影的渲染。blog

 

 

一、SV的生成:教程

  

  如上圖所示,左圖的綠色部分和右圖的灰色部分即爲 陰影體。陰影體是實實在在的Mesh,跟左圖的」人「和右圖的」摩托車"同樣,都是由三角形面片組成的。咱們須要根據光源的位置和陰影的生產者(Shadow Caster)的形狀去生成這個Mesh(某物體A遮住了光源,產生了陰影,咱們稱物體A爲Shadow Caster,簡稱SC。某物體B被物體A遮擋,在B上形成了陰影,咱們稱物體B爲Shadow Receiver,簡稱SR)。仔細觀察上圖,咱們會發現陰影體起始於SC面向光源的面,而終止於SR。陰影體在SC上的面像個蓋子(cap),在SR上的面像底兒(bottom)蓋子底兒之間的三角形面片圍一圈造成邊兒(surrounding),這個密閉空間就是陰影體的空間。用一個簡單的三角形做爲SC,以下圖所示:索引

  

  綠色的Cap(即三角形ABC),深灰的bottom(即三角形A'C'B')以及surroundings(四邊形CBB'C', CC'A'A, AA'B'B)組成了SV Mesh。!注意上述三角形的順序,遵循右手定則。

  可是實際上,陰影體的Cap並非位於SC上,而是沿着光源的方向有一個小的偏移量。陰影體的Bottom也不在SR上,而在無窮遠處,上圖中的A',B',C'分別爲A,B,C沿着入射光方向被投射到無窮遠處的對應點。以下圖所示:

  

  紫色的三角形A''B''C''是真正的Cap。這是爲了不Z-fighting。

  那麼,生成陰影體Mesh的問題能夠轉化爲尋找蓋子底兒邊兒的過程。有了這些面兒,將它們圍起來就是一個閉合的陰影體Mesh。

  下面開始生成SV Mesh。對於SC的一個三角形面片T,它有三個邊a,b,c,三個鄰面Ta,Tb,Tc,分別與T共享邊a,b,c。那麼僞代碼以下:

  

 1 for every triangle facet T in the SC:
 2 
 3     if T faces the light
 4 
 5       generate the cap triangle by applying a displacement to the original T.     //生成Cap
 6 
 7       generate the bottom triangle by projecting the original T to infinity.   //生成Bottom
 8 
 9       for every adjacent triangle Tx ( x = a,b,c )        
10 
11         if Tx faces the light
12 
13            edge x is not part of the silhouette, continue.
14 
15         else
16 
17           edge x is part of the silhouette, generate the surrouding triangles.
18 
19      else 
20 
21       continue 

 

   上面的僞代碼在Geometry Shader中實現。

  上面的僞代碼中提到了 Silhouette (輪廓)。是的,SV Mesh 的 Surrounding Triangles 只在屬於 Silhouette 的三角形邊處生成。關於silhouette如何檢測,上述僞代碼已經說得比較清楚了,其原理也比較簡單,可是Silhouette detection在大多數狀況下仍然做爲一個單獨的問題來討論。

  下面就簡單提一下:

  silhouette Detection(邊界檢測)。邊界檢測相關資料不少了,原理也很簡單。在計算機圖形學中,物體由三角形面片(triangle facet)組成。以光照邊界檢測爲例,物體外部有某光源(point,spot or direction light ),這個物體上的全部三角面片要麼直接受該光源照射(該面法向量與入射光線方向夾角大於90小於180°),要麼不直接受光源照射(該面法向量與入射光線方向夾角大於等於0°小於等於90°),那麼必然有一個「邊的集合」位於這兩種三角形面片相交的邊界處。邊緣檢測即找出這個「邊的集合」。以下圖二維示意圖所示。面向和背向光源的三角面片共享的邊即咱們須要尋找的邊。(該圖摘自http://ogldev.atspace.co.uk/www/tutorial39/tutorial39.html  ,在原圖基礎上加入中文圖示)

      

  如何去尋找呢?很簡單。以下圖所示,對某三角形A,有鄰面B,C,D。若是A面對光源,那麼遍歷其三個鄰面,若是鄰面背對光源,那麼A與該鄰面共享的那條邊便是邊界。若是其三個鄰面也全都面對光源,那麼面A的三條邊都不屬於邊界。

  

  該邊緣檢測的計算過程能夠在Geometry shader中進行。因爲Geometry shader 能夠訪問Primitive的adjacency信息,因此能夠方便地對每一個三角形的鄰面進行信息讀取和計算。固然,在OpenGL Application端須要向Pipeline提供具備adjacency信息的數據並按照必定地規則進行排列。例如上圖中的三角形A,在提供此Primitive信息的時候應該按頂點索引(0,1,2,3,4,5)的順序在內存中排列。具體如何從任意3d模型中計算adjacency信息,在此不詳細說明。

   如何將SC上的頂點project到無窮遠處做爲Bottom的頂點呢?以下圖所示:

  

  光源將頂點P投射到無窮遠處,而後投影到near clip(近裁剪面)的上,其X軸座標爲Xndc.

(圖引自 http://ogldev.atspace.co.uk/www/tutorial40/tutorial40.html )

 

  n爲近裁剪面的距離,v爲光源到頂點P的向量,t爲標量,從0到正無窮。當t趨向正無窮時,就獲得咱們想求的Xndc。

(圖引自 http://ogldev.atspace.co.uk/www/tutorial40/tutorial40.html )

  同理,Yndc也可由此獲得。

  至此,SV的生成到此結束。

   下圖是實驗結果:五環上方有旋轉的點光源,下方是個球體。粉色的部分是陰影體。

  

相關文章
相關標籤/搜索