卐 4-3D图形的数学
目錄
- Vectors(向量)
- Common Vector Operators(常用的向量操作)
- Dot Product(點(diǎn)積)
- Cross Product(叉積)
- Length of a Vector(向量的長度)
- Reflection and Refraction(反射和折射)
- Matrices(矩陣)
- Matrix Construction and Operators(矩陣的構(gòu)建與操作)
- Understanding Transformations(理解變換)
- Coordinate Spaces in OpenGL(OpenGL中的坐標(biāo)空間)
- Object Coordinates(對象坐標(biāo)系)
- World Coordinates(世界坐標(biāo)系)
- View Coordinates(視圖坐標(biāo)系)
- Clip and Normalized Device Space(裁剪與歸一化設(shè)備空間)
- Coordinate Transformations(坐標(biāo)轉(zhuǎn)換)
- The Identity Matrix(單位矩陣)
- The Translation Matrix(平移矩陣)
- The Rotation Matrix(旋轉(zhuǎn)矩陣)
- Euler Angles(歐拉角)
- The Scaling Matrix(縮放矩陣)
- Concatenating Transformations(串聯(lián)變換)
- Quaternions(四元數(shù))
- The Model-View Transform(模型-視圖變換)
- The Lookat Matrix(Lookat矩陣)
- Projection Transformations(投影變換)
- Perspective Matrices(透視矩陣)
- Orthographic Matrices(正交矩陣)
- Interpolation,Lines,Curves,and Splines(插值、直線、曲線和樣條曲線)
- Curves(曲線)
- Splines(樣條曲線)
- Summary(總結(jié))
Vectors(向量)
一個xyz三元組可以用一個向量來表示(事實(shí)上,對于數(shù)學(xué)上純粹的心來說,一個位置實(shí)際上也是一個向量)。當(dāng)涉及到操作三維幾何體時,向量可能是需要理解的最重要的基礎(chǔ)概念。這三個值(x、y和z)組合表示兩個重要值:方向和幅值。
向量是OpenGL操作的基礎(chǔ),因此各種大小的向量都是GLSL中的一級類型,并被命名為vec3和vec4(分別表示三元素向量和四元素向量)。向量可以表示的第二個量是大小。向量的大小是向量的長度。對于x軸向量(1, 0, 0),向量的長度是1。長度為1的向量稱為單位向量。如果一個向量不是一個單位向量,我們想把它縮放成一個,我們稱之為歸一化。對向量進(jìn)行歸一化會對其進(jìn)行縮放,使其長度變?yōu)?,然后稱該向量為歸一化向量。當(dāng)我們只想表示一個方向而不是一個大小時,單位向量很重要。
此外,如果向量長度出現(xiàn)在我們將要使用的方程中,當(dāng)這些長度為1時,它們會變得簡單得多!幅值也很重要;例如,它可以告訴我們在給定的方向上需要走多遠(yuǎn),我們需要離鱷魚多遠(yuǎn)。向量(和矩陣)是3D圖形中非常重要的概念,它們是GLSL語言(編寫著色器的語言)中的頭等公民。然而,在C++語言中,情況并非如此。為了允許你在C++程序中使用它們,vmath庫,它包含可以表示類似于它們的GLSL對應(yīng)的向量和矩陣的類。例如,vmath::vec3可以表示三分量浮點(diǎn)向量(x, y, z),vmath::vec4可以表示四分量浮點(diǎn)向量(x, y, z, w),依此類推。添加w坐標(biāo)以使向量齊次(homogeneous),但通常設(shè)置為1.0。稍后,x、y和z值可能會除以w,當(dāng)它為1.0時,實(shí)際上只剩下xyz值。vmath中的類實(shí)際上是具有類型定義的模板類,用于表示常見類型,例如單精度和雙精度浮點(diǎn)值以及有符號和無符號整數(shù)變量。
vmath::vec3與vmath::vec4的定義如下:
typedef Tvec3<float> vec3; typedef Tvec4<float> vec4;定義一個三元素向量簡單如下:
vmath::vec3 vVector;所有vmath類都定義了大量構(gòu)造函數(shù)和復(fù)制運(yùn)算符,這意味著您可以按如下方式聲明和初始化向量:
vec3 vmath::vVertex1(0.0f, 0.0f, 1.0f); vec4 vmath::vVertex2 = vec4(1.0f, 0.0f, 1.0f, 1.0f); vec4 vmath::vVertex3(vVertex1, 1.0f);vec3 vmath::vVerts[] = { vmath::vec3(-0.5f, 0.0f, 0.0f),vmath::vec3(0.5f, 0.0f, 0.0f),vmath::vec3(0.0f, 0.5f, 0.0f) };vmath庫還包括許多與數(shù)學(xué)相關(guān)的函數(shù),并覆蓋其類上的大多數(shù)運(yùn)算符,以允許向量和矩陣進(jìn)行加、減、乘、轉(zhuǎn)置等操作。
在這里我們需要小心,不要過分地掩飾第四個w分量。大多數(shù)情況下,當(dāng)您使用頂點(diǎn)位置指定幾何體時,只需存儲一個三分量頂點(diǎn)并將其發(fā)送到OpenGL即可。對于許多方向向量,例如曲面法線(垂直于用于照明計算的曲面的向量),三分量向量就足夠了。但是,我們將很快深入研究矩陣世界,要變換3D頂點(diǎn),必須將其乘以4×4變換矩陣。規(guī)則是你必須將一個四分量向量乘以一個4×4矩陣;如果你嘗試使用一個4×4矩陣的三分量向量,鱷魚會吃掉你!更多關(guān)于這一切意味著什么。本質(zhì)上,如果你要對向量做你自己的矩陣運(yùn)算,那么在很多情況下你可能需要四個分量向量。
Common Vector Operators(常用的向量操作)
向量的行為與加法、減法、一元求反等運(yùn)算的預(yù)期相同。這些運(yùn)算符執(zhí)行每個分量的計算,并生成與其輸入大小相同的向量。vmath向量類重載加法、減法和一元求反運(yùn)算符以及其他幾個運(yùn)算符,以提供此類功能。
vmath::vec3 a(1.0f, 2.0f, 3.0f); vmath::vec3 b(4.0f, 5.0f, 6.0f); vmath::vec3 c;c = a + b; c = a - b; c += b; c = -c;然而,在下面的小節(jié)中,從數(shù)學(xué)角度解釋了更多關(guān)于向量的操作。它們在vmath庫中也有實(shí)現(xiàn),下面將對其進(jìn)行概述。
Dot Product(點(diǎn)積)
設(shè)有兩向量V1(x1,y1,z1)和V2(x2,y2,z2),則有:
V1●V2 = |V1||V2|cosθ = x1x2 + y1y2 + z1z2
其中,θ是向量V1與V2的夾角。
一對單位向量之間的點(diǎn)積是一個值(介于?1.0和+1.0),表示它們之間夾角的余弦。一個稍微高級一點(diǎn)的函數(shù)vmath::angle實(shí)際上返回這個角度(弧度)。
float angle(const vmath::vec3& u, const vmath::vec3& v);Cross Product(叉積)
V1 × V2 = |V1||V2|sinθ×n = (y1z2 - z1y2, z1x2 - x1z2, x1y2 - y1x2)
其中,θ是向量V1與V2的夾角;n是一個單位向量,它的方向由V1和V2按右手定則產(chǎn)生(如下圖中V3)。
叉積的應(yīng)用很多,從尋找三角形的曲面法線到構(gòu)造變換矩陣。
Length of a Vector(向量的長度)
設(shè)有向量V(x, y, z),則它的長度為√(x2 + y2 + z2)。它的長度也等于√(V●V)。
vmath庫中也包含計算這個長度的函數(shù):
Reflection and Refraction(反射和折射)
上圖中,入射光線Rin,反射光線Rreflect,折射光線Rrefract。其中, η是折射因子。
反射光計算公式:Rreflect = Rin - (2N●Rin)N
折射光計算公式:
k = 1 - η2(1 - (N●R)2)
當(dāng)k<0時,Rrefract = 0;
當(dāng)k>=0時,Rrefract = ηR - (η(N●R) + √k)N
其中,R和N都是單位長度的向量。
vmath庫有兩個函數(shù)完成上述方程式,它們的源代碼如下:
template <typename T, const int len> static inline vecN<T,len> reflect(const vecN<T,len>& I, const vecN<T,len>& N) {return I - 2 * dot(N, I) * N; }template <typename T, const int len> static inline vecN<T,len> refract(const vecN<T,len>& I, const vecN<T,S>& N, T eta) {T d = dot(N, I);T k = T(1) - eta * eta * (T(1) - d * d);if (k < 0.0)return vecN<T,N>(0);elsereturn eta * I - (eta * d + sqrt(k)) * N; }Matrices(矩陣)
如果在空間中有一個點(diǎn)由x、y和z坐標(biāo)表示,并且如果圍繞某個任意點(diǎn)和方向旋轉(zhuǎn)若干度,則需要知道該點(diǎn)的位置,就使用矩陣。為什么?因?yàn)樾碌膞坐標(biāo)不僅取決于舊的x坐標(biāo)和其他旋轉(zhuǎn)參數(shù),而且還取決于y和z坐標(biāo)是什么。變量和解之間的這種依賴關(guān)系正是矩陣擅長解決的問題。
我們可以把一些矩陣看作是列向量表。
矩陣可以相乘和相加,但也可以與向量和標(biāo)量值相乘。將一個點(diǎn)(由向量表示)乘以一個矩陣(表示變換)得到一個新的變換點(diǎn)(另一個向量)。矩陣變換實(shí)際上不太難理解,對矩陣變換的理解是許多3D任務(wù)的基礎(chǔ)。
vmath::mat2 m1;// 2×2 matrix vmath::mat3 m2;// 3×3 matrix vmath::mat4 m3;// 4×4 matrix與GLSL中一樣,vmath中的矩陣類定義了常見的運(yùn)算符,如加法、減法、一元求反、乘法和除法,以及構(gòu)造函數(shù)和關(guān)系運(yùn)算符。同樣,vmath中的矩陣類是使用模板構(gòu)建的,包括單精度和雙精度浮點(diǎn)以及有符號和無符號整數(shù)矩陣類型的類型定義。
Matrix Construction and Operators(矩陣的構(gòu)建與操作)
對于一個4×4矩陣,OpenGL不是用一個二維數(shù)組存儲矩陣的浮點(diǎn)值,而是用一個包含16個元素的一維數(shù)組表示。默認(rèn)OpenGL是以列為主(column-major or column-primary)布局的。也就是說,對于一個4×4矩陣,前4個元素代表矩陣的第一列,接下來的4個元素代表矩陣的第二列,以此類推。
GLfloat matrix[16];// Nice OpenGL-friendly matrix GLfloat matrix[4][4];// Not as convenient for OpenGL programmersOpenGL可以使用第二種變體,但第一種變體更有效。
下面的數(shù)組代表上圖的矩陣:
事實(shí)上,vmath庫在內(nèi)部將矩陣表示為它自己的向量類的數(shù)組,每個向量包含一列矩陣。
假設(shè)有矩陣A和B,以及向量V,則有:
A·(B·V) = (A·B)·V (矩陣乘法滿足結(jié)合律)
我們可以用我們喜歡的任何方式將變換序列組合在一起,因?yàn)榫仃嚦朔ㄊ窍嗦?lián)的,但是矩陣在乘法中出現(xiàn)的順序很重要,因?yàn)榫仃嚦朔ú粷M足交換律。
旋轉(zhuǎn)與平移執(zhí)行的先后順序?qū)ξ矬w的影響:
圖(a)中正方形先繞z軸相對于原點(diǎn)旋轉(zhuǎn)θ角,然后沿著旋轉(zhuǎn)后的新x軸(即x1軸)平移,圖(b)中相同的正方形先沿x軸平移,然后繞z軸相對于新原點(diǎn)旋轉(zhuǎn)θ角。正方形的最終位置不同是因?yàn)?strong>每次變換都是相對于最后一次執(zhí)行的變換執(zhí)行的。在圖(a)中,正方形首先相對于原點(diǎn)旋轉(zhuǎn)。在圖(b)中,正方形平移后,圍繞新平移的原點(diǎn)進(jìn)行旋轉(zhuǎn)。
Understanding Transformations(理解變換)
仔細(xì)想想,大多數(shù)3D圖形都不是真正的3D。我們使用3D概念和術(shù)語來描述事物的外觀;然后這些3D數(shù)據(jù)被“擠壓”到2D電腦屏幕上。我們稱之為將三維數(shù)據(jù)壓縮成二維數(shù)據(jù)投影的過程。每當(dāng)我們想要描述頂點(diǎn)處理期間發(fā)生的變換類型(正交(orthographic)或透視(perspective))時,我們都會提到投影(projection),但投影只是OpenGL中發(fā)生的變換類型之一。變換還允許旋轉(zhuǎn)對象;移動它們;甚至拉伸、收縮和扭曲它們。
Coordinate Spaces in OpenGL(OpenGL中的坐標(biāo)空間)
| Model space | Positions relative to a local origin.Also sometimes known as object space. |
| World space | Positions relative to a global origin(i.e.,their location within the world). |
| View space | Positions relative to the viewer.Also sometimes called camera or eye space. |
| Clip space | Positions of vertices after projection into a nonlinear homogeneous coordinate. |
| Normalized device coordinate(NDC) space | Vertex coordinates are said to be in NDC after their clip space coordinates have been divided by their own w component. |
| Window space | Positions of vertices in pixels, relative to the origin of the window. |
Object Coordinates(對象坐標(biāo)系)
大多數(shù)頂點(diǎn)數(shù)據(jù)通常在對象空間(object space)(也稱為模型空間(model space))中開始使用。在對象空間中,頂點(diǎn)的位置相對于局部原點(diǎn)進(jìn)行解釋。考慮一個宇宙飛船模型。模型的起源可能會在某個合乎邏輯的地方,比如飛行器的鼻尖、重心或飛行員可能坐的位置。在3D建模程序中,返回原點(diǎn)并充分縮小應(yīng)顯示整個宇宙飛船。模型的原點(diǎn)通常是可以旋轉(zhuǎn)模型以將其放置到新方向的點(diǎn)。將原點(diǎn)放置在遠(yuǎn)離模型的位置是沒有意義的,因?yàn)閲@該點(diǎn)旋轉(zhuǎn)對象將應(yīng)用顯著的平移和旋轉(zhuǎn)。
World Coordinates(世界坐標(biāo)系)
世界空間,它相對于固定的全局原點(diǎn)存儲坐標(biāo)的位置。繼續(xù)宇宙飛船的類比,這可能是一個運(yùn)動場或其他固定物體的中心,如附近的行星。一旦進(jìn)入世界空間,所有對象都存在于一個公共框架中。通常,這是執(zhí)行照明和物理計算的空間。
View Coordinates(視圖坐標(biāo)系)
本章中的一個重要概念是視圖坐標(biāo),通常也稱為相機(jī)(camera)或眼睛(eye)坐標(biāo)。視圖坐標(biāo)相對于觀察者的位置(因此稱為“相機(jī)”和“眼睛”),而不考慮可能發(fā)生的任何變換;你可以將它們視為“絕對”坐標(biāo)。因此,眼睛坐標(biāo)表示一個虛擬的固定坐標(biāo)系,用作公共參考系。下圖顯示了兩個視點(diǎn)的視圖坐標(biāo)系。在左側(cè),視圖坐標(biāo)表示為場景的觀察者所看到的坐標(biāo)(即,垂直于監(jiān)視器)。在右側(cè),視圖坐標(biāo)系稍微旋轉(zhuǎn),以便更好地查看z軸的關(guān)系。從觀察者的角度來看,正x和y分別指向右側(cè)和上方。正z值從原點(diǎn)向用戶移動,負(fù)z值從視點(diǎn)向屏幕移動。屏幕位于z坐標(biāo)0處。
使用OpenGL在3D空間繪制時,使用笛卡爾坐標(biāo)系。在沒有任何變換的情況下,使用剛才描述的眼睛坐標(biāo)系(eye coordinate system)。
Clip and Normalized Device Space(裁剪與歸一化設(shè)備空間)
裁剪空間是OpenGL執(zhí)行裁剪的坐標(biāo)空間。當(dāng)頂點(diǎn)著色器寫入gl_Position時,該坐標(biāo)被視為在裁剪空間(clip space)中。這始終是一個四維齊次坐標(biāo)(four-dimensional homogenous coordinate)。退出剪輯空間后,頂點(diǎn)的所有四個組件將被w分量相除。顯然,在此之后,w等于1.0。如果在此除法之前w不是1.0,則x、y和z分量將通過w的倒數(shù)進(jìn)行有效縮放。這允許透視縮短和投影等效果。將除法結(jié)果視為在歸一化設(shè)備坐標(biāo)空間(NDC空間)中。顯然,如果裁剪空間坐標(biāo)的結(jié)果w分量為1.0,則裁剪空間和NDC空間將變得相同。
Coordinate Transformations(坐標(biāo)轉(zhuǎn)換)
如前所述,通過將坐標(biāo)的向量表示乘以變換矩陣,可以將坐標(biāo)從一個空間移動到另一個空間。變換用于操縱模型及其內(nèi)的特定對象。這些變換將對象進(jìn)行移動、旋轉(zhuǎn)和縮放。上圖說明了將應(yīng)用于對象的三種最常見的建模轉(zhuǎn)換。圖(a)顯示了平移,其中對象沿給定軸移動。圖(b)顯示了一個旋轉(zhuǎn),一個對象圍繞其中一個軸旋轉(zhuǎn)。最后,圖?顯示了縮放的效果,對象的尺寸增加或減少了指定的量。縮放可以不均勻地進(jìn)行(不同的尺寸可以按不同的量進(jìn)行縮放),因此可以使用縮放來拉伸和收縮對象。
這些標(biāo)準(zhǔn)變換中的每一個都可以表示為一個矩陣,你可以通過該矩陣乘以頂點(diǎn)坐標(biāo)來計算變換后的位置。接下來小節(jié)討論這些矩陣的構(gòu)造,包括數(shù)學(xué)構(gòu)造和使用vmath庫中提供的函數(shù)。
The Identity Matrix(單位矩陣)
單位矩陣除斜對角線為1其余都為0。所有的單位矩陣都是平方的,如4×4。將頂點(diǎn)乘以單位矩陣等于將其乘以1。所有單位矩陣都是它本身的轉(zhuǎn)置矩陣。
可以這樣構(gòu)建單位矩陣:
// Using a raw array: GLfloat m1[] = { 1.0f, 0.0f, 0.0f, 0.0f, // X Column0.0f, 1.0f, 0.0f, 0.0f, // Y Column0.0f, 0.0f, 1.0f, 0.0f, // Z Column0.0f, 0.0f, 0.0f, 1.0f };// W Column // Or using the vmath::mat4 constructor: vmath::mat4 m2 { vmath::vec4(1.0f, 0.0f, 0.0f, 0.0f), // X Columnvmath::vec4(0.0f, 1.0f, 0.0f, 0.0f), // Y Columnvmath::vec4(0.0f, 0.0f, 1.0f, 0.0f), // Z Columnvmath::vec4(0.0f, 0.0f, 0.0f, 1.0f) };// W Column // use vmath library functions vmath::mat2 m2 = vmath::mat2::identity(); vmath::mat3 m3 = vmath::mat3::identity(); vmath::mat4 m4 = vmath::mat4::identity();The Translation Matrix(平移矩陣)
實(shí)際上,位置向量幾乎總是使用四個分量編碼,其中w分量為1.0,而方向向量要么簡單地使用三個分量編碼,要么使用四個分量編碼,其中w為0。因此,將四分量方向向量乘以平移矩陣根本不會改變它。
vmath庫包含兩個函數(shù),它們將使用三個單獨(dú)的組件或三維向量為您構(gòu)建4×4轉(zhuǎn)換矩陣:
The Rotation Matrix(旋轉(zhuǎn)矩陣)
可以將這三個矩陣相乘生成一個復(fù)合變換矩陣,然后在單個矩陣-向量相乘運(yùn)算中圍繞三個軸中的每個軸旋轉(zhuǎn)給定的量。
注意angle的單位是度數(shù)而非弧度。此函數(shù)在內(nèi)部將度轉(zhuǎn)換為弧度,因?yàn)榕c計算機(jī)不同,許多程序員更喜歡用度來思考。
Euler Angles(歐拉角)
歐拉角是一組表示空間方向的三個角。每個角度表示圍繞定義幀的三個正交向量之一的旋轉(zhuǎn)(例如,x、y和z軸)。如前所述,矩陣變換的執(zhí)行順序很重要,因?yàn)橐圆煌捻樞驁?zhí)行某些變換(如旋轉(zhuǎn))將產(chǎn)生不同的結(jié)果。這是由于矩陣乘法的非交換性質(zhì)(non-commutative nature)。
設(shè)定xyz-軸為參考系的參考軸。稱xy-平面與XY-平面的相交為交點(diǎn)線,用英文字母(N)代表。zxz順規(guī)的歐拉角可以靜態(tài)地這樣定義:
α 是x-軸與交點(diǎn)線的夾角,β 是z-軸與Z-軸的夾角,γ 是交點(diǎn)線與X-軸的夾角。
繞X軸旋轉(zhuǎn):
繞Y軸旋轉(zhuǎn):
繞Z軸旋轉(zhuǎn):
將方向表示為一組三個角度有一些優(yōu)點(diǎn)。例如,這種類型的表示相當(dāng)直觀,如果你計劃將角度連接到用戶界面,這一點(diǎn)很重要。另一個好處是,插值角度、在每個點(diǎn)構(gòu)造旋轉(zhuǎn)矩陣以及在最終動畫中看到平滑一致的運(yùn)動非常簡單。
然而,歐拉角也有一個嚴(yán)重的陷阱——萬向鎖(gimbal lock)。
當(dāng)旋轉(zhuǎn)一個角度使一個軸重新定向以與另一個軸對齊時,會發(fā)生萬向節(jié)鎖定。任何圍繞兩個現(xiàn)在共線的軸的進(jìn)一步旋轉(zhuǎn)都將導(dǎo)致模型的相同變換,從而從系統(tǒng)中移除自由度。因此,歐拉角不適合串聯(lián)變換或累積旋轉(zhuǎn)。
為了避免這種情況,我們的vmath::rotate函數(shù)能夠獲取旋轉(zhuǎn)角度和旋轉(zhuǎn)軸。當(dāng)然,將三個旋轉(zhuǎn)疊加在一起(x、y和z軸各一個)可以在必要時使用歐拉角,但最好使用角度軸表示旋轉(zhuǎn),或使用四元數(shù)表示變換并根據(jù)需要將其轉(zhuǎn)換為矩陣。
The Scaling Matrix(縮放矩陣)
縮放變換通過按指定的因子沿三個軸擴(kuò)展或收縮所有頂點(diǎn)來更改對象的大小。
例如,一個10×10×10立方體在x和z軸方向上綻放,如下圖:
Concatenating Transformations(串聯(lián)變換)
正如您所了解的,坐標(biāo)變換可以用矩陣表示,向量從一個空間到另一個空間的變換涉及一個簡單的矩陣-向量乘運(yùn)算。乘以一系列矩陣可以應(yīng)用一系列變換。在每次矩陣-向量相乘之后,不必存儲中間向量。相反,首先將構(gòu)成一組相關(guān)變換的所有矩陣相乘,生成一個表示整個變換序列的矩陣是可能的,并且通常更可取。然后,可以使用該矩陣將向量直接從源坐標(biāo)空間轉(zhuǎn)換到目標(biāo)坐標(biāo)空間。記住,順序很重要。使用vmath或GLSL編寫代碼時,應(yīng)始終將矩陣與向量相乘,并按倒序讀取變換序列。例如,考慮下面的代碼序列:
vmath::mat4 translation_matrix = vmath::translate(4.0f, 10.0f, -20.0f); vmath::mat4 rotation_matrix = vmath::rotate(45.0f, vmath::vec3(0.0f, 1.0f, 0.0f)); vmath::vec4 input_vertex = vmath::mat4(....); vmath::vec4 transformed_vertex = translation_matrix * rotation_matrix * input_vertex;該代碼首先將模型繞y軸旋轉(zhuǎn)45°,然后將其在x軸上平移4個單位,在y軸上平移10個單位,在z軸上平移負(fù)20個單位。這會將模型放置在特定方向,然后將其移動到位。是先旋轉(zhuǎn),后平移。我們可以將此代碼重寫如下:
vmath::mat4 translation_matrix = vmath::translate(4.0f, 10.0f, -20.0f);vmath::mat4 rotation_matrix = vmath::rotate(45.0f, vmath::vec3(0.0f, 1.0f, 0.0f));vmath::mat4 composite_matrix = translation_matrix * rotation_matrix;vmath::vec4 input_vertex = vmath::vec4(...);vmath::vec4 transformed_vertex = composite_matrix * input_vertex;// 先旋轉(zhuǎn),再平移Quaternions(四元數(shù))
四元數(shù)是一種四維量,在某些方面類似于復(fù)數(shù)。它有一個實(shí)部和三個虛部(與復(fù)數(shù)的一個虛部相比)。正如復(fù)數(shù)有一個虛部i一樣,四元數(shù)有三個虛部i、j和k。數(shù)學(xué)上,四元數(shù)q表示為
q = (x + yi + zj + wk)
性質(zhì)?:i2 = j2 = k2 = ijk = -1。
性質(zhì)?:i = jk、j = ik、k = ji。
與復(fù)數(shù)一樣,四元數(shù)的乘法是非交換的。四元數(shù)的加法和減法定義為簡單的矢量加減法,各項按分量進(jìn)行加減。其他函數(shù)(如一元否定和幅值)的行為也與四分量向量的預(yù)期相同。雖然四元數(shù)是一個四分量實(shí)體,但通常將四元數(shù)表示為實(shí)標(biāo)量部分和三分量虛矢量部分。這種表述通常書面寫作:q = (r, v)。
好的,很好,但這不是可怕的數(shù)學(xué)章節(jié),對嗎?這是關(guān)于計算機(jī)圖形、OpenGL和所有有趣的東西。這就是四元數(shù)真正有用的地方。回想一下,我們的旋轉(zhuǎn)函數(shù)以一個角度和一個軸為中心旋轉(zhuǎn)。
我們可以將這兩個量表示為四元數(shù),在實(shí)部填充角度,在向量部填充軸,得到一個表示繞任意軸旋轉(zhuǎn)的四元數(shù)。
旋轉(zhuǎn)序列可以由一系列四元數(shù)相乘表示,生成一個四元數(shù),一次編碼整個批次。雖然可以生成一組表示圍繞各個笛卡爾軸旋轉(zhuǎn)的矩陣,然后將它們相乘,這種方法容易受到萬向節(jié)鎖的影響。如果對一系列四元數(shù)執(zhí)行相同的操作,則萬向節(jié)鎖定不會發(fā)生。為了便于編寫代碼,vmath包括vmath::quaternion類,該類實(shí)現(xiàn)了這里描述的大部分功能。
The Model-View Transform(模型-視圖變換)
在一個簡單的OpenGL應(yīng)用程序中,最常見的轉(zhuǎn)換之一是將模型從模型空間(model space)轉(zhuǎn)換到視圖空間(view space),以便對其進(jìn)行渲染。實(shí)際上,我們首先將模型移動到世界空間(即相對于世界原點(diǎn)放置),然后再從那里移動到視圖空間(相對于觀察者放置)。這個過程確定了場景的有利位置。默認(rèn)情況下,透視投影中的觀察點(diǎn)位于原點(diǎn)(0,0,0),看向負(fù)z軸(進(jìn)入監(jiān)視器或屏幕)。該觀察點(diǎn)相對于眼睛坐標(biāo)系(eye coordinate system)移動,以提供特定的有利位置。當(dāng)觀察點(diǎn)位于原點(diǎn)時,如在透視投影中,使用正z值繪制的對象位于觀察者后面。然而,在正交投影中,假定觀察者在正z軸上無限遠(yuǎn),并且可以看到視體(viewing volume)內(nèi)的一切。
由于此變換將頂點(diǎn)從模型空間(有時也稱為對象空間)直接帶入視圖空間,并有效地繞過世界空間,因此通常稱為模型-視圖變換,對此變換進(jìn)行編碼的矩陣稱為模型-視圖矩陣。
模型變換實(shí)質(zhì)上是將對象放置到世界空間中。每個對象都可能有自己的模型變換,通常由一系列縮放、旋轉(zhuǎn)和平移操作組成。將模型空間中頂點(diǎn)的位置乘以模型變換的結(jié)果是世界空間中的一組位置。這種轉(zhuǎn)換有時被稱為模型-世界轉(zhuǎn)換(model-world transform)。
視圖轉(zhuǎn)換允許您將觀察點(diǎn)放置在任意位置,并朝任意方向觀察。確定查看變換類似于將攝影機(jī)放置并指向場景。在總體方案中,必須在任何其他建模轉(zhuǎn)換之前應(yīng)用視圖轉(zhuǎn)換。原因是它似乎相對于眼睛坐標(biāo)系移動了當(dāng)前工作坐標(biāo)系。然后,所有后續(xù)變換都基于新修改的坐標(biāo)系進(jìn)行。將坐標(biāo)從世界空間移動到視圖空間的變換有時稱為世界-視圖變換(world-view transform)。
通過將模型-世界和世界-視圖變換矩陣相乘,將它們連接在一起,得到模型-視圖矩陣(即,從模型到視圖空間獲取坐標(biāo)的矩陣)。這樣做有一些好處。首先,場景中可能有許多模型,每個模型中都有許多頂點(diǎn)。如前所述,使用單復(fù)合變換將模型移動到視圖空間比先將其移動到世界空間,然后再移動到視圖空間更有效。第二個優(yōu)勢更多地與單精度浮點(diǎn)數(shù)字的數(shù)值精度有關(guān):世界可能很大,在世界空間中執(zhí)行的計算將具有不同的精度,具體取決于頂點(diǎn)離世界原點(diǎn)的距離。但是,如果在視圖空間中執(zhí)行相同的計算,則精度取決于頂點(diǎn)離觀察者的距離,這可能是您想要的——對靠近觀察者的對象應(yīng)用了大量的精度,但犧牲了距離觀察者很遠(yuǎn)的精度。
The Lookat Matrix(Lookat矩陣)
如果你在一個已知的位置有一個有利的位置,并且你想看一個東西,你會希望把你的虛擬相機(jī)放在那個位置,然后把它指向正確的方向。要正確定位相機(jī),您還需要知道它向上的方向;否則,相機(jī)可能會繞著它的前向軸旋轉(zhuǎn),即使從技術(shù)上講它仍然指向正確的方向,這幾乎肯定不是你想要的。因此,給定一個原點(diǎn)、一個感興趣點(diǎn)和一個我們認(rèn)為要上升的方向,我們想要構(gòu)造一系列變換,理想地烘烤成一個矩陣,這將表示一個旋轉(zhuǎn),它將指向一個攝像機(jī)在正確的方向上,一個將原點(diǎn)移動到攝像機(jī)中心的平移。該矩陣稱為lookat矩陣(lookat matrix),可僅使用本章迄今為止所述的數(shù)學(xué)知識構(gòu)建。
首先,我們知兩個位置相減會得到一個向量,這個向量會將一個點(diǎn)從第一個位置移動到第二個位置,而對向量結(jié)果進(jìn)行歸一化會得到它的方向。因此,如果我們?nèi)∫粋€關(guān)注點(diǎn)的坐標(biāo),從中減去我們相機(jī)的位置,然后歸一化得到的向量,我們就有了一個新的向量,表示從相機(jī)到關(guān)注點(diǎn)的視角方向。我們稱之為前向向量(forward vector)。
接下來,我們知道,如果我們?nèi)蓚€向量的叉積,我們將得到與兩個輸入向量正交(成直角)的第三個向量。我們有兩個矢量,我們剛才計算的前向矢量(forward vector),和向上矢量(up vector),它代表我們認(rèn)為向上的方向。取這兩個向量的叉積,得到第三個向量,該向量與它們中的每一個向量正交,并且相對于我們的相機(jī)指向側(cè)面。我們稱之為側(cè)向向量(sideways vector)。然而,上方向向量和前方向向量不一定相互正交,我們需要第三個正交向量來構(gòu)造旋轉(zhuǎn)矩陣。為了得到這個向量,我們可以簡單地再次應(yīng)用相同的過程,取前向向量和側(cè)向向量的叉積,得到第三個向量,這第三個向量與前向向量和側(cè)向向量正交,表示相對于相機(jī)的上方向(up)。
這三個向量具有單位長度,并且彼此正交,因此它們形成一組正交基向量并表示我們的視圖框架。給定這三個向量,我們可以構(gòu)造一個旋轉(zhuǎn)矩陣,它將在標(biāo)準(zhǔn)笛卡爾基礎(chǔ)上取一個點(diǎn),并將其移動到相機(jī)的基礎(chǔ)上。在下面的數(shù)學(xué)中,e是眼睛(或相機(jī))的位置,p是關(guān)注點(diǎn),u是上方向向量。
首先,構(gòu)造我們的前向向量f:
f = (p - e) / |p - e|
然后,構(gòu)造側(cè)向向量s:
s = f×u
在相機(jī)參考中構(gòu)造一個新的上方向向量u′:
u′ = s×f
最后,構(gòu)造一個旋轉(zhuǎn)矩陣,表示重新定向到我們新構(gòu)造的正交基中:
要將對象轉(zhuǎn)換為攝影機(jī)的幀,不僅需要正確確定所有對象的方向,還需要將原點(diǎn)移動到攝影機(jī)的位置。我們通過簡單地將結(jié)果向量轉(zhuǎn)換為相機(jī)位置的負(fù)數(shù)來實(shí)現(xiàn)這一點(diǎn)。還記得平移矩陣是如何通過將偏移量放入矩陣最右邊的列中來構(gòu)造的嗎?我們也可以在這里這樣做:
終于,我們得到lookat矩陣,就是上面的矩陣T。
由vmath::lookat函數(shù)生成的矩陣可以用作相機(jī)矩陣的基礎(chǔ)——表示相機(jī)位置和方向的矩陣。換句話說,這可以是你的視圖矩陣。
Projection Transformations(投影變換)
投影變換將在模型-視圖變換后應(yīng)用于頂點(diǎn)。該投影實(shí)際上定義了視體并建立了剪裁平面。剪裁平面是三維空間中的平面方程,OpenGL使用它來確定觀察者是否可以看到幾何體。更具體地說,投影變換指定如何將完成的場景(完成所有建模后)投影到屏幕上的最終圖像。你將了解有關(guān)正交投影(orthographic)和透視投影(perspective)兩種類型的詳細(xì)信息。
在正交或平行投影中,所有多邊形都以指定的相對尺寸精確地繪制在屏幕上。直線和多邊形使用平行線直接映射到2D屏幕,這意味著無論某物離屏幕有多遠(yuǎn),它仍然繪制為相同大小,只是在屏幕上展平。這種類型的投影通常用于渲染二維圖像,如藍(lán)圖(blueprints)中的正面、頂部和側(cè)面立面,或二維圖形(如文本或屏幕菜單)。
透視投影顯示的場景更多的是真實(shí)生活中的場景,而不是藍(lán)圖。透視投影的特點(diǎn)是縮短(foreshortening),這使得遠(yuǎn)處的物體看起來比同樣大小的附近物體小。三維空間中可能平行的線并不總是與觀察者平行。例如,對于鐵路軌道,軌道是平行的,但使用透視投影,它們似乎在某個遙遠(yuǎn)的點(diǎn)會聚。透視投影的好處是,你不必知道直線在哪里會聚,也不必知道遠(yuǎn)處的物體有多小。您只需使用模型-視圖變換指定場景,然后應(yīng)用透視投影矩陣。線性代數(shù)為你帶來了所有的魔力。
下圖比較了兩個不同場景上的正交投影和透視投影。
正如你在左側(cè)顯示的正交投影中所看到的,立方體在遠(yuǎn)離查看器時,其大小似乎不會發(fā)生變化。然而,在右側(cè)顯示的透視投影中,立方體隨著距離觀察者越來越遠(yuǎn)而變得越來越小。
正交投影最常用于二維繪圖目的,其中需要像素和繪圖單位之間的精確對應(yīng)。您可以將它們用于原理圖布局、文本或二維圖形應(yīng)用程序。如果渲染深度與距視點(diǎn)的距離相比具有非常小的深度,則也可以使用正交投影進(jìn)行三維渲染。透視投影用于渲染包含需要應(yīng)用縮短的開闊空間或?qū)ο蟮膱鼍啊T诖蠖鄶?shù)情況下,透視投影是典型的三維圖形。事實(shí)上,用正交投影觀察3D對象可能會有點(diǎn)令人不安。
Perspective Matrices(透視矩陣)
一旦頂點(diǎn)在視圖空間中,我們需要將它們放入裁剪空間,我們可以通過應(yīng)用投影矩陣來實(shí)現(xiàn)這一點(diǎn),投影矩陣可以表示透視投影或正交投影(或其他投影)。常用的透視矩陣是平截頭體矩陣。平截頭體矩陣是一種投影矩陣,它生成透視投影,使得裁剪空間的形狀為矩形平截頭體,即截斷的矩形棱錐體。其參數(shù)是到近平面和遠(yuǎn)平面的距離以及左、右、上和下剪裁平面的世界空間坐標(biāo)。平截體矩陣采用以下形式:
構(gòu)造透視矩陣的另一種常用方法是直接將視野(field of view)指定為角度(FOV角)(可能以度為單位)、縱橫比(通常通過將窗口的寬度除以其高度得出)以及近平面和遠(yuǎn)平面的視圖空間位置。這在某種程度上更易于指定,并且只生成對稱的視錐(symmetric frustra)。然而,這幾乎總是你想要的。
static inline mat4 perspective(float fovy, float aspect, float n, float f) { ... }Orthographic Matrices(正交矩陣)
如果希望對場景使用正交投影,則可以構(gòu)造(稍微簡單一些的)正交投影矩陣。正交投影矩陣只是將視圖空間坐標(biāo)線性映射到裁剪空間坐標(biāo)的縮放矩陣。構(gòu)造正交投影矩陣的參數(shù)是場景邊界的視圖空間中的左、右、上和下坐標(biāo),以及近平面和遠(yuǎn)平面的位置。
Interpolation,Lines,Curves,and Splines(插值、直線、曲線和樣條曲線)
D = B - A
P = A + tD = A + t(B - A) = (1 - t)A + tB
如果t在0.0和1.0之間,那么P將在A和B之間結(jié)束。超出此范圍的t值會將P推離線的末端。你們應(yīng)該可以看到,通過平滑地改變t,我們可以將點(diǎn)P從A移到B,然后再移回來。這被稱為線性插值(linear iterpolation)。A和B(和P)的值可以有任意數(shù)量的維度。例如,它們可以是標(biāo)量值;二維值,如圖形上的點(diǎn);三維值,如三維空間中的坐標(biāo)、顏色等;或者更高維度的數(shù)量,例如矩陣、數(shù)組,甚至整個圖像。在許多情況下,線性插值沒有多大意義(例如,兩個矩陣之間的線性插值通常不會產(chǎn)生有意義的結(jié)果),但角度、位置和其他坐標(biāo)通常可以安全地插值。
線性插值是圖形中的一種常見操作,GLSL包括一個專門用于此目的的內(nèi)置函數(shù),mix:
vec4 mix(vec4 A, vec4 B, float t);mix函數(shù)有幾個版本,將向量或標(biāo)量的不同維數(shù)作為A和B輸入,并將標(biāo)量或匹配向量作為t輸入。
Curves(曲線)
如果我們只想沿著兩點(diǎn)之間的直線移動所有東西,那么這就足夠了。但是,在現(xiàn)實(shí)世界中,對象以平滑曲線移動,并平滑地加速和減速。曲線可以由三個或更多控制點(diǎn)表示。對于大多數(shù)曲線,有三個以上的控制點(diǎn),其中兩個形成端點(diǎn);其他定義了曲線的形狀。考慮下圖所示的簡單曲線。
有三個控制點(diǎn)A、B、C,其中A和C是曲線的端點(diǎn),B定義了曲線的形狀。如果我們將點(diǎn)A和點(diǎn)B與一條直線連接起來,將點(diǎn)B和點(diǎn)C與另一條直線連接起來,那么我們可以使用簡單的線性插值沿這兩條直線進(jìn)行插值,以找到一對新的點(diǎn)D和E。現(xiàn)在,給定這兩點(diǎn),我們可以用另一條線把它們連接起來,沿著它插值,找到一個新的點(diǎn),P。當(dāng)我們改變插值參數(shù)t時,點(diǎn)P將沿著從A到D的平滑曲線路徑移動。用數(shù)學(xué)表示:
D = A + t(B - A)
E = B + t(C - B)
P = D + t(E - D)
= A + t(B ? A)+ t((B +(t(C ? B))) ? (A + t(B ? A))))
= A +2t(B ? A)+ t2(C ? 2B + A)
你應(yīng)該認(rèn)識到這是t中的二次方程(quadratic equation)。它描述的曲線稱為二次Bézier曲線。實(shí)際上,我們可以使用mix函數(shù)在GLSL中非常容易地實(shí)現(xiàn)這一點(diǎn),因?yàn)槲覀兯龅闹皇菍η懊鎯纱尾逯档慕Y(jié)果進(jìn)行線性插值(混合)。
通過添加第四個控制點(diǎn),如下圖所示,我們可以將階數(shù)增加1,并生成三次Bézier曲線。
我們現(xiàn)在有四個控制點(diǎn),A、B、C和D。構(gòu)造曲線的過程類似于二次Bézier曲線。我們從A到B形成第一條線,從B到C形成第二條線,從C到D形成第三條線。沿這三條直線中的每一條進(jìn)行插值會產(chǎn)生三個新點(diǎn),即E、F和G。利用這三個點(diǎn),我們再形成兩條線,一條從E到F,另一條從F到G,沿著這兩條線插值,得到點(diǎn)H和點(diǎn)I,在這兩條線之間我們可以插值找到我們的最終點(diǎn)P。
因此,我們有:
E = A + t(B - A)
F = B + t(C - B)
G = C + t(D - C)
H = E + t(F - E)
I = F + t(G - F)
P = H + t(I - H)
如果你認(rèn)為這些方程看起來很熟悉,你是對的:我們的點(diǎn)E,F和G形成了一條二次Bézier曲線,我們用它來插值到我們的最終點(diǎn)P。如果我們將E、F和G的方程代入H和I的方程中,然后代入P的方程中,通過展開式,我們將得到一個三次方程,其項包含在t3——因此被稱為三次Bézier曲線。同樣,我們可以通過使用混合函數(shù)在GLSL中進(jìn)行線性插值來簡單有效地實(shí)現(xiàn)這一點(diǎn):
正如三次Bézier曲線方程的結(jié)構(gòu)“包括”二次曲線方程一樣,實(shí)現(xiàn)它們的代碼也是如此。事實(shí)上,我們可以將這些曲線層疊在一起,使用一條曲線的代碼構(gòu)建下一條曲線。
vec4 cubic_bezier(vec4 A, vec4 B, vec4 C, vec4 D, float t) {vec4 E = mix(A, B, t); // E = A + t(B - A)vec4 F = mix(B, C, t); // F = B + t(C - B)vec4 G = mix(C, D, t); // G = C + t(D - C)return quadratic_bezier(E, F, G, t); }現(xiàn)在,我們看到了這個模式,我們可以更進(jìn)一步,產(chǎn)生更高階的曲線。例如,五次Bézier曲線(一條有五個控制點(diǎn))可以實(shí)現(xiàn)為:
vec4 quintic_bezier(vec4 A, vec4 B, vec4 C, vec4 D, vec4 E, float t) {vec4 F = mix(A, B, t); // F = A + t(B - A)vec4 G = mix(B, C, t); // G = B + t(C - B)vec4 H = mix(C, D, t); // H = C + t(D - C)vec4 I = mix(D, E, t); // I = D + t(E - D)return cubic_bezier(F, G, H, I, t); }理論上,這種分層可以反復(fù)應(yīng)用于任何數(shù)量的控制點(diǎn)。但是,在實(shí)踐中,通常不使用具有四個以上控制點(diǎn)的曲線。相反,我們使用樣條曲線。
Splines(樣條曲線)
樣條曲線實(shí)際上是由幾個較小的曲線(如Bézier曲線)組成的長曲線,這些曲線局部定義了它們的形狀。至少表示曲線端點(diǎn)的控制點(diǎn)在線段之間共享,并且通常一個或多個內(nèi)部控制點(diǎn)在相鄰線段之間以某種方式共享或鏈接。任何數(shù)量的曲線都可以通過這種方式連接在一起,從而形成任意長的路徑。
這就是將曲線粘在一起形成樣條曲線的原因。這些控制點(diǎn)稱為焊縫(welds),中間的控制點(diǎn)稱為節(jié)點(diǎn)(knots)。
在上圖中,曲線由十個控制點(diǎn)A到J定義,它們形成三條三次Bézier曲線。第一個由A、B、C和D定義,第二個共享D并進(jìn)一步使用E、F和G,第三個共享G并添加H、I和J。這種樣條曲線稱為三次Bézier樣條曲線,因?yàn)樗怯梢幌盗腥蜝ézier曲線構(gòu)成的。這也被稱為三次B樣條(B-spline)——這一術(shù)語對于過去閱讀過大量圖形知識的人來說可能很熟悉。
要沿樣條曲線插值點(diǎn)P,我們只需將其劃分為三個區(qū)域,使t的范圍從0.0到3.0。在0.0和1.0之間,我們沿著第一條曲線插值,從A移動到D。在1.0和2.0之間,我們沿著第二條曲線插值,從D移動到G。當(dāng)t在2.0和3.0之間時,我們沿著G和J之間的最終曲線進(jìn)行插值。因此,t的整數(shù)部分決定了我們要沿其插值的曲線段,而t的分?jǐn)?shù)部分用于沿該段插值。當(dāng)然,我們可以隨心所欲地擴(kuò)展t。例如,如果我們?nèi)∫粋€介于0.0和1.0之間的值,并將其乘以曲線中的分段數(shù),則無論曲線中控制點(diǎn)的數(shù)量如何,我們都可以繼續(xù)使用t的原始值范圍。
下面的代碼將沿三次Bézier樣條插值一個向量,該樣條具有十個控制點(diǎn)(以及三個線段):
如果我們使用樣條曲線來確定對象的位置或方向,我們會發(fā)現(xiàn)我們必須非常小心地選擇控制點(diǎn)位置,以保持運(yùn)動平滑和流暢。插值點(diǎn)P值的變化率(即其速度)是曲線方程相對于t的微分。如果這個函數(shù)是不連續(xù)的,那么P會突然改變方向,我們的物體會出現(xiàn)跳躍。此外,P的速度(加速度)的變化率是樣條方程相對于t的二階導(dǎo)數(shù)。如果加速不平穩(wěn),則P會突然加速或減速。
具有連續(xù)一階導(dǎo)數(shù)的函數(shù)稱為C1連續(xù)函數(shù);類似地,具有連續(xù)二階導(dǎo)數(shù)的曲線稱為C2連續(xù)曲線。Bézier曲線段都是C1和C2連續(xù)的,但為了確保在樣條曲線的焊縫上保持連續(xù)性,我們需要確保每個段從前一段在位置、移動方向和變化率方面結(jié)束的位置開始。在特定方向上的移動速率就是一個速度。因此,我們可以在每個焊縫處指定速度,而不是為樣條曲線指定任意控制點(diǎn)。如果在計算該焊縫任一側(cè)的曲線段時,在每個焊縫處使用相同的曲線速度,則我們將使用C1和C2連續(xù)的樣條函數(shù)。
如果您再看一看上圖,這應(yīng)該是有意義的——沒有扭結(jié)(kinks),曲線通過焊縫(點(diǎn)D和點(diǎn)G)平滑。現(xiàn)在查看焊縫兩側(cè)的控制點(diǎn)。例如,以圍繞D的點(diǎn)C和點(diǎn)E為例。C和E形成一條直線,D正好位于中間。事實(shí)上,我們可以把從D到E的線段稱為D處的速度,或者VD。
給定點(diǎn)D(焊縫)的位置和曲線在D處的速度VD,則C和E可計算為:
C = D - VD
E = D + VD
同樣,如果**VA**表示A處的速度,則B可計算為:
B = A + VA
因此,您應(yīng)該能夠看到,給定三次B樣條曲線焊縫處的位置和速度,我們可以省去所有其他控制點(diǎn),并在評估每個控制點(diǎn)時動態(tài)計算它們。以這種方式表示的三次B樣條(作為一組焊接位置和速度)稱為三次Hermite樣條(cube Hermite spline),有時簡稱為CSP線。cspline是制作平滑自然動畫的非常有用的工具。
Summary(總結(jié))
在本章中,你學(xué)習(xí)了一些對使用OpenGL創(chuàng)建3D場景至關(guān)重要的數(shù)學(xué)概念。即使你不能在頭腦中處理矩陣,你現(xiàn)在也知道什么是矩陣,以及如何使用它們來執(zhí)行各種變換。你還學(xué)習(xí)了如何構(gòu)造和操作表示觀察者和視口屬性的矩陣。現(xiàn)在,你應(yīng)該了解如何將對象放置在場景中,并確定如何在屏幕上查看它們。本章還介紹了參考系的強(qiáng)大概念,你看到了操作參考系并將其轉(zhuǎn)換是多么容易。
最后,我們介紹了本書附帶的vmath庫的使用。這個庫完全是用便攜式C++編寫的,它提供了一個方便的工具箱,可以與OpenGL一起使用各種數(shù)學(xué)和輔助程序。
令人驚訝的是,在這整章中,我們沒有涉及一個新的OpenGL函數(shù)調(diào)用。是的,這是數(shù)學(xué)章節(jié),如果你認(rèn)為數(shù)學(xué)只是公式和計算,你可能根本沒有注意到。向量和矩陣及其應(yīng)用對于能夠使用OpenGL渲染3D對象和世界至關(guān)重要。然而,需要注意的是,OpenGL并沒有將任何特定的數(shù)學(xué)約定強(qiáng)加給你,并且本身也不提供任何數(shù)學(xué)功能。如果你使用不同的三維數(shù)學(xué)庫,或者甚至使用自己的三維數(shù)學(xué)庫,你仍然會發(fā)現(xiàn)自己遵循本章中列出的模式來操作幾何體和三維世界。
總結(jié)
以上是生活随笔為你收集整理的卐 4-3D图形的数学的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU4324 - Triangle L
- 下一篇: WPS格式文件转图片格式如何进行操作