OpenGL ES 3.0(四)矩陣變換

1、概述

前面幾篇關(guān)于OpenGLES的文章:

OpenGL ES 2.0 顯示圖形(上)

OpenGL ES 2.0 顯示圖形(下)

OpenGL ES 3.0(一)綜述

OpenGL ES 3.0(二)GLSL與著色器

OpenGL ES 3.0(三)紋理

有討論到關(guān)于圖像的變換和移動,前面這些變換是圖像基于每一幀改變物體的頂點(diǎn)并且重配置緩沖區(qū)從而使它們移動,但這太繁瑣了,而且會消耗很多的處理時間。現(xiàn)在有一個更好的解決方案,使用(多個)矩陣(Matrix)對象可以更好的變換(Transform)一個物體。

矩陣是一種非常有用的數(shù)學(xué)工具,如果上過線性代數(shù)這門課的話應(yīng)該都會有所了解。這篇主要討論一下在圖像處理中一些最簡單的矩陣變換,并且在OpenGL ES中進(jìn)行實(shí)踐。

2、向量的乘

要討論矩陣,一定繞不開向量。向量可以說是最簡單的矩陣,可以把它理解為1n的矩陣或者是n1的矩陣,關(guān)于向量的加減運(yùn)算和長度計(jì)算等實(shí)在太過基礎(chǔ)這邊不再討論。這邊關(guān)于向量的運(yùn)算主要討論其乘法相關(guān)的運(yùn)算。

2.1 點(diǎn)乘

向量的點(diǎn)乘一般用 v · k 這樣表示,兩個向量的點(diǎn)乘結(jié)果等于它們的數(shù)乘結(jié)果再乘兩個向量之間夾角的余弦值。公式如下:

點(diǎn)乘公式

等式右邊||v|| 和 ||k|| 分別代表兩個向量的長度。通過上面的公式也可以反推出兩個向量之間的夾角。而對于具體的兩個向量,其點(diǎn)乘就是對應(yīng)位置上的數(shù)字相乘再進(jìn)行累加。

向量點(diǎn)乘

2.2 叉乘

叉乘只在3D空間中有定義,它需要兩個不平行向量作為輸入,生成一個正交于兩個輸入向量的第三個向量。如果輸入的兩個向量也是正交的,那么叉乘之后將會產(chǎn)生3個互相正交的向量。下圖展示了3D空間中叉乘的樣子:

3D空間中的叉乘

叉乘公式如下:

向量叉乘

3、矩陣

上面討論的向量其實(shí)也是矩陣的一種,矩陣就是數(shù)字、符號或表達(dá)式數(shù)組。矩陣中每一項(xiàng)叫做矩陣的元素(Element)。下面是一個2×3矩陣的例子:

2*3矩陣

矩陣可以通過(i, j)進(jìn)行索引,i是行,j是列,這就是上面的矩陣叫做2×3矩陣的原因。獲取上面4的索引是(2, 1)(第二行,第一列)(注:如果是圖像索引應(yīng)該是(1, 2),先算列,再算行)。

下面討論一下一些矩陣的基本運(yùn)算。

3.1 矩陣加減

矩陣的加減是矩陣最簡單的操作,矩陣和標(biāo)量進(jìn)行加減其標(biāo)量值要加減到矩陣每一個值當(dāng)中。矩陣與矩陣之間的加減就是兩個矩陣對應(yīng)元素的加減運(yùn)算,不過在相同索引下的元素才能進(jìn)行運(yùn)算。這也就是說加法和減法只對同維度的矩陣才是有定義的。

矩陣與標(biāo)量加法
矩陣之間減法

3.2 矩陣數(shù)乘

矩陣與標(biāo)量相乘和矩陣與標(biāo)量的加減一樣,會對每個數(shù)據(jù)進(jìn)行乘。所以一般也用矩陣的數(shù)乘來縮放矩陣。

矩陣數(shù)乘

3.3 矩陣之間相乘

矩陣之間相乘會復(fù)雜許多,并且會有一些限制:

**① **只有當(dāng)左側(cè)矩陣的列數(shù)與右側(cè)矩陣的行數(shù)相等,兩個矩陣才能相乘。

**② **矩陣相乘不遵守交換律,也就是說A ·B 和 B·A 并不相等。

矩陣相乘時是將左邊矩陣的i行和右邊矩陣的j列分別對應(yīng)相乘并相加得到新矩陣i行j列位置上的值。結(jié)果矩陣的維度是(n, m),n等于左側(cè)矩陣的行數(shù),m等于右側(cè)矩陣的列數(shù)。

矩陣之間相乘

4、矩陣變換

前面已經(jīng)討論了矩陣和向量的一些基本操作,接下來討論通過這些操作來對矩陣進(jìn)行一些常見的變換。

4.1 縮放

對一個向量進(jìn)行縮放(Scaling)就是對向量的長度進(jìn)行縮放,而保持它的方向不變。由于進(jìn)行的是2維或3維操作,可以分別定義一個有2或3個縮放變量的向量,每個變量縮放一個軸(x、y或z)。

先來嘗試縮放向量v = (3,2)。可以把向量沿著x軸縮放0.5,使它的寬度縮小為原來的二分之一;將沿著y軸把向量的高度縮放為原來的兩倍。最終可得到如下向量s = (1.5,4):

向量縮放

OpenGL ES通常是在3D空間進(jìn)行操作的,對于2D的情況可以把z軸縮放1倍,就相當(dāng)于不縮放z軸。上圖的縮放操作是不均勻縮放,因?yàn)槊總€軸的縮放因子都不一樣。如果每個軸的縮放因子都一樣那么就叫均勻縮放。

下面構(gòu)造一個變換矩陣來提供縮放功能。從單位矩陣(矩陣正斜對角線為1,其余為0的矩陣),每個對角線元素會分別與向量的對應(yīng)元素相乘,而不會干擾其他維度上的向量值。對于需要將任意向量(x,y,x)分別縮放(S1,S2,S3)倍時,可以用這樣的特性來構(gòu)造縮放矩陣。如下:

縮放矩陣

第四個縮放向量仍然是1,因?yàn)樵?D空間中縮放w分量是無意義的。w分量另有其他用途,會在后面討論。

4.2 位移

位移是在原始向量的基礎(chǔ)上加上另一個向量從而獲得一個在不同位置的新向量的過程,從而在位移向量基礎(chǔ)上移動了原始向量。和縮放矩陣一樣,在4×4矩陣上有幾個特別的位置用來執(zhí)行特定的操作,對于位移來說它們是第四列最上面的3個值。如果我們把位移向量表示為(Tx,Ty,Tz),就能把位移矩陣定義為:

位移矩陣

因?yàn)樗械奈灰浦刀家艘韵蛄康膚行,所以位移值會加到向量的原始值上。而如果用3x3矩陣位移值就沒地方放也沒地方乘了,所以是不行的。這也是為什么3維的向量要用四維變換矩陣進(jìn)行。

這個向量的w分量也叫齊次坐標(biāo)分量。想要從齊次向量得到3維向量,可以把x、y和z坐標(biāo)分別除以w坐標(biāo)。通常不會注意這個問題,因?yàn)閣分量通常是1.0。使用齊次坐標(biāo)的好處在于它允許在3D向量上進(jìn)行位移(如果沒有w分量是不能位移向量的)。如果一個向量的齊次坐標(biāo)分量值是0,這個坐標(biāo)就是方向向量,因?yàn)閣坐標(biāo)是0,這個向量就不能位移。有了位移矩陣就可以在3個方向(x、y、z)上移動物體。

4.3 旋轉(zhuǎn)

上面幾個的變換內(nèi)容相對容易理解,在二維或三維空間中也容易表示出來,但旋轉(zhuǎn)稍復(fù)雜些。

首先來定義一個向量的旋轉(zhuǎn)到底是什么。二維或三維空間中的旋轉(zhuǎn)用角來表示。角可以是角度制或弧度制的,周角是360角度或2 PI弧度。下圖中展示的二維向量v是由k向右旋轉(zhuǎn)72度所得的:

二維向量的旋轉(zhuǎn)

在三維空間中旋轉(zhuǎn)需要定義一個角和一個旋轉(zhuǎn)軸。物體會沿著給定的旋轉(zhuǎn)軸旋轉(zhuǎn)特定角度。當(dāng)二維向量在三維空間中旋轉(zhuǎn)時,一般把旋轉(zhuǎn)軸設(shè)為z軸。

給定一個角度,可以把一個向量變換為一個經(jīng)過旋轉(zhuǎn)的新向量。這通常是使用一系列正弦和余弦函數(shù)的各種巧妙的組合得到的。旋轉(zhuǎn)矩陣在三維空間中每個單位軸都有不同定義,旋轉(zhuǎn)角度用θ表示:

沿x軸旋轉(zhuǎn):

沿x軸的旋轉(zhuǎn)矩陣

沿y軸旋轉(zhuǎn):

沿y軸的旋轉(zhuǎn)矩陣

沿z軸旋轉(zhuǎn):

沿z軸的旋轉(zhuǎn)矩陣

利用旋轉(zhuǎn)矩陣可以把任意位置向量沿一個單位旋轉(zhuǎn)軸進(jìn)行旋轉(zhuǎn)。也可以將多個矩陣復(fù)合,比如先沿著x軸旋轉(zhuǎn)再沿著y軸旋轉(zhuǎn)。但是這會很快導(dǎo)致一個問題——萬向節(jié)死鎖。對于三維空間中的旋轉(zhuǎn),一個更好的模型是沿著任意的一個軸旋轉(zhuǎn)。這樣的一個旋轉(zhuǎn)矩陣是存在的,但其非常復(fù)雜這邊不進(jìn)行展開討論。

4.4 組合變換

使用矩陣進(jìn)行變換的真正厲害之處在于,根據(jù)矩陣之間的乘法,可以把多個變換組合到一個矩陣中。假設(shè)有一個頂點(diǎn)(x, y, z),希望將其縮放2倍,然后位移(1, 2, 3)個單位。需要一個位移和縮放矩陣來完成這些變換。其最終的組合變換矩陣如下:

組合變換矩陣

當(dāng)矩陣相乘時先寫位移再寫縮放變換。矩陣乘法是不遵守交換律的,這意味著它們的順序很重要。當(dāng)矩陣相乘時,在最右邊的矩陣是第一個與向量相乘的,所以應(yīng)該從右向左讀這個乘法。建議在設(shè)計(jì)組合矩陣時,先進(jìn)行縮放操作,然后是旋轉(zhuǎn),最后才是位移,否則它們會互相影響。比如,如果先位移再縮放,位移的向量也會同樣被縮放。

用最終的變換矩陣左乘我們的向量會得到以下結(jié)果:

組合變換矩陣效果

如上所示,其目標(biāo)向量確實(shí)放大來兩倍并進(jìn)行了位移。

5、OpenGLES中的矩陣

前面已經(jīng)討論完了矩陣的基本知識及操作,接下來討論下關(guān)于OpenGLES 中矩陣的應(yīng)用。OpenGLES中有一個類是專門用來進(jìn)行矩陣處理的android.opengl.Matrix。這個類里面包括了對于矩陣的各種前面提到的處理變換操作。

**① **Matrix.setIdentityM() :用來創(chuàng)建一個單位矩陣。其中第一個參數(shù)是創(chuàng)建出來的單位矩陣存儲的地方,是一個float類型的一維數(shù)組。第二個參數(shù)是存儲的數(shù)據(jù)位置的偏移量,也就是說從哪里開始存儲。生成的結(jié)果先按照列優(yōu)先存儲的,也就是說先存放第一列的數(shù)據(jù),再存放第二列的數(shù)據(jù),以此類推。前面理論部分已經(jīng)提到,所有變換都是基于單位矩陣的基礎(chǔ)上進(jìn)行的,所以第一步創(chuàng)建單位矩陣是必須的。

**② **Matrix.rotateM() :用來進(jìn)行旋轉(zhuǎn)變換的。第一個參數(shù)是需要變換的矩陣;第二參數(shù)是偏移量;第三個參數(shù)是旋轉(zhuǎn)角度,這邊是以角度制,也就是說是0-360這個范圍;第四、五、六個參數(shù)分別代表旋轉(zhuǎn)軸向量的x,y,z值。如果x=0,y=0,z = 1 就相當(dāng)于以z軸為旋轉(zhuǎn)軸進(jìn)行旋轉(zhuǎn),其他類似。

旋轉(zhuǎn)90度效果

**③ **Matrix.translateM() :用來進(jìn)行圖像的位移,第一個參數(shù)是需要變換的矩陣;第二個參數(shù)是偏移量;第三、四、五個參數(shù)分別對應(yīng)x,y,z 方向的位移量。其以圖像自身x,y,z方向?yàn)閱挝唬簿褪钦f當(dāng)x方向位移量為0.5時,相當(dāng)于向右移動0.5個身位,其他類似。

偏移x=0.5 y=0.5效果

**④ **Matrix.scaleM():用來進(jìn)行圖像的縮放,第一個參數(shù)是需要變換的矩陣;第三、四、五個參數(shù)分別對應(yīng)x,y,z 方向的縮放比例,當(dāng)x方向縮放為0.5時,相當(dāng)于向x方向縮放為原來的0.5倍,其他類似。

縮放x=2 y=0.5 效果

前面說過這些變換是可以進(jìn)行組合運(yùn)算的,其組合代碼如下:


Triangle.kt

init{

    ...

    Matrix.setIdentityM(mTransMatrix, 0)

    Matrix.scaleM(mTransMatrix,0,2f,0.5f,1f)

    Matrix.rotateM(mTransMatrix, 0, mAngle, 0f, 0f, 1.0f)

    Matrix.translateM(mTransMatrix, 0, 0.5f, 0.5f, 0f)

    ...

}

之間用上面的操作相當(dāng)于生成了一個組合矩陣,其效果如下圖:

組合矩陣效果

光生成了變換矩陣還不能完成上述操作,還需要將變換矩陣數(shù)據(jù)傳入到頂點(diǎn)著色器上:


// Triangle.kt

private val vertexShaderCode =

                    ...

                    "uniform mat4 transform;" +

                    "void main() {" +

                    " gl_Position = transform * vec4(aPos, 1.0);" +

                    ...

                    "}"

fun draw() {

...

        val transformLoc = GLES30.glGetUniformLocation(mProgram, "transform")

        GLES30.glUniformMatrix4fv(transformLoc, 1, false, mTransMatrix, 0)

...

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內(nèi)容

  • 版本記錄 前言 OpenGL 圖形庫項(xiàng)目中一直也沒用過,最近也想學(xué)著使用這個圖形庫,感覺還是很有意思,也就自然想著...
    刀客傳奇閱讀 5,218評論 0 3
  • 1 前言 OpenGL渲染3D模型離不開空間幾何的數(shù)學(xué)理論知識,而本篇文章的目的就是對空間幾何進(jìn)行簡單的介紹,并對...
    RichardJieChen閱讀 7,058評論 1 11
  • 變換(Transformations) 我們可以嘗試著在每一幀改變物體的頂點(diǎn)并且重設(shè)緩沖區(qū)從而使他們移動,但這太繁...
    IceMJ閱讀 4,155評論 0 1
  • “靜”應(yīng)該是冬季獨(dú)有的特點(diǎn)!站在空曠的山間,遠(yuǎn)遠(yuǎn)的眺望著山的那端,朦朧中連綿起伏,一切都靜的出奇。山靜靜地...
    偷閑躲靜閱讀 497評論 0 2
  • 清邁這幾日 總在暴曬的大熱大悶後 再下場無所顧及的雨 所以白天我基本窩在旅館擼擼貓 寫寫資料 出門 是需要勇氣加持...
    嗚嚶閱讀 264評論 0 0