3D程序设计离不开各种坐标系统
2019獨角獸企業重金招聘Python工程師標準>>>
接觸3D程序設計,難免要認識各種坐標系統,并在各個系統之間進行轉換,直接使用程序代碼實現公式是個方法,然而3D的世界中經常運用矩陣運算,因此,認識齊次坐標也是必備的,因為,這不單只是數學,與程序代碼本身的效率也有很大的關系!
這是左手還是右手?
在3D世界中,最常運用的是直角坐標,然而卻有多種不同的表示方式,也就是X、Y、Z軸正方向會有各自不同的表示,軟件或鏈接庫可能采用不同系統,這是種困擾,然而木已成舟,開發者只能在運用鏈接庫之前,先分辨它們到底采用哪個系統,粗略來說,直角坐標系統可以分為兩種:左手坐標(Left-hand Coordinate)、右手坐標(Right-hand Coordinate)。
對于前者,把左手拿出來,姆指指向若符合X軸正方向,食指符合Y軸正方向,而掌心往上符合Z正方向的話,那么該系統是采用左手坐標,例如,WebGL裁剪空間(Clip Space)就是左手坐標系統;對于后者,就是把右手拿出來,姆指與食指對應X、Y軸后,看看掌心往上是不是符合Z軸正方向,如果是的話,就是采用右手坐標,例如glMatrix、Three.js就屬于這類右手坐標系統。如果你一開始設計3D對象時,是采用左手坐標,然而接下來想要套用glMatrix呢?表面上看來,右手坐標似乎只是將Z軸正方向反過來,對glMatrix是如此,然而對其他鏈接庫或軟件就不一定了。
例如,OpenSCAD、Blender是右手坐標,然而,它的X、Y是代表2D平面,Z代表高度,也就是說,同為右手坐標系統,還是要注意一下三個軸各自的意義為何;至于3D雕塑軟件的部份,似乎偏好左手坐標,例如:Sculptris、SculptGL,不過,它們的z軸正方向是朝上,而不是像WebGL裁剪空間的z軸代表深度。左手坐標或右手坐標的差別,會影響到坐標轉換時導證出來的公式結果,如果試圖結合兩種不同系統的鏈接庫,就必須自行實作轉換,不然繪制出來就會是錯誤的畫面。例如,一個右手系統的(x,y,z)要換成左手系統的話,并不是只有(x,y,-z)一種轉換方式,(?x,y,z)、(x,?y,z)、(?x,?y,z)、(?x,y,?z)、(x,?y,?z),也都是轉換為左手坐標的可能方式。
這是哪個空間?
剛開始接觸WebGL時,至少會接觸兩個空間:裁剪空間與屏幕空間(Screen Space)。對WebGL來說,屏幕指的就是Canvas,基本上,若頂點正確出現在裁剪空間中,WebGL會自動處理屏幕空間的繪制,不過,如果要處理像鼠標點選的問題時,就必須處理繪圖坐標至裁剪空間的轉換問題。要繪制的幾何對象是由一組頂點定義,雖然裁剪空間是左手坐標,然而這組頂點可以基于左手或右手坐標定義,也就是說頂點定義在一個獨立的對象空間(Object space),或說是局部空間(Local Space),這個空間有個獨立原點,頂點都是相對于該原點而定義。接著,我們會縮放、轉動、移動這些幾何對象,實際上這些轉換動作,是將這些對象中的頂點,轉換至世界空間(World Space)。也就是開發者建構的3D世界,在世界空間中可能有許多對象,然而可能只想繪制出某范圍內的對象,這就像是有個相機,世界很大,然而,只有相機內看到的范圍才會被繪制出來,這個范圍稱為觀察空間(View Space)。
開發者可能會用左、右、上、下,以及近面、遠面邊界,來定義觀察空間,而觀察空間會透過一些計算,對應至裁剪空間,這個過程稱為投影,常見的作法有正交投影或透視透影──正交投影不會創造出遠近感,然而,透視透影會因為視體(Viewing frustum)的視場角度(fov)等參數不同,呈現出不同的遠近感。簡單來說,從對象空間、世界空間、觀察空間一直到裁剪空間等,必須經過多個空間轉換,才能順利地繪制出想要的3D對象,這些轉換,說穿了,就是一連串的線性轉換數學公式,然而,透過矩陣運算的話會更好,因為這會牽涉到程序運算時的效率問題。
這是點還是向量?
若要透過矩陣運算來執行空間轉換,此時,就不得不接觸齊次坐標(Homogeneous coordinate)。多半的說詞是,齊次坐標在進行仿射轉換(Affine Transformation)時很方便,像是混合縮放、轉動、移動等操作的轉換時計算方便,不過,實際上,齊次坐標還可以用來區別點與向量的差別。若單純只使用直角坐標,(a, b, c)會是代表什么呢?一個點?一個向量?誰知道!
使用齊次坐標的話,(a, b, c, 1)表示這是個點,而(a, b, c, 0)表示是個向量。至于為什么會這么定義,事實上,這會牽涉到一些線性代數的基礎,有興趣的話,我們可以看看〈Understanding of homogeneous coordinates〉(https://bit.ly/2KECitX)。齊次坐標用第四個分量來代表點,這表示直角坐標中的同一個點(Px, Py, Pz),與之對應的齊次坐標可以有無數個,也就是說(1, 2, 3, 1)、(2, 4, 6, 2)、(3, 6, 9, 3)等都代表著同一點(1, 2, 3),也就是說,對于齊次坐標中的點(Px, Py, Pz, w),對應的直角坐標點是(Px/w, Py/w, Pz/w)。
這就表示,當轉換公式涉及某分量的除法時,透過齊次坐標可以化為矩陣運算。例如,公式轉換中,若x'=near*x/z,y'=near*y/z,z'=z,就可以用齊次坐標[near * x, near * y, z, z]來表示;也就是說,計算用的矩陣若以列為主(row-major)撰寫的話,會是[near, 0, 0, 0, 0, near, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0]。一旦線性轉換公式可以化為矩陣運算,那么,就能將各種轉換予以組合,最后得到一個矩陣,也就是說,若打算進行縮放、旋轉、平移等n個轉換操作,對象是1,000個頂點,直接用函式實作個別轉換公式的話,必須進行n*1000的呼叫;相對地,如果使用一個結合了n個轉換的矩陣,就只需要1,000次計算,若轉換對象是圖像的像素的話,這樣的差異會更為驚人。
?
不是都有鏈接庫/框架嗎?
是的,3D程序設計也會有現成的鏈接庫或框架,來做這類的轉換操作,然而,別以為這樣,就可以輕松了事。最起碼,還是要先搞清楚它采用的坐標系統,以及相關的參數意義,最好的方式,是親自導證一次縮放、旋轉、平移、投影等矩陣等是怎么來的,這會讓開發者在轉換坐標系統時,更為得心應手。對齊次坐標與矩陣轉換有興趣的話,不妨可以看看〈Interactive guide to homogeneous coordinates〉,該文從程序人的角度,提供互動的方式,來協助你認識齊次坐標與矩陣轉換。別以為這只是數學,正如該文中所談到的:「認識選擇的框架背后的數學,寫出來的程序代碼才會有效率」。
轉載于:https://my.oschina.net/u/4024424/blog/3051735
總結
以上是生活随笔為你收集整理的3D程序设计离不开各种坐标系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Autosar Dcm模块之Vector
- 下一篇: 08-OS X系统中将control和c