計算機圖形學十二:Whitted-Style光線追蹤原理詳解及實現細節

(本篇文章同步發表於知乎專欄:https://zhuanlan.zhihu.com/p/144403005 歡迎三連關注)

摘要

本篇內容主要分爲兩部分,第一部分會從爲什麼需要光線追蹤入手,一步步介紹Whitted-style光線追蹤的原理。第二部分則會具體介紹一些光線追蹤的實現細節,包括光線的表示,光線與物體的求交,以及反射折射方向的計算。

1 Whitted-Style 光線追蹤

在進入原理講解之前,我們首先考慮一下爲什麼需要光線追蹤呢?
因爲Blinn-Phong這種局部模型無法處理全局效果!
舉個例子:

如上圖中房屋頂部的所接受到的光可不僅僅是Blinn-Phong模型考慮的直接光源,還有可能是來自窗外的光源照射到地板,再發生反射照射到了房屋頂部,而這部分光是局部光照模型沒有考慮到的,而光線追蹤正是爲了解決這種問題所提出的一種全局光照模型。
換個角度來考慮,光柵化雖然快但是得到的圖像質量一般較低,爲了追求更好的結果當然就會尋求更加完美的模型了。

1.1 光線追蹤原理解釋

光線追蹤聽名字就知道,討論的核心是光線,因此我們首先對光線做一些假設。
1 光線一定沿着直線傳播
2 光線之間無法碰撞
3 光線路徑可逆,即從A發出的到B的光線,一定也可以從B發出到A(中途可發生反射和折射)

明白了光線的一些假設之後,想一想人爲什麼能看到不同的物體?是因爲從物體表面上有光進入了人眼。那麼能不能逆向思考一下,是不是也可理解爲人眼發出了很多感知光線碰撞到了物體,所以可以看見呢?在古代可還真就有不少人這麼想:

當然,現代物理知識已經告訴我們這種觀點是錯誤的,但是並不妨礙從中獲取一些靈感,考慮一下對光線的第三條假設:光路可逆,所有進入到人眼的光,都可從人眼發出光按照原路反方向返回,那麼利用這種模擬從人眼發射光線的方法不就可以還原出所有的光路了呢?沒錯這就是光線追蹤的核心想法,正着不行那就反着來!

第一步 Ray Casting

從人眼或攝像機向近投影平面上的每一個像素點發射一條光線,判斷與場景物體的交點,示意圖如下:

當然一條光線自然可能會與不止一個物體相交,但是考慮遮擋關係,只去找最近的交點。接着連接該交點和光源,只要判斷這條連線之間是否有物體存在就可以知道該交點是否在陰影之中(怎麼樣,是不是比shadow mapping那一套簡單了許多):

緊接着,自然可以利用Blinn-Phong模型對這個點進行局部光照模型計算,得到該像素的顏色,那麼遍歷所有近投影平面上的像素就能得到一張完整的圖像。但如果光線追蹤僅僅是在第一步Ray Casting就停止的話,那麼它的效果與局部光照模型是一樣的,因此我們需要第二步,真正的考慮全局效果

第二步 Recursive (Whitted-Style) Ray Tracing
考慮第一步中所做的Ray Casting,該條光線第一個與圓球物體相交,假設該圓球是一個玻璃球,那麼便會發生鏡面反射,如圖:

當然除了鏡面反射之外,自然也存在折射,同時反射與折射出去的光線會可能與場景中的物體再次碰撞,發生第二次折射與反射:

(爲了圖示清晰,圖中僅以兩次折射或反射的部分光線爲例)
從圖中可以見到,不僅僅是與圓球相交的那一點可以貢獻光到達眼睛,折射與反射之後再與物體相交的點也可以貢獻光(光路可逆原理)。簡而言之,除了直接從光源照射到圓球交點再沿着 eye rays(第一條發射的光線)到眼睛中,也可能存在這樣一種情形,有光照射到其他物體,再沿着eye rays的反射或折射的光線方向傳回人眼!

因此每一個交點的顏色貢獻來自這樣種幾類型 直接光照,反射方向間接光,折射方向間接光(如果有折射的話)

下一步將這些所有交點與光源連接,稱這些線爲shadow rays(因爲可以用來檢測陰影),計算這些所有點的局部光照模型的結果,將其按照光線能量權重累加(該做法與遞歸過程等價,讀者可以看看僞代碼思考一下),最終得到近投影平面上該像素點的顏色!而這就是一個全局光照模型了,因爲不僅僅考慮了直接光源的貢獻,還考慮各種折射與反射光線的貢獻。

以上就是光線追蹤的整個過程了,還有額外幾點要注意的
tips:

  1. 整體過程是一個遞歸的過程,因此需要一定的遞歸終止條件,比如說允許的最大反射或折射次數爲10。
  2. 光線在每次反射和折射之後都有能量損耗的,由係數決定,因此越往後的折射和反射光貢獻的能量越小,這也是爲什麼在上文中提到根據光線能量權重求和。
    e.g. 反射係數爲0.7,那麼第一次反射折損30%,第二次反射折損1-(70%x70%),依次類推。
  3. 如果反射或折射光線沒有碰撞到物體,一般直接返回一個背景色。
  4. 有一些關於光線表示,及如何求交點的實現細節在1.2節裏討論。

參考僞代碼如下:

如果讀者是第一次接觸光線追蹤的話,理解起來還是有點難度,但是隻要真正的去實現一遍,就能很快的理解其原理,因此我在這裏推薦一個我看過的很不錯的教程:RayTracingInOneWeekend 這個教程手把手的教你用c++實現了一個沒有帶光源的光線追蹤器出來,並且還帶有許多細節方面原理知識的講解,寫的通俗易懂!

2 光線的表示方法

我們可以將每一條光線想象成一條射線,那麼每一條光線都會由起點及方向這兩個屬性所固定,如下圖所示:

除了起點 o\bold{o}, 以及方向 d\bold{d}之外,還額外定義了一個參數 t 來表示光線行進的長度。

3 光線與物體求交的方法

3.1 光線與隱式曲面求交的方法

首先介紹如何計算光線與隱式曲面的交點的方法,以一個球體爲例,二者表示方程如下:

光線的表示方法在上節已經介紹過,對於一個球體來說,其表面上所有點 p\bold{p}, 到圓心c\bold{c}的距離是固定爲 R 的, 也就得到了上述的球的隱式曲面方程。

那麼對於一個光線會在什麼時候與球相交呢?

當然是在一個點即滿足光線方程,又滿足球體方程的時候,所以可以計算如下,把
p=o+td\bold{p} = \bold{o}+t\bold{d}代入球體方程,利用一元二次方程的解法即可得到參數 t 值:

同樣的根據 b24acb^2-4ac 的正負關係,即可判斷光線與球是一個交點還是兩個交點又或是沒有交點,這都是中學知識了,不多贅述。

雖然這裏只舉了對一個球的隱式曲面交點的計算,對於所有其他隱式曲面過程都是類似的,只要將光線方程代入求解 t 即可,如下圖所示
在這裏插入圖片描述

3.2 光線與顯示曲面求交的方法

當然,真正在圖形學中大量運用的其實是顯示曲面,更具體來說就是許許多多個三角形,因此如何判斷一條光線與顯示曲面的交點,其實也就是計算光線與三角形面的交點。對於任意一個平面,可以用如下圖中的式子表達:
在這裏插入圖片描述
圖中對於平面方程的講解已經很清楚。那麼到這裏其實已經成功把對顯示曲面的求交又轉化爲了類似隱式曲面求交的方法,對於任意一個三角面來說,它一定處於一個平面之上,只需求出光線與平面的交點,再判斷該交點是否在三角形內,就可以得到光線是否與三角形面相交的結果了!

首先給出如何計算光線與平面交點的過程:
在這裏插入圖片描述
得到參數 t 之後,自然可以計算出交點,並且再去計算出重心座標就能判斷該交點是否在三角形內了,但是這種方法略顯繁瑣,能不能一步就得到結果呢?當然可以!
在這裏插入圖片描述
直接將點的形式用重心座標的形式表示,隨後利用克萊姆法則求解線性方程組即可!(推導過程省略,但其實就是用了線代知識裏面的克萊姆法則。)

4 反射與折射

4.1 反射方向的計算

反射方向計算相對容易,如下圖所示,已知 l\bold{l},n\bold{n}想要求出反射方向r\bold{r}
在這裏插入圖片描述
計算如下:
r=2n(ln)l\bold{r} = 2\bold{n}(\bold{l}\cdot\bold{n})-\bold{l}
幾何含義便是 入射光線 l\bold{l} 在法向上投影的兩倍再減去入射光線 l\bold{l} 方向,即可得到r\bold{r}

4.2 折射方向的計算

折射方向的推導其實是由斯奈爾定理(Snell’s Law)得來的:

nsinθ=ntsinϕ(1)nsin\theta = n_tsin\phi \tag{1}

其中nnntn_t分別代表反射平面兩邊的反射率,如下圖所示左半部分爲n,右半部分爲ntn_t
在這裏插入圖片描述
根據 sin2+cos2=1sin^2+cos^2 = 1以及 (1)式,可以推出 cosϕcos\phi 如下:

cos2ϕ=1n2nt2(1cos2θ)(2) cos^2\phi =1- \frac{n^2}{n_t^2}(1-cos^2\theta) \tag{2}
但是,這僅僅是求得了反射角度,更希望得到的是向量形式的方向 t\bold{t},因此根據上圖,可以得到如下關係(圖中皆爲單位向量):
t=sinϕbcosϕn(3) \mathbf{t}=\sin \phi \mathbf{b}-\cos \phi \mathbf{n}\tag{3}
其中 b\bold{b} 是未知的,但是可以根據入射光線 d\bold{d} 推出
d=sinθbcosθnb=d+ncosθsinθ(4) \mathbf{d}=\sin \theta \mathbf{b}-\cos \theta \mathbf{n} \\ \mathbf{b}=\frac{\mathbf{d}+\mathbf{n} \cos \theta}{\sin \theta}\tag{4}
如此(3)式當中所有的變量都是已知,計算得到折射方向 tt 如下:
t=n(d+ncosθ))ntncosϕ=n(dn(dn))ntn1n2(1(dn)2)nt2(5) \begin{aligned} \mathbf{t} &=\frac{n(\mathbf{d}+\mathbf{n} \cos \theta))}{n_{t}}-\mathbf{n} \cos \phi \\ &=\frac{n(\mathbf{d}-\mathbf{n}(\mathbf{d} \cdot \mathbf{n}))}{n_{t}}-\mathbf{n} \sqrt{1-\frac{n^{2}\left(1-(\mathbf{d} \cdot \mathbf{n})^{2}\right)}{n_{t}^{2}}} \end{aligned} \tag{5}

至此就已經成功得到了折射方向,但是有沒有什麼問題呢?
這就要說到菲涅耳反射了!

4.3 菲涅耳反射(Fresnel Reflection)

注意(5)式在計算折射方向時,用到了
cosϕ=1n2nt2(1cos2θ)(6) cos\phi =\sqrt{1- \frac{n^2}{n_t^2}(1-cos^2\theta)} \tag{6}
顯而易見的,一定要保證根號裏面是正數,那麼有沒有可能會是負數呢?我們說這是有可能的,如果從一個折射率大的空間折射如一個折射率小的空間,折射角度會增大,且
n/nt>1n/n_t > 1,只要入射 θ\theta 角度足夠大,1cos2θ1 - cos^2\theta 就會接近1,那麼此時根號裏的數便會小於 0,而這也就意味着,此時沒有折射項,光線全部反射

大家不妨在家實驗一下,如果你垂直觀察玻璃,你很容易看清玻璃外的東西(折射而來),如果你視線玻璃近乎平行,此時你看到的大部分會是你自己(反射得到),且視線越與玻璃平行,即與法線夾角越大,你的人像越加清晰,這種現象,就可以用菲涅爾反射來進行解釋!
在這裏插入圖片描述
簡單來說,便是物體的反射率其實與你的觀察角度即有關,對於絕緣體來說觀察角度與法線夾角越大,反射的程度就越大,如下圖:
在這裏插入圖片描述
(其中光線極化什麼的那兩條線不用太去管,只要知道對於絕緣體角度越大反射越多即可)
而導體則與絕緣體不同,他的反射率與夾角呈如下關係:
在這裏插入圖片描述
想想金屬確實反射率一直很大,所以很有光澤。符合上圖的規律

那麼對於任意一個物體該去怎麼計算出它的精確的反射率呢?計算公式如下:
在這裏插入圖片描述
當然這裏考慮了兩個極化,然後再求平均,我們不需要知道爲什麼要這麼算,只要知道,物體的反射率和入射角度,和入射空間的折射率,和物體的折射率有關就可以了,然後套公式算就能得出正確的反射率了!那麼對於精確的算法來說,可以看到計算量是非常大的,因此就有大佬提出了個簡單的算法,近似得到結果,但計算量大大減小,如下:
在這裏插入圖片描述

Note:whited-style光線追蹤該如何考慮漫反射?

在Blin-Phong模型中層提到過,漫反射是光線照射到粗糙物體表面從而發生向周圍均勻反射光線的一種現象,反射的光線可以說是無數的!

那麼對於這種反射,在光線追蹤該怎麼處理呢?借鑑RayTracingInOneWeekend 裏的做法,對於漫反射表面每次進行反射的時候,隨機的選取物體表面向外半圓內的一個方向作爲該次反射的方向,對其再像鏡面反射及折射一樣進行遞歸的光線追蹤計算。

但對每一個像素不僅僅只發出一條感知光線,利用多條光線RayTracing的結果求均值,最終作爲該像素的顏色值

比如說我每個像素sample 1000條光線,如果撞到漫反射表面那就是1000條隨機方向的 RayTracing結果的均值,這樣便能較爲準確的模擬了漫反射表面的特性了。
(對一個像素進行多次sample,其實也就把抗鋸齒也給做了)

tips:
該方法更多算是path tracing,對於傳統的whited-style光線追蹤來說遇到漫反射表面會直接返回點着色值而不再遞歸下去。

更多的細節,讀者可以自行的去連接裏面看。

總結

至此我們已經瞭解了光線追蹤的原理,明白了光線的表示以及光線與隱式曲面,顯示曲面的求交方法,同時也介紹了折射反射方向的計算,以及菲涅爾項等細節內容,相信讀者已經可以自己去嘗試寫一個光線追蹤器的出來了,當然也可以去參考閆老師的作業以及文中所提到的RayTracingInOneWeekend裏的做法。

本來是想把光線追蹤的加速結構一起寫進來的,但是發現已經寫挺多了,所以對於加速方法打算放在下一篇文章在寫吧!

最後如果本文對你有幫助求點贊求關注 😃 ,後序會持續更新,感謝閱讀!

Reference

[1] Fundamentals of Computer Graphics 4th
[2] GAMES101-現代計算機圖形學入門-閆令琪
[3] RayTracingInOneWeekend

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章