[光線追蹤] 08 -- 更多相機(jī)
在之前已經(jīng)實(shí)現(xiàn)了最基本的針孔相機(jī),? 現(xiàn)在就來進(jìn)行一個(gè)其他相機(jī)的實(shí)現(xiàn).

平行相機(jī)
這里為了名稱統(tǒng)一,? 就把使用平行投影的相機(jī)稱作平行相機(jī)了.? 平行投影可以看作視點(diǎn)位于無限遠(yuǎn)處的立體投影,? 但是直接把無窮引入計(jì)算里會(huì)導(dǎo)致不少問題,? 所以需要給平行相機(jī)單獨(dú)做一個(gè)類型.
在立體相機(jī) (也就是針孔相機(jī)) 里,? d 解釋為視平面中心對(duì)于視點(diǎn)的相對(duì)位置,? 所以視方向也等于 d.? 但在平行相機(jī)里,? 因?yàn)橐朁c(diǎn)位置不參與計(jì)算,? 所以視平面中心需要世界坐標(biāo)表示,? 而視方向也需要另外給出.? 那么平行相機(jī)可以實(shí)現(xiàn)為

正如針孔相機(jī)里說過那樣,? 要手動(dòng)給出紋理坐標(biāo)系 u, v 是非常不直觀的做法,? 所以平行相機(jī)也應(yīng)該給出一個(gè)比較直觀的構(gòu)造方法.? 在針孔相機(jī)里存在 fov (視野范圍) 這一項(xiàng),? 但因?yàn)槠叫邢鄼C(jī)的理論視點(diǎn)在無限遠(yuǎn)處,? 所有非零的 fov 都會(huì)使視平面變?yōu)闊o限大.? 所以在平行相機(jī)里使用視平面寬度代替 fov 項(xiàng),? 那么比較直觀的構(gòu)造方法為:

然后構(gòu)建一個(gè)場(chǎng)景進(jìn)行渲染,? 這個(gè)場(chǎng)景也是下面所有相機(jī)的渲染場(chǎng)景:??



在這里需要注意到右下角的黑色圓形:? 盡管理論上平行相機(jī)的視點(diǎn)是在無限遠(yuǎn),? 但為了避免無窮,? 實(shí)際上光線的起點(diǎn)是在視平面上的,? 所以在視平面背后的物體是不可見的.? 在這幅圖里,? 視平面剛好有一部分在球體內(nèi)部,? 并且球體是不透明的,? 所以造成了渲染圖里的一個(gè)黑色圓形.

透鏡相機(jī) (景深)
景深就是當(dāng)物體不在相機(jī)的焦點(diǎn) (應(yīng)該說焦平面) 上時(shí)會(huì)產(chǎn)生失焦,? 從而造成物體的輪廓變得模糊.? 有關(guān)景深的更多知識(shí)可以去 wiki 看看?[https://zh.wikipedia.org/zh-cn/%E6%99%AF%E6%B7%B1].
在光柵化渲染里可以實(shí)現(xiàn)偽景深,? 但因?yàn)檫@個(gè)過程是在已有的渲染輸出上進(jìn)行的,? 所以光柵化渲染的景深在細(xì)節(jié)上是有錯(cuò)誤的.? 光追可以對(duì)相機(jī)里的透鏡進(jìn)行建模從而模擬出準(zhǔn)確的景深,? 下圖是一個(gè)現(xiàn)實(shí)相機(jī)的簡(jiǎn)單模型:

傳感器平面與透鏡在外部組成了一個(gè)虛構(gòu)的平面,? 焦平面,? ?在焦平面上的所有點(diǎn)都可以完美對(duì)焦,? 而不在焦平面上的點(diǎn)則會(huì)失焦,? 如下圖所示,? 并且距離焦平面越遠(yuǎn)失焦越嚴(yán)重

可以看到離開焦平面的點(diǎn)在傳感器上會(huì)形成一片區(qū)域,? 而不是一個(gè)點(diǎn),? 并且這個(gè)區(qū)域的形狀取決于透鏡的形狀.
與針孔相機(jī)類似,? 在實(shí)現(xiàn)時(shí)可以對(duì)透鏡相機(jī)的模型進(jìn)行化簡(jiǎn).? 可以看到上面的圖里,? 以透鏡為中心,? 左右兩邊的模型可以看作是相似的,? 并且近似地忽略薄透鏡的折射,? 化簡(jiǎn)的模型為:

在這個(gè)模型里,? 傳感器即是焦平面,? 透鏡變?yōu)橐粋€(gè)圓面,? 并且從下面的圖例可以看到不在焦平面上的點(diǎn)在傳感器上仍然會(huì)擴(kuò)散為一片區(qū)域.? 那么可以對(duì)針孔相機(jī)進(jìn)行修改:? 視點(diǎn)位置作為透鏡的圓心位置,? 那么為了模擬景深,? 相機(jī)射出的光線起點(diǎn)不再是視點(diǎn),? 而是透鏡上的任意點(diǎn),? 剩余部分跟針孔相機(jī)相同.? 另外,? 景深強(qiáng)度正比于透鏡的半徑,? 大概是就是所謂的光圈? 對(duì)攝影學(xué)一概不通就是了,? 所以我直接用 lens_radius 了.

透鏡相機(jī)大部分參數(shù)與針孔相機(jī)相同,? 這里就不多說了.? 下面是透鏡相機(jī)對(duì)應(yīng)的 get_ray 方法:

里面需要注意的是如何獲得在透鏡上的采樣點(diǎn),? 這里我是直接使用視平面的紋理坐標(biāo)系 u, v 獲得透鏡采樣點(diǎn)相對(duì)于視點(diǎn)的位置.? 但如同之前說的那樣,? 在移軸相機(jī)里 u, v 不是與視方向 d 垂直的,? 所以這樣也會(huì)造成透鏡不與 d 垂直,? 但是我也不能真的搞到一臺(tái)移軸相機(jī)來實(shí)驗(yàn)究竟是什么情況就是了.? 另外,? 如果在對(duì)透鏡進(jìn)行采樣時(shí)不對(duì) u, v 進(jìn)行歸一化的話,? 透鏡將會(huì)是一個(gè)與畫面長(zhǎng)寬比相同的橢圓.
下面簡(jiǎn)單進(jìn)行展示:


在這里,? 對(duì)焦距離在綠球附近,? 所以只有綠球是清晰的,? 而紅球和藍(lán)球是模糊的.? 更改對(duì)焦距離 (focus distance) 和 透鏡半徑 可以改變渲染結(jié)果:


題外話:? 可以留意到紅球的邊界與綠球之間產(chǎn)生了明顯的黑邊,? 這就是?RGB 空間不準(zhǔn)確的地方了,? 為了得到正確的色彩,? 顏色混合應(yīng)該在 XYZ 空間內(nèi)進(jìn)行.? 但這個(gè)就是另外的話題了.

魚眼相機(jī)
魚眼相機(jī)是一個(gè)非線性投影的相機(jī),? 在魚眼相機(jī)里,? 視平面不再是一個(gè)長(zhǎng)方形,? 而是球體的一部分,? 關(guān)于魚眼相機(jī)可以去看看 wiki [https://en.wikipedia.org/wiki/Fisheye_lens].
對(duì)于魚眼相機(jī),? 在視點(diǎn)處的局部坐標(biāo)系 {p; u, v, d} 里,? 天頂角 θ 與像素點(diǎn)到圖像中心的距離 r 成一定關(guān)系,? 并且這個(gè)關(guān)系確定了魚眼相機(jī)的類型: (選自 wiki)

在這里僅實(shí)現(xiàn)保角魚眼相機(jī) (即上圖里的 Equidistant) 作為展示,? 因?yàn)槠渌愋偷聂~眼相機(jī)都涉及反三角函數(shù)的分類討論,? 這里就不搞這些了.? 那么魚眼相機(jī)可以實(shí)現(xiàn)為:


get_ray 里的過程就是從像素位置得到到圖像中心的距離 r,? 然后計(jì)算立體角對(duì)應(yīng)的局部坐標(biāo) tex,? 最后把局部坐標(biāo)轉(zhuǎn)為全局坐標(biāo)即是光線的方向 d.
然后進(jìn)行展示:


可以看到,? 魚眼相機(jī)的 fov 可以達(dá)到 200°,? 從而使在場(chǎng)景里的另外兩個(gè)球體也出現(xiàn)在了畫面中.? 實(shí)際上,? 與針孔相機(jī)不同的是,? 在這里實(shí)現(xiàn)的魚眼相機(jī)是沒有視野限制的,? 但超過 360° 會(huì)非常扭曲,? 如下圖所示


球極全景相機(jī)
全景相機(jī)就是可以看到所有方向的相機(jī),? fov 為 360° 的魚眼相機(jī)就是一個(gè)典型的全景相機(jī).? 全景相機(jī)的模型多種多樣,? 這里要實(shí)現(xiàn)的是基于球極坐標(biāo)的簡(jiǎn)單全景相機(jī).
在球極相機(jī)里,? 天頂角 θ 和方位角 φ 與 figure 上的紋理坐標(biāo) tex_u, tex_v 成一次關(guān)系.? 在所有相機(jī)里,? 紋理坐標(biāo)的值都是在 [-1, 1] 里 (opengl標(biāo)準(zhǔn)? dx 是 [0,1]),? 那么則有映射關(guān)系:?,? 剩下的東西就和魚眼相機(jī)里差不多了.? 但需要注意的是,? 魚眼相機(jī)里的局部坐標(biāo)為 {u, v, d},? 而在球極相機(jī)里為 {d, u, v},? 這是為了保證視方向在圖像中心.? 那么球極相機(jī)實(shí)現(xiàn)為:

展示:


因?yàn)檫@里的 fov 已經(jīng)固定 (360°),? 所以當(dāng)改變長(zhǎng)寬比時(shí)會(huì)造成物體的扭曲:

只有長(zhǎng)寬比為2:1時(shí)物體扭曲為最小.

項(xiàng)目倉(cāng)庫:??https://github.com/nyasyamorina/nyasRT
群:?274767696