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)系作者
  • 序言:七十年代末坑赡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子么抗,更是在濱河造成了極大的恐慌毅否,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝇刀,死亡現(xiàn)場離奇詭異螟加,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)熊泵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門仰迁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人顽分,你說我怎么就攤上這事∈┟郏” “怎么了卒蘸?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我缸沃,道長恰起,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任趾牧,我火速辦了婚禮检盼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘翘单。我一直安慰自己吨枉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布哄芜。 她就那樣靜靜地躺著貌亭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪认臊。 梳的紋絲不亂的頭發(fā)上圃庭,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機(jī)與錄音失晴,去河邊找鬼剧腻。 笑死,一個胖子當(dāng)著我的面吹牛涂屁,可吹牛的內(nèi)容都是我干的恕酸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼胯陋,長吁一口氣:“原來是場噩夢啊……” “哼蕊温!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起遏乔,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤义矛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后盟萨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凉翻,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年捻激,在試婚紗的時候發(fā)現(xiàn)自己被綠了制轰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡胞谭,死狀恐怖垃杖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情丈屹,我是刑警寧澤调俘,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布伶棒,位于F島的核電站,受9級特大地震影響彩库,放射性物質(zhì)發(fā)生泄漏肤无。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一骇钦、第九天 我趴在偏房一處隱蔽的房頂上張望宛渐。 院中可真熱鬧,春花似錦眯搭、人聲如沸窥翩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鳍烁。三九已至,卻和暖如春繁扎,著一層夾襖步出監(jiān)牢的瞬間幔荒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工梳玫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留爹梁,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓提澎,卻偏偏與公主長得像姚垃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子盼忌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

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

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