向量
首先我們了解一下標量和向量的區(qū)別:
標量:只有大小的量,如帆疟,1鹉究、3、5鸯匹;
向量:有方向的標量坊饶;
在 3D 笛卡爾坐標系, 基本上. 一個頂點 就是XYZ 坐標空間上的?個位置. ?在空間中給定的
?個位置 恰恰是由一個單獨的 XYZ 定義的. 而這這樣的 XYZ 就是向量;
單位向量
向量?度為1. 我們稱為長度為1的向量為單位向量.如、在X軸上的向量量 (1,0,0)殴蓬。
向量長度(向量的模)計算公式:
如果?個向量不是單位向量, 而我們把它縮放到 1. 這個過程叫做標準化. 將?個向量進行標準化就是將它的縮為1; 也叫做單位化向量匿级,即非零向量除以向量的模,如下圖所示;
OPenGl定義向量[ math3d 庫]
在OpenGL中提供了一個數(shù)學庫類 #include<math3d.h>
我們會兩個比較常見的類:
- M3DVector3f:表示三維向量(x,y,z)-(f)表示float類型的意思染厅。
同時也可以用來設(shè)置三維數(shù)組也是沒有問題的
typedef float M3DVector3f[3]; // Vector of three floats (x, y, z) 默認是一個一維數(shù)組
- M3DVector4f:表示四維向量(x,y,z,w)w表示縮放因子w默認為1.0-(f)同上
我們也可以用M3DVector4f來表示顏色值的設(shè)置
M3DVector4f color[] = {1.0f, 1.0f, 0.0f, 1.0f};
向量點乘
向量可以進?加法,減法計算. 但是向量里有?個在開發(fā)中使?價值非常高的操作,叫做
“點乘(dot product)” .點乘只能發(fā)生在2個向量之間進行;
2個(三維向量)單元向量之間進?點乘運算將得到?個標量(不是三維向量,是?個標量).
它表示兩個向量之間的夾?;
前提條件: 2個向量必須為單位向量;
動作: 2個三維向量之間進?點乘;
結(jié)果: 返回?個[-1,1]范圍的值. 這個值其實就是夾角的cos值(余弦值);
那么在代碼中如何實現(xiàn)點乘呢痘绎?2個向量相乘
//1.m3dDotProduct3 函數(shù)獲得2個向量量之間的點乘結(jié)果;
m3dDotProduct3(const M3DVector3f u, const M3DVector3f v)
根據(jù)兩個向量獲取角度值
float m3dGetAngleBetweenVectors3(const M3DVector3f u, const M3DVector3f v)
向量叉乘
向量之間的叉乘(cross product) 也是在業(yè)務(wù)開發(fā)里?常有?的?個計算方式; 2個向量之間叉乘就可以得到另外?個向量,新的向量會與原來2個向量定義的平面垂直. 同時進行叉乘,不必為單位向量;
前提: 2個普通向量
動作: 向量與向量叉乘
結(jié)果: 向量(垂直于原來2個向量定義的平面的向量)
math3d 庫中提供了了關(guān)于叉乘的API
//1.m3dCrossProduct3 函數(shù)獲得2個向量量之間的叉乘結(jié)果得到?個新的向量
void m3dCrossProduct3(M3DVector3f result,const M3DVector3f u ,const
M3DVector3f v);
注意:result是存放新返回的向量,與點乘不同的是肖粮,叉乘要按照順序來設(shè)置孤页,不然得出的值會是相反值,例如:v1乘v2是向上的向量涩馆,v2乘v1是向下的向量行施,所以需要注意順序,不能亂乘魂那。
矩陣
假設(shè), 在空間有一個點.使用 xyz 描述它的位置. 此時讓其圍繞任意位置旋轉(zhuǎn)一定?度
后. 我們需要知道這個點的新的位置. 此時需要通過矩陣進行計算;
為什么?
因為新的位置的x不單純與原來的x還和旋轉(zhuǎn)的參數(shù)有關(guān). 甚?至于y和z坐標有關(guān);
矩陣只有?行或者?列都是合理的. 只有??或者?列數(shù)字可以稱為向量. 也可以稱為矩陣;
OPenGl中三維矩陣/四維矩陣的聲明
typedef float M3DMatrix33f[9];
typedef float M3DMatrix44f[16];
在其他編程標準中, 許多矩陣庫定義?個矩陣時,使用二維數(shù)組;
OpenGL的約定里,更多傾向使??維數(shù)組; 這樣做的原因是: OpenGL 使用的是 Column-Major(以列列為主)矩陣排序的約定蛾号,如下圖:
- 行優(yōu)先矩陣:一行一行讀取
- 列優(yōu)先矩陣:一列一列讀取
兩者的關(guān)系為:行優(yōu)先矩陣經(jīng)過轉(zhuǎn)置 即可的到列優(yōu)先矩陣
由上我們知道OPenGl中的矩陣是列優(yōu)先矩陣琅翻,那么其中的值分別代表什么呢褂始?如下圖
這16個值表示空間中一個特定的位置; 這4列中,每一列都是有4個元素組成的向量;
如果將?個對象所有的頂點向量乘以這個矩陣,就能讓整個對象變換到空間中給定的位置和?方向;
那么?個4*4矩陣是如何在3D空間中表示?個位置和?向的呢?
列向量進?了特別的標注:矩陣的最后一?都為0您访,只有最后?個元素為1活逆,如上如所示精刷。
單元矩陣
主對角線上數(shù)據(jù)都是1,其余元素都是0蔗候,即為單元矩陣怒允;
//單元矩陣初始化?方式1
GLFloat m[] = {
1,0,0,0, //X Column
0,1,0,0, //Y Column
0,0,1,0, //Z Column
0,0,0,1 // Translation
}
// 單元矩陣初始化?方式 2
M3DMatrix44f m = {
1,0,0,0, //X Column
0,1,0,0, //Y Column
0,0,1,0, //Z Column
0,0,0,1 // Translation }
//單元矩陣初始化?方式3
void m3dLoadIdentity44f(M3DMatrix44f m);
向量 X 單元矩陣 = 向量 X 1,不會發(fā)生任何變化锈遥;
向量與單元矩陣相乘的前提是:向量的列數(shù) == 單元矩陣的行數(shù)误算;如下就不能相乘
矩陣的點乘
矩陣可以進行點乘的前提:兩個矩陣的行列數(shù)相等
矩陣A · 矩陣B = 矩陣C
-規(guī)則: 矩陣A的第一個元素與矩陣B的第一個元素的乘積 = 矩陣C的第一個元素
矩陣的叉乘
矩陣可以進行叉乘的前提:第一個矩陣的列數(shù) = 第二個矩陣的行數(shù)
矩陣A X 矩陣B = 矩陣C
規(guī)則:矩陣A第一行與矩陣B第一列對應(yīng)元素乘積的綜合 = 矩陣C的第一個元素
OpenGL中的矩陣相乘
- 線性代數(shù)?度
OpenGL中的矩陣規(guī)定是以行為主仰美,所以頂點以列向量的方式表示
在線性代數(shù)學的維度,為了便于書寫. 所以坐標計算. 都是從左往右順序,進?計算. 如下
列公式:
變換后頂點向量 = V_local * M_model * M_view * M_pro
變換后頂點向量 = 頂點 ? 模型矩陣 ? 觀察矩陣 ? 投影矩陣
這種方式叫做左乘
,如下圖以線性代數(shù)的方式進行MVP矩陣的計算
- OpenGL?度
OpenGL中的矩陣規(guī)定是以列為主,所以頂點以列向量的方式表示
在OpenGL 的維度. 如下列列公式:
變換頂點向量 = M_pro * M_view * M_model * V_local
變換頂點向量 = 投影矩陣 ? 視圖變換矩陣 ? 模型矩陣 ? 頂點
這種方式叫做右乘
,如下圖以O(shè)PenGL的方式進行MVP矩陣的計算
OPenGL中MVP矩陣相乘順序
OpenGL矩陣堆棧中矩陣相乘源碼分析
上圖矩陣相乘主要有三步:
- 從棧頂獲取棧頂矩陣 復制到 mTemp;
- 將棧頂矩陣 mTemp 左乘 mMatrix ;
- 將結(jié)果放回棧頂空間?;
在我們繪制金字塔儿礼、六邊形的案例中咖杂,我們用到了MVP(模型視圖投影矩陣),那么其中各矩陣的相乘規(guī)則是什么樣的呢蚊夫?
1诉字、ChangeSize函數(shù)中,得到投影矩陣知纷,將投影矩陣壓入投影矩陣堆棧棧頂壤圃,并與模型視圖矩陣棧頂相乘,將結(jié)果覆蓋棧頂琅轧,即 投影矩陣 * 單元矩陣 = 投影矩陣
2伍绳、RenderScene函數(shù)中,將棧頂矩陣copy一份乍桂,然后將觀察者矩陣與模型視圖矩陣堆棧棧頂相乘冲杀,其結(jié)果覆蓋棧頂矩陣,即投影矩陣 * 視圖矩陣 = 視圖投影矩陣
3睹酌、得到模型矩陣权谁,將模型矩陣與棧頂矩陣相乘,其結(jié)果覆蓋棧頂矩陣憋沿,即 模型矩陣 * 視圖投影矩陣 = 模型視圖投影矩陣
上述代碼旺芽,矩陣堆棧的變化過程如下:
由此可知,在實際的代碼中辐啄,mvp矩陣的計算順序是pvm采章,最后再將頂點矩陣與mvp矩陣相乘,得到物體變換后的頂點和位置壶辜。