離線渲染中的不規則光源(Meshlight)


    之前一直在考慮這樣一個問題,在實際生活中的光源都是有體積的,但是圖形學中,很多時候我們用簡單的點光源,面光源,或者方向光來模擬實際生活中這些光源,勢必會產生一些誤差,同時導致很多效果不好做。那么在離線渲染中要怎么對不規則光源進行渲染呢?首先很容參考的是之前我用path tracing模擬環境光照的例子(http://www.cnblogs.com/starfallen/p/3520021.html),即給光源所包含的所有三角面加上一個發光屬性,然后直接使用path tracing渲染場景,當從視點發出的ray擊中這些三角面中的一個時,認為成功找到一條有效路徑。這個方法是可行的,只是效率實在太低了,特別是當光源面積比較小的時候。使用bidirectional path tracing就能解決這個問題,但是我們都知道BDPT是需要對光源進行采樣的,而如何在不規則光源上采樣就是這個問題的關鍵了。這個問題,我自己一開始也是沒有想出來該怎么做,在向Len3d大牛請教之后才明白,下面來看它的解決方案。

    為了簡化問題,我們只考慮均勻光源,即光源面上每個點的亮度是一樣的,那么在光源上采點的問題也可以看成是如何在一個給定mesh上均勻采樣一個點的問題。我們知道一個mesh是由很多三角面組成的,要在mesh上采樣一個點,首先要采樣一個三角面,然后再在三角面上取一個點。取點的依據是光源的表面積,也就是要把光源的表面積算出來,這里我們就用組成光源的所有三角面的面積表示光源表面積了。接下來是把所有光源上的三角形按照面積做成一個cdf(cumulative density function),然后用這個cdf來對光源三角形進行采樣得到一個目標三角形,最后在這個目標三角形上取一個點即可。為了更形象一點說明,舉一個例子:

如上圖,假設光源由ABCD四個三角形構成,它們的面積分別是A=4,B=2.2,C=1.8,D=2,光源總面積S為10,cdf就是ABCD按順序的累計概率密度函數p(x)。

p(A)=A/S=0.4;

p(B)=(A+B)/S=0.62;

p(C)=(A+B+C)/S=0.8;

p(D)=(A+B+C+D)/S=1.0;

於是正如上圖最后的表格所示,采樣的時候,我們先隨機產生一個0-1的隨機數r,

if (r<=p(A)) 取到三角形A;

else if(r<=p(B)) 取到三角形B;

else if(r<=p(C)) 取到三角形C;

else 取三角形D;

當然這樣做的話,算法復雜度就是O(n),對於一些復雜的光源來說,通常有成千上萬的三角面,效率顯然是不足的。利用cdf函數單調遞增的特點,可以考慮折半查找的方法,每次取三角形序列中間位置的三角面R,並比較該三角面的cdf值與隨機數r的大小(比較r與p(R)的大小),依次遞歸。或者做一個哈希桶,比如把cdf函數10等分,把0-0.1區間的三角形放在一起,0.1-0.2區間的三角形放在一起,以此類推,當取到隨機數r的時候,先判斷r落在哪個區間上,然后再對這個區間中的三角形進行查詢,選取合適的三角形。

    選取到合適的三角形后,接下來就是要在這個三角形上均勻取一個點,方法很多,我參考的是網上給出的方法(http://stackoverflow.com/questions/4778147/sample-random-point-in-triangle):給定三角形三個頂點A,B,C以及兩個[0,1]隨機數r1,r2,隨機取點P:

P = (1 - sqrt(r1)) * A + (sqrt(r1) * (1 - r2)) * B + (sqrt(r1) * r2) * C

這樣一來,主要的問題就解決了,得到了光源的采樣點后,剩下的就和bidirectional path tracing算法其余的部分一致了。下面兩張圖是用了meshlight的渲染結果:

 

 

     最后要說的一點是,雖然這個方法也可以處理不均勻光源或者帶紋理的光源,但是由於沒有進行重要性采樣,所以效率不高,更好的方法是在構造cdf函數的時候把表面亮度考慮進去,但是目前我沒有做這一點。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM