99、NeRF ray space

CG相機模型

在圖形學中最常用的相機模型的原理和小孔成像是類似的。
在這里插入圖片描述
不同之處在于,如上圖,小孔成像得到的圖像是倒立的,但是我們希望得到的圖像是正向的,因此,我們選擇小孔前成像。
在這里插入圖片描述
從 3D 到 2D 的投影,就是根據 3D 物體的坐標,計算其投影到 2D 成像平面上的坐標。對于一個已有的相機而言,只有在恰當位置范圍內的 3D 物體才可能投影到成像平面上。這個恰當范圍,跟成像平面的大小,以及相機中心到平面距離等因素有關。

在圖形學中有一個專門的模型來定義這個范圍:
在這里插入圖片描述
上圖這個形似棱錐的模型,就是相機的可視范圍。其中,有兩個重要的概念:Near clipping planeFar clipping plane

Near clipping plane 是相機前方的平面,也就是成像平面,Far clipping plane 是更遠處的平面,限制了相機最遠可視的范圍,它們都與相機的 z 軸垂直。在這兩個平面之間的空間,就是相機的可視范圍。在這個范圍內的物體,才能投影到相機的成像平面上。在圖形學中,這個可視范圍被稱為視錐體 (Viewing Frustum)。

在真實的相機中,Far clipping plane 一般是無限遠的,但在圖形學中,為了簡化計算,一般將其設置為有限的距離。
在這里插入圖片描述

3D坐標到2D坐標

在這里插入圖片描述
上圖是一個典型的物體投影到屏幕上的過程。我們假設已經獲得了物體在世界坐標系中的坐標,在世界坐標系轉換到圖像坐標系的過程中,涉及以下過程。

世界坐標系轉換到相機坐標系

對三維物體投影的第一步,是將三維物體從世界坐標系轉換到以相機為中心的坐標系統,這樣方便后續的投影計算。

相機坐標系是以相機為中心的坐標系 (也叫 eye coordinates),由于相機和世界坐標系的原點可能不同,且其坐標軸方向和世界坐標系可能不同,因此世界坐標系和相機坐標系的轉換一般涉及旋轉平移兩項操作。

在圖形學中,通常使用齊次坐標,并配合 4x4 的矩陣來完成兩個坐標系統的轉換。

相機坐標系到屏幕坐標系

獲得物體的相機坐標系(Near clipping planeFar clipping plane 之間)后,接下來就可以計算物體投影到成像平面上的坐標。

這個過程可以根據相似三角形的原理計算得出。
在這里插入圖片描述

如上圖所示,假設相機的中心在 A 點,三維物體在 C 點,其在成像平面上的投影為 C’。

由于我們已經獲得了物體在相機坐標系中的坐標,因此可以計算出 AB、BC 的長度。而 AB’、B’C’ 的長度,可以根據相似三角形的原理計算出來 (上圖假設相機焦距是 1,但實際情況中不做限制,我們用 Z n e a r Z_{near} Znear?表示):

B C A B = B ′ C ′ A B ′ \frac{BC}{AB} = \frac{B'C'}{AB'} ABBC?=ABBC?

P . y ∣ P . z ∣ = P ′ . y Z n e a r P ′ . y = Z n e a r ? P . y ∣ P . z ∣ \frac{P.y}{|P.z|} = \frac{P'.y}{Z_{near}} \\ P'.y = \frac{Z_{near}*P.y}{|P.z|} P.zP.y?=Znear?P.y?P.y=P.zZnear??P.y?

同樣的,可以算出 : P ′ . x = Z n e a r ? P . x ∣ P . z ∣ P'.x = \frac{Z_{near}*P.x}{|P.z|} P.x=P.zZnear??P.x?

對于 z 軸坐標來說,由于 Near clipping plane 和 z 軸是垂直的,因此所有投影到成像平面上的點,z 坐標都是相同的。而事實上在投影到 2D 坐標后,z 軸坐標已經沒有意義了,因此可以直接忽略。

P ′ . x P'.x P.x P ′ . y P'.y P.y 可以發現,投影到成像平面上的坐標,其 x 和 y 坐標都是除以 z 坐標得到的。因此這種投影變換也被稱為 z divide 或者 perspective divide。這也是透視投影的特點,投影到成像平面上的坐標,其 x 和 y 坐標都是 與 z 坐標絕對值成反比的。也因此,物體越遠,其在屏幕上的大小越小。

屏幕坐標系到圖像坐標系

轉換到屏幕坐標系后,我們理論上已經獲得了物體的 2D 坐標,但這個坐標并不是最終圖像上的坐標。

在第 2 步相機坐標系到屏幕坐標系的轉換中,不難發現,屏幕坐標系的原點是在屏幕中心的,但在圖像坐標系中,原點一般是在左上角或者左下角。因此,要轉換到圖像坐標系,還需要一步歸一化的過程。

在不同的系統中,圖像坐標系的原點是存在差異的。比如,有些系統中的圖像原點位于左下角,y 軸朝上,但有些則反著來。而 NDC 坐標系是一個跟設備無關的坐標系統,它將圖像的 x/y/z 軸都統一歸一化到 [0, 1],并規定了坐標軸方向 (在有些圖形系統中,也會將 x/y/z 軸歸一化到 [-1, 1]),如下圖所示 (中間即是 NDC 坐標系)。

NDC 全稱是 Normalized Device Coordinate,也即歸一化的設備坐標系。這是從屏幕坐標系轉換到圖像坐標系的中間媒介。
在這里插入圖片描述
用上圖的例子來演示 屏幕坐標系 -> NDC 坐標系 -> 圖像坐標系 (即上圖的 raster 坐標系) 的轉換過程。

假設 投影屏幕 長寬分別為 height、width,NDC 的原點在左下角,y 軸朝上,那么,屏幕坐標系到 NDC 坐標系的轉換公式為:

P b d c . x = P ′ . x + w i d t h / 2 w i d t h P b d c . y = P ′ . y + h e i g h t / 2 h e i g h t P_{bdc}.x = \frac{P'.x+width/2}{width} \\ P_{bdc}.y = \frac{P'.y+height/2}{height} Pbdc?.x=widthP.x+width/2?Pbdc?.y=heightP.y+height/2?

假設圖像大小為 image_height、image_width,圖像原點位于左上角,y 軸朝下。那么,NDC 坐標系圖像坐標系的轉換公式為:

P i m a g e . x = P n d c . x ? i m a g e _ w i d t h P i m a g e . y = ( 1 ? P n d c . y ) ? i m a g e _ h e i g h t P_{image}.x = P_{ndc}.x * image\_width \\ P_{image}.y = (1-P_{ndc}.y) * image\_height Pimage?.x=Pndc?.x?image_widthPimage?.y=(1?Pndc?.y)?image_height

NDC 坐標系是連續的坐標系,只有轉換到圖像坐標系,才會對坐標進行取整操作。此外,NDC 坐標系仍是三維坐標系,不過在考慮投影的時候,z 軸通常會被忽略

OpenGL 中,NDC 坐標到 raster 圖像坐標的轉換過程,也被稱為 viewport transform

采用 NDC 坐標的好處是,我們可以將 NDC 看作是一個通用的坐標系統,并將不同系統的坐標統一起來。比如,我們在將屏幕坐標系轉換到圖像坐標系時,可以先換算到統一的 NDC 坐標系中,再實現二者的相互轉化。在 NDC 坐標系中進行處理的時候,就不需要關心投影屏幕長寬、圖像大小等信息了。

投影矩陣(Projection Matrix)

從上面三維坐標到二維坐標的轉換過程中,不難發現,整個過程涉及步驟很多,非常繁瑣。為了簡化計算,在很多圖形系統中,會將物體從相機坐標系到 NDC 坐標系的過程,用一個矩陣串聯起來 (即投影矩陣)。

即完成所有操作總共需要兩個矩陣:世界坐標系和相機坐標系之間的變換矩陣、投影矩陣。

理解投影矩陣,對后面 NeRF 中 NDC 坐標系統的推導至關重要。因此,這里先詳細介紹投影矩陣的由來,并補充一些相關的數學知識。

不同坐標系統的轉換

三維坐標轉二維坐標的第一步,就是將物體從世界坐標系轉換到相機坐標系。

這一步在投影矩陣的求解中是不需要的。不過,由于圖形學中,不同坐標系之間的轉換是一個基本操作。

任何三維坐標系統,都可以用三個互相垂直的坐標軸以及坐標原點來唯一確定。

這三個坐標軸,在線性代數中,也被稱為基向量v={ v 1 , v 2 , v 3 v_1,v_2,v_3 v1?,v2?,v3?} 。通常情況下,我們會用標準向量 e 1 = [ 1 , 0 , 0 ] e_1=[1,0,0] e1?=[1,0,0] e 1 = [ 0 , 1 , 0 ] e_1=[0,1,0] e1?=[0,1,0] e 1 = [ 0 , 0 , 1 ] e_1=[0,0,1] e1?=[0,0,1] 來表示這三個坐標軸。不過事實上也可以隨意定義,只要它們線性無關,可以表達出整個三維空間即可。

現在,假設有兩個不同的坐標系統 A 和 B。A 的基向量 v = { v 1 , v 2 , v 3 } v=\{v_1,v_2,v_3\} v={v1?,v2?,v3?},B 的基向量 u = { u 1 , u 2 , u 3 } u=\{u_1,u_2,u_3\} u={u1?,u2?,u3?} 。根據線性無關,可以得出:

u 1 = γ 11 v 1 + γ 12 + γ 13 v 3 u 2 = γ 21 v 1 + γ 22 + γ 23 v 3 u 3 = γ 31 v 1 + γ 32 + γ 33 v 3 u_1 = \gamma_{11}v_1+\gamma_{12}+\gamma_{13}v_3 \\ u_2 = \gamma_{21}v_1+\gamma_{22}+\gamma_{23}v_3 \\ u_3 = \gamma_{31}v_1+\gamma_{32}+\gamma_{33}v_3 \\ u1?=γ11?v1?+γ12?+γ13?v3?u2?=γ21?v1?+γ22?+γ23?v3?u3?=γ31?v1?+γ32?+γ33?v3?

用矩陣方程的形式表示為:
u = M v u=Mv u=Mv

對于三維空間中的某個點 w 來說,均可以由 u、v 這兩個坐標系表示:
w = a T v = b T u w=a^Tv=b^Tu w=aTv=bTu

其中的 a T a^T aT b T b^T bT 其實就是 w 在這兩個坐標系統中的坐標。再結合公式 (2),可以得到:

w = b T u = b T M v = a T v w=b^Tu=b^TMv=a^Tv w=bTu=bTMv=aTv

由此推出, a = M T b , b = ( M T ) ? 1 a a=M^Tb,b=(M^T)^{-1}a a=MTb,b=(MT)?1a

到這里,我們就發現:對于點 w 來說,想要從坐標系 A 轉換到坐標系 B,只需要對原坐標系 A 中的坐標,乘以一個矩陣 M 即可。反之,則是乘以矩陣的逆 ( M T ) ? 1 (M^T)^{-1} (MT)?1。而這個矩陣M ,可以通過兩個坐標系統的基向量,也就是坐標軸,通過公式 (1) 的矩陣方程進行求解。

在將物體從世界坐標系轉到相機坐標系的過程中,只需要將這個矩陣應用到世界坐標系的物體坐標上,就可以得到三維物體相對于相機坐標系的位置坐標。

這個過程中,物體的實際位置沒有發生任何改變,只不過它的坐標,從相對于世界坐標系,變成相對于相機坐標系。

在這里插入圖片描述

齊次坐標(Homogenous Coordinates)

上面提到的變換矩陣 M 存在一點不足,那就是它只能表達旋轉和縮放操作,但無法表達平移。具體原因有很多資料已做了描述,這里不再贅述。

在三維世界中,旋轉、縮放、平移是三個最基礎的操作,因此,為了將平移也融入矩陣運算中,人們引入了齊次坐標。

齊次坐標相比普通的三維坐標,就是在 x、y、z 之外,再引入一維 w:[x,y,z,w]。

同時我們規定 [x,y,z]=[x,y,z,w=1],即當 w=1 時,齊次坐標可以等價于普通的三維坐標。

如果 w ≠ 1 w\neq1 w=1 ,那換算方法是: [ x , y , z , w ] = [ x w , y w , z w ] [x,y,z,w] = [ \frac{x}{w},\frac{y}{w},\frac{z}{w}] [x,y,z,w]=[wx?,wy?,wz?]

引入齊次坐標后,變換矩陣自然也可以拓展成 4x4 的維度。

[ m 00 m 01 m 02 T x m 10 m 11 m 12 T y m 20 m 21 m 22 T z 0 0 0 1 ] ? [ x y z w = 1 ] \left[ \begin{matrix} m_{00} & m_{01} & m_{02} & T_x \\ m_{10} & m_{11} & m_{12} & T_y \\ m_{20} & m_{21} & m_{22} & T_z \\ 0 & 0 & 0 & 1 \end{matrix} \right] * \left[ \begin{matrix} x \\ y \\ z \\ w=1 \end{matrix} \right] ?m00?m10?m20?0?m01?m11?m21?0?m02?m12?m22?0?Tx?Ty?Tz?1? ?? ?xyzw=1? ?

在 w=1 的情況下,矩陣第 4 列代表的,就是 x、y、z 對應的平移量。

在之后投影矩陣的計算過程中,齊次坐標的作用會更加明顯。

投影矩陣推導

假設我們已經獲得了物體在相機坐標系中的坐標 P e = [ x e , y e , z e ] P_e=[x_e,y_e,z_e] Pe?=[xe?,ye?,ze?] (如果只有世界坐標系,也可以通過前面所講的不同坐標系統的變換,來轉換到相機坐標系,這一步也屬于相機外參標定的流程)。

P e P_e Pe? 從相機坐標系轉換到 NDC 的過程,其實就是將 P e P_e Pe? 從下圖左邊的棱錐轉換到右邊的立方體的過程 (這里使用 OpenGL 中的坐標習慣,NDC 將 x/y/z 軸都歸一化到 [-1, 1]):
在這里插入圖片描述
假設 Near Clipping Plane 到相機中心的距離為 n。在 OpenGL 等圖形庫中,由于相機坐標系的 z 軸是朝向屏幕外的,因此 Near Clipping Plane 上,點的 z 坐標均為 z = -n。

再假設 Near Clipping Plane 平面上,x 軸的屏幕范圍是 [l,r],y 軸的屏幕范圍是 [b,t],那么屏幕上四個邊界點的坐標分別是:(l,t,-n)、(r,t,-n)、(l,b,-n)、(r,b,-n)

首先,將點 P e P_e Pe? 投影到 Near Clipping Plane 上。根據上文的介紹,這就是 z divide 的過程,由此得到投影后的坐標為:

x p = n ? x e ? z e y p = n ? y e ? z e x_p = \frac{n*x_e}{-z_e} \\ y_p = \frac{n*y_e}{-z_e} \\ xp?=?ze?n?xe??yp?=?ze?n?ye??

在投影后需要考慮把超出屏幕的點裁剪掉,不過這一步也可以放在后面進行,我們先跳過。

接下來就是把投影后的點轉換到 NDC 空間了,這是歸一化的過程,把 [l,r] 和 [b,t] 這兩個區間的數值歸一化到 [-1,1] 。可以分兩步完成。

先把 x p x_p xp? 歸一化到 [0,1]: x p ? l r ? l \frac{x_p-l}{r-l} r?lxp??l?

再從 [0,1] 歸一化到 [-1,1]: 2 ? x p ? l r ? l ? 1 2*\frac{x_p-l}{r-l}-1 2?r?lxp??l??1

x n d c = 2 ? x p ? l r ? l ? 1 = 2 x p r ? l ? r + l r ? l x_{ndc} = 2 * \frac{x_p-l}{r-l}-1 \\ = \frac{2x_p}{r-l} - \frac{r+l}{r-l} xndc?=2?r?lxp??l??1=r?l2xp???r?lr+l?

同理可得 y n d c y_{ndc} yndc?:
y n d c = 2 y p t ? b ? t + b t ? b y_{ndc} = \frac{2y_p}{t-b} - \frac{t+b}{t-b} yndc?=t?b2yp???t?bt+b?

由此我們已經得到了 NDC 中的 x/y 坐標(將上述 y p , x p y_p,x_p yp?,xp?代入)。完整的轉換公式:

x n d c = 2 n ? x e ? z e ? ( r ? l ) ? r + l r ? l y n d c = 2 n ? y e ? z e ? ( t ? b ) ? t + b t ? b x_{ndc} = \frac{2n*x_e}{-z_e*(r-l)} - \frac{r+l}{r-l} \\ y_{ndc} = \frac{2n*y_e}{-z_e*(t-b)} - \frac{t+b}{t-b} xndc?=?ze??(r?l)2n?xe???r?lr+l?yndc?=?ze??(t?b)2n?ye???t?bt+b?

這個公式看起來復雜,但可以融入到齊次坐標中,變成矩陣運算:

[ x c y c z c w c ] = [ 2 n r ? l 0 r + l r ? l 0 0 2 n t ? b t + b t ? b 0 0 0 A B 0 0 ? 1 0 ] ? [ x e y e z e w e = 1 ] \left[ \begin{matrix} x_c \\ y_c \\ z_c \\ w_c \end{matrix} \right ] = \left[ \begin{matrix} \frac{2n}{r-l} & 0 & \frac{r+l}{r-l} & 0 \\ 0& \frac{2n}{t-b} & \frac{t+b}{t-b} & 0 \\ 0& 0 & A & B \\ 0& 0 & -1 & 0 \\ \end{matrix} \right] * \left[ \begin{matrix} x_e \\ y_e \\ z_e \\ w_e = 1 \end{matrix} \right] ?xc?yc?zc?wc?? ?= ?r?l2n?000?0t?b2n?00?r?lr+l?t?bt+b?A?1?00B0? ?? ?xe?ye?ze?we?=1? ?

其中 A、B是待求解的參數。

x c x_c xc? 為例,計算過程如下:
x c = 2 n x e r ? l + r + l r ? l ? z e w c = ? z e x_c = \frac{2nx_e}{r-l} + \frac{r+l}{r-l} * z_e \\ w_c = -z_e xc?=r?l2nxe??+r?lr+l??ze?wc?=?ze?

由于 w ≠ 1 w\neq1 w=1,需要除去 w 才能得到最終的坐標

x n d c = x c w c = 2 n ? x e ? z e ? ( r ? l ) ? r + l r ? l x_{ndc} = \frac{x_c}{w_c} \\ = \frac{2n*x_e}{-z_e*(r-l)} - \frac{r+l}{r-l} xndc?=wc?xc??=?ze??(r?l)2n?xe???r?lr+l?

這樣子求出的 x n d c x_{ndc} xndc? 和上述的一致,這就是使用齊次坐標的好處。

由于 r 和 l 是沿中心對稱的,即 l=-r,所以 r-l=2r,r+l=0。同理 t-b=2t,t+b=0 。所以矩陣可以簡化為:
[ n r 0 0 0 0 n t 0 0 0 0 A B 0 0 ? 1 0 ] \left[ \begin{matrix} \frac{n}{r} & 0 & 0 & 0 \\ 0 & \frac{n}{t} & 0 & 0 \\ 0 & 0 & A & B \\ 0 & 0 & -1 & 0 \end{matrix} \right] ?rn?000?0tn?00?00A?1?00B0? ?

上面的矩陣中,還缺失 z e z_e ze? 對應的參數 A、B。由于 z 軸的計算和 x/y 無關,因此矩陣第三行 x/y 對應的參數可以直接設為 0,我們單獨看A、B 如何求解。

由上面的矩陣可以算出: z n d c = A ? z e + B ? z e z_{ndc} = \frac{A*z_e+B}{-z_e} zndc?=?ze?A?ze?+B?

假設 Far Clipping Plane 到相機中心的距離為 f 。那么 z 軸是從 [-n,-f] 歸一化到 [-1,1],即 z e = ? n z_e=-n ze?=?n 時, z n d c = ? 1 z_{ndc} = -1 zndc?=?1 z e = ? f z_e=-f ze?=?f 時, z n d c = 1 z_{ndc}=1 zndc?=1。由此可以得到兩個等式:

? A ? f + B f = 1 A ? n + B n = ? 1 \frac{-A*f+B}{f} = 1 \\ \frac{A*n+B}{n} = -1 f?A?f+B?=1nA?n+B?=?1

解得: A = ? f + n f ? n A=-\frac{f+n}{f-n} A=?f?nf+n? B = ? ? 2 f n f ? n B=-\frac{-2fn}{f-n} B=?f?n?2fn?

最終的矩陣為:

[ n r 0 0 0 0 n t 0 0 0 0 ? f + n f ? n ? 2 f n f ? n 0 0 ? 1 0 ] \left[ \begin{matrix} \frac{n}{r} & 0 & 0 & 0 \\ 0 & \frac{n}{t} & 0 & 0 \\ 0 & 0 & -\frac{f+n}{f-n} & \frac{-2fn}{f-n} \\ 0 & 0 & -1 & 0 \end{matrix} \right] ?rn?000?0tn?00?00?f?nf+n??1?00f?n?2fn?0? ?

這個矩陣,即是所謂的投影矩陣,它可以完成相機坐標系到 NDC 坐標系的轉換。

對于投影點的坐標 ( x n d c , y n d c , z n d c ) (x_{ndc},y_{ndc},z_{ndc}) (xndc?,yndc?,zndc?),如果數值超出 [-1,1] 的范圍,就說明投影后的點超出了屏幕范圍,可以直接舍棄。

NeRF中的NDC ray space

NeRF 中的坐標,是以射線的形式表示:o+td,其中 o 是射線起點,d 是方向向量,t 是射線長度。

所謂的 NDC ray space,就是把這種射線形式表示的坐標,從相機坐標系投影到 NDC 坐標系。因此,轉換的媒介仍然是投影矩陣:

( n r 0 0 0 0 n t 0 0 0 0 ? f + n f ? n ? 2 f n f ? n 0 0 ? 1 0 ) ( x y z 1 ) = ( n r x n t y ? f + n f ? n z ? 2 f n f ? n ? z ) p r o j e c t → ( n r x ? z n t y ? z f + n f ? n ? 2 f n f ? n 1 ? z ) \left( \begin{matrix} \frac{n}{r} & 0 & 0 & 0 \\ 0 & \frac{n}{t} & 0 & 0 \\ 0 & 0 & -\frac{f+n}{f-n} & \frac{-2fn}{f-n} \\ 0 & 0 & -1 & 0 \end{matrix} \right) \left( \begin{matrix} x \\ y \\ z \\ 1 \end{matrix} \right) = \left( \begin{matrix} \frac{n}{r} x\\ \frac{n}{t}y \\ -\frac{f+n}{f-n}z - \frac{2fn}{f-n} \\ -z \end{matrix} \right) \\ project \rightarrow \left( \begin{matrix} \frac{n}{r} \frac{x}{-z}\\ \frac{n}{t}\frac{y}{-z} \\ \frac{f+n}{f-n} - \frac{2fn}{f-n}\frac{1}{-z} \end{matrix} \right) ?rn?000?0tn?00?00?f?nf+n??1?00f?n?2fn?0? ? ?xyz1? ?= ?rn?xtn?y?f?nf+n?z?f?n2fn??z? ?project ?rn??zx?tn??zy?f?nf+n??f?n2fn??z1?? ?

不過,由于坐標的表達形式換了,因此公式上也發生了一些變動

假設我們已經獲得了相機坐標系中的坐標點 P e = o + t d P_e=o+td Pe?=o+td,對應 x/y/z 軸的坐標分別為 (注意區分這里的 t 和投影平面的邊界 t ):
x e = o x + t ? d x y e = o y + t ? d y z e = o z + t ? d z x_e = o_x+t*d_x \\ y_e = o_y+t*d_y \\ z_e = o_z+t*d_z xe?=ox?+t?dx?ye?=oy?+t?dy?ze?=oz?+t?dz?

現在需要求出它在 NDC 坐標系中的投影坐標,假設是 P ′ = o ′ + t ′ d ′ P'=o'+t'd' P=o+td

那么根據投影矩陣, P e P_e Pe? 轉換到 P’ 的過程可以表示為:

x ′ = o x ′ + t ′ ? d x ′ = ? n r ? o x + t ? d x o z + t ? d z y ′ = o y ′ + t ′ ? d y ′ = ? n t ? o y + t ? d y o z + t ? d z z ′ = o z ′ + t ′ ? d z ′ = f + n f ? n + 2 f n f ? n ? 1 o z + t ? d z x' = o'_x +t'*d'_x = - \frac{n}{r} * \frac{o_x+t*d_x}{o_z+t*d_z} \\ y' = o'_y +t'*d'_y = - \frac{n}{t} * \frac{o_y+t*d_y}{o_z+t*d_z} \\ z' = o'_z +t'*d'_z = \frac{f+n}{f-n} + \frac{2fn}{f-n}*\frac{1}{o_z+t*d_z} x=ox?+t?dx?=?rn??oz?+t?dz?ox?+t?dx??y=oy?+t?dy?=?tn??oz?+t?dz?oy?+t?dy??z=oz?+t?dz?=f?nf+n?+f?n2fn??oz?+t?dz?1?

為了簡潔一些,假設 ? n r = a x -\frac{n}{r} = a_x ?rn?=ax? ? n t = a y -\frac{n}{t}=a_y ?tn?=ay? f + n f ? n = a z \frac{f+n}{f-n}=a_z f?nf+n?=az? 2 f n f ? n = b z \frac{2fn}{f-n} = b_z f?n2fn?=bz?。那么上面這堆復雜的式子可以簡化為:

x ′ = a x ? o x + t ? d x o z + t ? d z y ′ = a y ? o y + t ? d y o z + t ? d z z ′ = a z ? b z o z + t ? d z x' = a_x * \frac{o_x+t*d_x}{o_z+t*d_z} \\ y' =a_y * \frac{o_y+t*d_y}{o_z+t*d_z} \\ z' =a_z * \frac{b_z}{o_z+t*d_z} x=ax??oz?+t?dz?ox?+t?dx??y=ay??oz?+t?dz?oy?+t?dy??z=az??oz?+t?dz?bz??

接下來就是要把 o’、t’、d’ 求解出來。

首先,對于 o’ 來說,可以直接通過 o 投影得到,即讓上述公式中 t為0:

o ′ = [ o x ′ o y ′ o z ′ ] = [ a x ? o x o z a y ? o y o z a z + b z o z ] o' = \left[ \begin{matrix} o'_x \\ o'_y \\ o'_z \\ \end{matrix} \right] = \left[ \begin{matrix} a_x * \frac{o_x}{o_z} \\ a_y * \frac{o_y}{o_z} \\ a_z+\frac{b_z}{o_z} \end{matrix} \right] o= ?ox?oy?oz?? ?= ?ax??oz?ox??ay??oz?oy??az?+oz?bz??? ?

在 o’確定后,t‘*d’ 可以表示為:

[ t ′ ? d x ′ t ′ ? d y ′ t ′ ? d z ′ ] = [ x ′ ? o x ′ y ′ ? o y ′ y ′ ? o z ′ ] \left[ \begin{matrix} t'*d'_x \\ t'*d'_y \\ t'*d'_z \end{matrix} \right] = \left[ \begin{matrix} x'-o'_x \\ y'-o'_y \\ y'-o'_z \\ \end{matrix} \right] ?t?dx?t?dy?t?dz?? ?= ?x?ox?y?oy?y?oz?? ?
代入 o x ′ , o y ′ , o z ′ o'_x,o'_y,o'_z ox?,oy?,oz? 并化簡得到
在這里插入圖片描述
解得:
t ′ = t ? d z o z + t ? d z = 1 ? o z o z + t ? d z d ′ = [ a x ? ( d x d z ? o x o z ) a y ? ( d y d z ? o y o z ) ? b z ? 1 o z ] t' = \frac{t*d_z}{o_z+t*d_z} = 1- \frac{o_z}{o_z+t*d_z} \\ d' = \left[ \begin{matrix} a_x * (\frac{d_x}{d_z} - \frac{o_x}{o_z}) \\ a_y * (\frac{d_y}{d_z} - \frac{o_y}{o_z}) \\ -b_z*\frac{1}{o_z} \end{matrix} \right] t=oz?+t?dz?t?dz??=1?oz?+t?dz?oz??d= ?ax??(dz?dx???oz?ox??)ay??(dz?dy???oz?oy??)?bz??oz?1?? ?

當 t = 0時,t’=0,當 t → ∞ t\rightarrow \infty t t ′ → 1 t' \rightarrow 1 t1。所以,在相機坐標系對光線進行采樣 ( t ∈ ( 0 , ∞ ) t\in(0,\infty) t(0,)),就等價于在 NDC ray space 中,對 t’ 在 [0,1] 范圍內進行采樣。

對于投影屏幕來說,可以設定最后成像的圖片長寬 (H*W) 和屏幕大小一致,由于投影屏幕的中心即是坐標原點,因此 r=w/2 ,t=H/2。再假定相機的焦距 f c a m f_{cam} fcam?Near Clipping Plane 到相機中心的距離相等,即 n = f c a m n=f_{cam} n=fcam?。則 a x , a y a_x,a_y ax?,ay? 可以重新表示為:

a x = ? f c a m W / 2 a y = ? f c a m H / 2 a_x = -\frac{f_{cam}}{W/2} \\ a_y = -\frac{f_{cam}}{H/2} \\ ax?=?W/2fcam??ay?=?H/2fcam??

(所謂焦距,指的是相機光圈到成像平面的距離。但正如文章開始提到的,由于圖形學中的相機是模擬的,所以并不存在焦距的概念。只是由于投影平面一般和 Near Clipping Plane 重合,因此可以簡單認為 f c a m = n f_{cam} = n fcam?=n ,但二者其實是不同的概念)

對于 a z a_z az? b z b_z bz? ,由于論文將 f 設定為無窮遠,因此:

a z = lim ? f → ∞ f + n f ? n = lim ? f → ∞ ( 1 + 2 n f ? n ) = 1 a_z = \lim_{f \rightarrow \infty} \frac{f+n}{f-n} \\ =\lim_{f \rightarrow \infty}(1+\frac{2n}{f-n}) \\ = 1 az?=flim?f?nf+n?=flim?(1+f?n2n?)=1

b z = lim ? f → ∞ 2 f n f ? n = lim ? f → ∞ 2 n 1 ? n f = 2 n b_z = \lim_{f \rightarrow \infty} \frac{2fn}{f-n} \\ =\lim_{f \rightarrow \infty} \frac{2n}{1-\frac{n}{f}} \\ = 2n bz?=flim?f?n2fn?=flim?1?fn?2n?=2n

可以得到最終的 o’ 和 d’
在這里插入圖片描述

t ∈ [ 0 , 1 ] t\ \in [0,1] t?[0,1] 內采樣,等價于相機坐標系中在 t ∈ [ 0 , ∞ ] t\in[0,\infty] t[0,] 范圍內采樣。但是,如前文描述的,相機坐標系的可視范圍是從 Near Clipping PlaneFar Clipping Plane 之間,也就是在 z ∈ [ ? ∞ ] , ? n z\in[-\infty],-n z[?],?n 這個區間。為了保證光線上每個采樣點可見,需要把光線起點對齊到 Near Clipping Plane 上。

即 o 沿光線方向移動 t n t_n tn? 個單位后, o z = ? z o_z = -z oz?=?z,表示成公式為:

o z + t n ? d z = ? n t n = n + o z d z o_z+t_n*d_z = -n \\ t_n = \frac{n+o_z}{d_z} oz?+tn??dz?=?ntn?=dz?n+oz??

因此,移動后的光線起點為 o n = o + t n d o_n = o+t_n d on?=o+tn?d

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/210428.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/210428.shtml
英文地址,請注明出處:http://en.pswp.cn/news/210428.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Grad-CAM原理

這篇是我對嗶哩嗶哩up主 霹靂吧啦Wz 的視頻的文字版學習筆記 感謝他對知識的分享 只要大家一提到深度學習 缺乏一定的解釋性 比如說在我們之前講的分類網絡當中 網絡它為什么要這么預測 它針對每個類別所關注的點在哪里呢 在great cam這篇論文當中呢 就完美的解決了在cam這篇論…

java多線程(常用方法、實現方式、線程安全問題、生命周期、線程池)

多線程相關的三組概念 程序和進程 程序(program):一個固定的運行邏輯和數據的集合,是一個靜態的狀態,一般存儲在硬盤中。簡單來說就是我們編寫的代碼 進程(process):一個正在運行的…

Python 中的 queue 模塊隊列詳解;隊列如何使用——如何處理信息在多個線程間安全交換的多線程程序?

queue 模塊即隊列,特別適合處理信息在多個線程間安全交換的多線程程序中。下面我們對 queue 模塊進行一個詳細的使用介紹。 1 queue 模塊定義的類和異常 queue 模塊定義了以下四種不同類型的隊列,它們之間的區別在于數據入隊列之后出隊列的順序不同。 …

cmake編譯數據庫

在使用CMake進行編譯時,如果你想生成編譯數據庫,你可以定義CMAKE_EXPORT_COMPILE_COMMANDS選項。具體的命令如下: cmake -DCMAKE_EXPORT_COMPILE_COMMANDS1或者在CMakeLists.txt顯示的使能配置 set(CMAKE_EXPORT_COMPILE_COMMANDS ON)這將會…

游戲玩家升級不傷手之選,光威龍武系列超強性能

得益于國產存儲芯片的崛起,現在的內存條價格太香了。要放在前幾年,購買內存條時都會優先考慮國際一線品牌。隨著內存條行業發生巨變,國產品牌光威GLOWAY,是全球前三的內存模組廠商嘉合勁威旗下品牌,它推出的內存條產品…

Zebec 推出由 Visa、萬事達網絡支持的即時支付卡,加密支付新征程

“Zebec現已推出全新的加密支付卡,該卡由Visa、萬事達網絡支持,具備即時、多鏈、非托管、無需KYC、免費等特性,其能夠通過加密錢包與多條主流公鏈鏈接并直接調用支付,這將是加密支付領域的里程碑事件。” 在2023年的12月8日&#…

C++中的string容器的substr()函數

一、作用 用來截取某段字符串。 二、頭文件 #include<string> 三、參數與用法 形式&#xff1a;s.substr(pos, len) 第一個參數是想要截取的字符串初始位置&#xff0c;第二個參數是截取字符串長度。 直接來說&#xff0c;就是從s[pos]開始截一個長度為len的子串。…

【python交互界面】實現動態觀察圖像在給定HSV范圍的區域顯示

HSV顏色空間 與RGB顏色空間相比&#xff0c;HSV顏色空間更適合進行顏色分析和提取特定顏色的目標。在HSV空間中&#xff0c;顏色信息被分布在不同的通道上&#xff0c;使我們能夠更準確地定義顏色的范圍&#xff0c;并使用閾值操作輕松地分離出我們感興趣的區域部分。 HSV三個通…

二叉樹查找值為x的結點(C語言)

目錄 前言 查找值為x的結點 返回值為指針 返回值為布爾類型 整體代碼 前言 在二叉樹結點個數、葉子結點個數、樹的高度、第k層結點個數的計算&#xff08;C語言&#xff09;中&#xff0c;我們解決了關于二叉樹的部分問題&#xff0c;但是還有一個問題我們放在本篇解決。 …

數據集成和人工智能驅動的見解

數字時代使數據成為人們關注的焦點&#xff0c;將其從單純的二進制序列轉變為有價值的組織資產。隨著企業越來越多地轉向數據驅動戰略&#xff0c;數據管理的復雜性也隨之增加。當前的任務不僅僅是存儲甚至收集數據&#xff0c;而是將其轉化為可操作的情報。本博客旨在剖析尋求…

Python中的selenium安裝的步驟(瀏覽器自動化測試框架)

一、前言 我們今天要安裝的selenium 就是瀏覽器自動化測試框架&#xff0c;是一個用于Web應用程序的測試工具&#xff0c;就是模擬用戶操作。支持的瀏覽器包括Chrome&#xff0c;IE&#xff0c;Mozilla Firefox&#xff0c;Safari&#xff0c;Opera等。今天我們以Chrome為例講…

STM32單片機項目實例:基于TouchGFX的智能手表設計(2)UI交互邏輯的設計

STM32單片機項目實例&#xff1a;基于TouchGFX的智能手表設計&#xff08;2&#xff09;UI交互邏輯的設計 目錄 一、UI交互邏輯的設計 1.1 硬件平臺的資源 1.2 界面切換功能 ???????1.3 表盤界面 1.4 運動界面 ???????1.6 設置界面 ???????1.7 應…

不一樣的年會彩瞳推薦,綺芙莉多款彩瞳彰顯個性

臨近年底&#xff0c;各種公司年會、跨年晚會活動也逐漸排上日程&#xff0c;出席這種正式場合&#xff0c;每個人都有自己的“殺手锏”&#xff0c;從發型妝容到穿搭都是變美小細節&#xff0c;作為心靈之窗的雙眸&#xff0c;更需要一副彩瞳來提升我們的眼妝質感&#xff0c;…

微前端 ---- wujie-vue3 原理

目錄 前言 設置子應用? 預加載? 啟動子應用? 封裝 1.創建文件 2.安裝依賴 3.編寫組件 4.配置打包規則 5.執行打包命令 swc技術 SWC Babel Babel VS SWC 更改使用 swc 解析 使用swc 完成 esm 模式 &#xff08;export--import&#xff09; 發布到npm 更改p…

【SpringBoot】解析Springboot事件機制,事件發布和監聽

解析Springboot事件機制&#xff0c;事件發布和監聽 一、Spring的事件是什么二、使用步驟2.1 依賴處理2.2 定義事件實體類2.3 定義事件監聽類2.4 事件發布 三、異步調用3.1 啟用異步調用3.2 監聽器方法上添加 Async 注解 一、Spring的事件是什么 Spring的事件監聽&#xff08;…

持續集成交付CICD:使用Jenkins插件上傳Nexus制品

目錄 一、實驗 1.使用Jenkins插件上傳Nexus制品 一、實驗 1.使用Jenkins插件上傳Nexus制品 &#xff08;1&#xff09;Jenkins安裝插件Nexus Artifact Uploader &#xff08;2&#xff09;添加憑據 &#xff08;3&#xff09;使用片段生成器生成DSL &#xff08;4&#xf…

基于Java物業管理系統

基于Java物業管理系統 功能需求 1、房產信息管理&#xff1a;系統需要提供房產信息管理功能&#xff0c;包括房產的基本信息、租賃狀態、業主信息等。 2、報修管理&#xff1a;系統需要提供報修管理功能&#xff0c;業主可以通過系統提交報修申請&#xff0c;物業管理人員可…

docke網絡之bridge、host、none

一、bridge網絡 1.創建一個測試容器 [rootlocalhost ~]# docker run -d -it --name busybox_1 busybox /bin/sh -c "while true;do sleep 3600;done" 03b308c847edd23f21ba69afb825d92f7aaeb05b1ff4431dd47ccee439a0361a 2.查看當前機器docker有哪些網絡 [rootlocal…

C++ 訪問限定符

目錄 訪問修飾符概述 protected在類的內部和派生類中訪問調用 private在類的內部訪問和調用 訪問修飾符概述 在C中&#xff0c;有三個主要的訪問修飾符&#xff1a;public、private和protected。這些修飾符用于控制類的成員&#xff08;變量和函數&#xff09;的訪問權限。…

2023年9月8日 Go生態洞察:gopls的擴展與Go生態系統的成長

&#x1f337;&#x1f341; 博主貓頭虎&#xff08;&#x1f405;&#x1f43e;&#xff09;帶您 Go to New World?&#x1f341; &#x1f984; 博客首頁——&#x1f405;&#x1f43e;貓頭虎的博客&#x1f390; &#x1f433; 《面試題大全專欄》 &#x1f995; 文章圖文…