學(xué)習(xí)OpenGL ES之變換矩陣

本系列所有文章目錄

獲取示例代碼


在介紹本文的代碼之前,先要了解一個(gè)概念:矩陣。學(xué)過(guò)線性代數(shù)的朋友應(yīng)該都知道矩陣相當(dāng)于是一個(gè)二維數(shù)組,有自己的運(yùn)算規(guī)則接奈。下面就通過(guò)幾個(gè)例子簡(jiǎn)單了解一下矩陣的特性歼捐。

3X3矩陣的加法



從圖中可以看出3X3矩陣就像是一個(gè)3X3的表格喂很,每個(gè)單元格中填寫(xiě)一個(gè)數(shù)廷没。它的加法就是把兩個(gè)矩陣對(duì)應(yīng)位置的元素加起來(lái)放在結(jié)果矩陣對(duì)應(yīng)的位置上。那么如果相加的兩個(gè)矩陣尺寸不一樣怎么辦魔市?答案是無(wú)法運(yùn)算主届。矩陣的加減要求兩邊的矩陣必須尺寸相等。

下面是減法的運(yùn)算待德,和加法相似君丁,很好理解。


接下來(lái)是乘法磅网。

乘法稍微有些復(fù)雜谈截,所以我用符號(hào)來(lái)代替數(shù)值,方便觀察規(guī)律涧偷。我們看結(jié)果的第一行第一列aj + bm + cp簸喂,它就是左邊的矩陣第一行和右邊的矩陣第一列逐個(gè)相乘再相加的結(jié)果。


再看結(jié)果的第二行第一列aj + bm + cp燎潮,它就是左邊的矩陣第二行和右邊的矩陣第一列逐個(gè)相乘再相加的結(jié)果喻鳄。


差不多已經(jīng)可以總結(jié)出規(guī)律了,結(jié)果矩陣的第n行第m列的結(jié)果就是左邊的矩陣第n行和右邊的矩陣第m列逐個(gè)相乘再相加的結(jié)果确封。讀者可以看看其他的值是不是這樣計(jì)算出來(lái)的除呵。

最后說(shuō)一下除法,矩陣的除法有些特殊爪喘,比如說(shuō)B/A,可以換算成B*inv(A)颜曾。inv(A)是A的逆矩陣,因?yàn)椴皇撬芯仃嚩加心婢仃嚤#猿ㄔ诰仃囉?jì)算中并不總是可用泛豪。逆矩陣的求解比較復(fù)雜,這里暫時(shí)就不解釋了侦鹏。本文目前也沒(méi)有用到求逆矩陣的地方诡曙。如果讀者感興趣的話,可以自行百度或者翻一翻以前的線性代數(shù)課本略水。

變換矩陣

說(shuō)完了矩陣价卤,那么什么是變換矩陣呢?在圖形繪制過(guò)程中渊涝,有三種變換慎璧,分別是平移,縮放驶赏,旋轉(zhuǎn)炸卑。如果我們想要用代碼表示一個(gè)3D環(huán)境中的變換需要幾個(gè)變量呢,首先要有平移tx, ty, tz煤傍,然后是縮放sx, sy, sz盖文,最后是旋轉(zhuǎn)rx, ry, rz。在渲染的時(shí)候把這些變量附加到原始的位置數(shù)據(jù)上就可以實(shí)現(xiàn)變換了蚯姆。這種方式雖然可行但不夠好五续,尤其是在GPU上這種方式產(chǎn)生的運(yùn)算負(fù)擔(dān)遠(yuǎn)大于使用矩陣洒敏。

attribute vec4 position;
attribute vec4 color;

uniform float elapsedTime;
uniform mat4 transform;

varying vec4 fragColor;

void main(void) {
    fragColor = color;
    gl_Position = transform * position;
}

這是本文代碼例子中的Vertex Shader,新增了一個(gè)uniform uniform mat4 transform;疙驾,mat4這個(gè)類(lèi)型前文有提到過(guò)凶伙,4X4的矩陣。它是Shader內(nèi)置的類(lèi)型它碎,支持直接加減乘等操作函荣。使用矩陣會(huì)產(chǎn)生更少的運(yùn)算指令,GPU可以更好的優(yōu)化運(yùn)算過(guò)程扳肛。那么應(yīng)該怎么使用呢傻挂?接下來(lái)我就一一介紹每一種變換矩陣。

平移矩陣

假設(shè)有一個(gè)點(diǎn)(1, 2, 3),經(jīng)過(guò)大小為(1, 2, 3)的平移挖息,最終必定會(huì)平移到(1+1, 2+2, 3+3)的位置金拒。使用矩陣計(jì)算如下。

這里補(bǔ)充一點(diǎn)套腹,如果左邊的矩陣的列數(shù)等于右邊的矩陣的行數(shù)绪抛,它們就可以相乘,結(jié)果矩陣的行數(shù)等于左邊矩陣的行數(shù)电禀,列數(shù)等于右邊矩陣的列數(shù)幢码。

平移矩陣就是一個(gè)4X4的單位矩陣的第4行的前三個(gè)元素用tx,ty尖飞,tz填充之后的矩陣蛤育。下面就是一個(gè)單位矩陣。


使用GLKMatrix4 translateMatrix = GLKMatrix4MakeTranslation(tx, ty, tz);可以得到一個(gè)平移矩陣葫松。GLKMatrix4MakeTranslation位于GLKit中。

縮放矩陣


縮放矩陣的三個(gè)縮放元素sx底洗,sy腋么,sz,分布在從左到右的對(duì)角線上亥揖,矩陣相乘后位置的x珊擂,y,z分別乘以了sx费变,sy摧扇,sz,從而實(shí)現(xiàn)了縮放挚歧。


代碼實(shí)現(xiàn)如下扛稽。

GLKMatrix4 scaleMatrix = GLKMatrix4MakeScale(sx, sy, sz);

旋轉(zhuǎn)矩陣

旋轉(zhuǎn)矩陣相比于上面兩個(gè)略微有些復(fù)雜,旋轉(zhuǎn)包含兩個(gè)重要元素滑负,旋轉(zhuǎn)的角度在张,繞什么軸旋轉(zhuǎn)用含。具體原理可以參考三維空間中的旋轉(zhuǎn):旋轉(zhuǎn)矩陣、歐拉角帮匾。代碼實(shí)現(xiàn)如下啄骇。

GLKMatrix4 rotateMatrix = GLKMatrix4MakeRotation(M_PI/2 , 0.0, 0.0, 1.0);

M_PI/2是弧度,0.0瘟斜,0.0缸夹,1.0是旋轉(zhuǎn)軸的向量。

綜合三個(gè)矩陣

現(xiàn)在我們得到了三個(gè)矩陣螺句,接下來(lái)就是把它們相乘虽惭。

self.transformMatrix = GLKMatrix4Multiply(translateMatrix, rotateMatrix);
self.transformMatrix = GLKMatrix4Multiply(self.transformMatrix, scaleMatrix);

注意相乘的順序translateMatrix * rotateMatrix * scaleMatrix,這樣可以保證先縮放再旋轉(zhuǎn)壹蔓,最后再平移趟妥。如果先平移再縮放,點(diǎn)的位置已經(jīng)改變佣蓉,縮放出來(lái)的結(jié)果自然就不對(duì)了披摄。

代碼實(shí)現(xiàn)

最后回到本文的代碼實(shí)現(xiàn)中來(lái),我把chapter4的代碼整理了一下勇凭,公用的東西移到了基類(lèi)GLBaseViewController里疚膊,這樣可以更加專(zhuān)注于要重點(diǎn)介紹的知識(shí)點(diǎn)。目前ViewController.m中代碼如下虾标。

//
//  ViewController.m
//  OpenGLESDemo
//
//  Created by wangyang on 15/8/28.
//  Copyright (c) 2015年 wangyang. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()
@property (assign, nonatomic) GLKMatrix4 transformMatrix;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.transformMatrix = GLKMatrix4Identity;
}

#pragma mark - Update Delegate

- (void)update {
    [super update];
    float varyingFactor = sin(self.elapsedTime);
    GLKMatrix4 scaleMatrix = GLKMatrix4MakeScale(varyingFactor, varyingFactor, 1.0);
    GLKMatrix4 rotateMatrix = GLKMatrix4MakeRotation(varyingFactor , 0.0, 0.0, 1.0);
    GLKMatrix4 translateMatrix = GLKMatrix4MakeTranslation(varyingFactor, 0.0, 0.0);
    // transformMatrix = translateMatrix * rotateMatrix * scaleMatrix
    // 矩陣會(huì)按照從右到左的順序應(yīng)用到position上寓盗。也就是先縮放(scale),再旋轉(zhuǎn)(rotate),最后平移(translate)
    // 如果這個(gè)順序反過(guò)來(lái),就完全不同了璧函。從線性代數(shù)角度來(lái)講傀蚌,就是矩陣A乘以矩陣B不等于矩陣B乘以矩陣A。
    self.transformMatrix = GLKMatrix4Multiply(translateMatrix, rotateMatrix);
    self.transformMatrix = GLKMatrix4Multiply(self.transformMatrix, scaleMatrix);
}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    [super glkView:view drawInRect:rect];
    
    GLuint transformUniformLocation = glGetUniformLocation(self.shaderProgram, "transform");
    glUniformMatrix4fv(transformUniformLocation, 1, 0, self.transformMatrix.m);
    [self drawTriangle];
}


#pragma mark - Draw Many Things
- (void)drawTriangle {
    static GLfloat triangleData[36] = {
        0,      0.5f,  0,  1,  0,  0, // x, y, z, r, g, b,每一行存儲(chǔ)一個(gè)點(diǎn)的信息蘸吓,位置和顏色
        -0.5f,  0.0f,  0,  0,  1,  0,
        0.5f,   0.0f,  0,  0,  0,  1,
        0,      -0.5f,  0,  1,  0,  0,
        -0.5f,  0.0f,  0,  0,  1,  0,
        0.5f,   0.0f,  0,  0,  0,  1,
    };
    [self bindAttribs:triangleData];
    glDrawArrays(GL_TRIANGLES, 0, 6);
}

@end

Vertex Shader

attribute vec4 position;
attribute vec4 color;

uniform float elapsedTime;
uniform mat4 transform;

varying vec4 fragColor;

void main(void) {
    fragColor = color;
    gl_Position = transform * position;
}

代碼中每一次update計(jì)算新的變換矩陣善炫,渲染時(shí)把值傳遞給Vertex Shader的uniform mat4 transform,Vertex Shader把原始位置和transform相乘库继,得出新的位置箩艺。注意,因?yàn)閠ransform是mat4宪萄,所以給uniform賦值時(shí)使用的是glUniformMatrix4fv艺谆。代碼效果如下。

本篇主要介紹了什么是變換矩陣拜英,如何使用變換矩陣以及怎樣和Vertex Shader配合静汤。下一篇就要開(kāi)始介紹3D渲染最基本的技術(shù),透視投影矩陣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末撒妈,一起剝皮案震驚了整個(gè)濱河市恢暖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌狰右,老刑警劉巖杰捂,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異棋蚌,居然都是意外死亡嫁佳,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)谷暮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蒿往,“玉大人,你說(shuō)我怎么就攤上這事湿弦∪柯” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵颊埃,是天一觀的道長(zhǎng)蔬充。 經(jīng)常有香客問(wèn)我,道長(zhǎng)班利,這世上最難降的妖魔是什么饥漫? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮罗标,結(jié)果婚禮上庸队,老公的妹妹穿的比我還像新娘。我一直安慰自己闯割,他們只是感情好彻消,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著宙拉,像睡著了一般证膨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鼓黔,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音不见,去河邊找鬼澳化。 笑死,一個(gè)胖子當(dāng)著我的面吹牛稳吮,可吹牛的內(nèi)容都是我干的缎谷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼列林!你這毒婦竟也來(lái)了瑞你?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤希痴,失蹤者是張志新(化名)和其女友劉穎者甲,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體砌创,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡虏缸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嫩实。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刽辙。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖甲献,靈堂內(nèi)的尸體忽然破棺而出宰缤,到底是詐尸還是另有隱情,我是刑警寧澤晃洒,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布慨灭,位于F島的核電站,受9級(jí)特大地震影響锥累,放射性物質(zhì)發(fā)生泄漏缘挑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一桶略、第九天 我趴在偏房一處隱蔽的房頂上張望语淘。 院中可真熱鬧,春花似錦际歼、人聲如沸惶翻。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吕粗。三九已至,卻和暖如春旭愧,著一層夾襖步出監(jiān)牢的瞬間颅筋,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工输枯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留议泵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓桃熄,卻偏偏與公主長(zhǎng)得像先口,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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