OpenGL ES---矩陣變換

?上一節(jié)中冗酿,借助 OpenGL ES 對二維圖形的繪制,我們了解了相關(guān)概念络断。本節(jié)裁替,我們來談一個有趣的問題,坐標(biāo)變換貌笨。
?坐標(biāo)變換對于渲染管線來說弱判,是一個非常重要的概念。我們通過它锥惋,將一個三維對象從原始的模型坐標(biāo)系中昌腰,一步一步投射到屏幕坐標(biāo)系中。而可編程的 vertex shader(頂點渲染器) 給我們自定義變換過程提供了基礎(chǔ)膀跌。

概述

?接下來遭商,我們來看看坐標(biāo)變換的流程。

坐標(biāo)變換流程

?如上圖所示捅伤,modeling transformation劫流、view transformation、projection transformation 發(fā)生在頂點著色器中(vertex shader)丛忆。而 perspective division 和 view transformation 隨后發(fā)生祠汇,且不可自定義過程。不同的轉(zhuǎn)換熄诡,實際上是將要繪制的對象帶入到了不同的坐標(biāo)系中可很。我們注意到有這樣幾個坐標(biāo)系:

  • 模型坐標(biāo)系:主要用以定義描述繪制對象;
  • 世界坐標(biāo)系:將要繪制的對象放置到世界坐標(biāo)系中凰浮。所有的繪制對象需要一個共同的坐標(biāo)系來決定對象之間的相對位置我抠。正如一個杯子的坐標(biāo),只是用來描述杯子本身的形體袜茧,我們還需要把它們放到世界空間中菜拓,在它的旁邊,可能還有茶壺惫周、桌子等等尘惧。
  • 視坐標(biāo):也叫照相機坐標(biāo)系,你可以想象我們在那個方向递递、那個位置放置了一個照相機喷橙,也可以說啥么,那是我們眼睛的位置。
  • 裁剪坐標(biāo)系:將區(qū)域進行裁剪贰逾,有些東西可能在視線之外悬荣,就需要裁掉;
  • 歸一化坐標(biāo)系:OpenGL 認(rèn)為它所繪制的區(qū)域是一個正方形疙剑,每個方向上范圍在[-1,1]之間氯迂。
  • 屏幕坐標(biāo)系:或者說是窗口坐標(biāo)系,就是將歸一化坐標(biāo)系投射到實際屏幕上言缤。

更加形象的過程嚼蚀,如下圖所示:

坐標(biāo)變換流程

接下來,我們再來詳細看看每種變換過程管挟。

模型變換

?模型變換的主要作用轿曙,是將對象從模型坐標(biāo)系中轉(zhuǎn)移到公共的世界坐標(biāo)系中,模型坐標(biāo)通常用來描述對象本身僻孝。這種變換包括了:平移导帝、旋轉(zhuǎn)、放縮穿铆,而變換本身實際上是通過與一個 4*4 的變換矩陣相乘實現(xiàn)的您单。

平移矩陣:

平移矩陣

縮放矩陣:

縮放矩陣

沿 X 軸旋轉(zhuǎn)矩陣:

沿 X 軸旋轉(zhuǎn)矩陣

沿 Y 軸旋轉(zhuǎn)矩陣:

沿 Y 軸旋轉(zhuǎn)矩陣

沿 Z 軸旋轉(zhuǎn)矩陣:

沿 Z 軸旋轉(zhuǎn)矩陣

?你可能會疑惑,三維世界里的對象當(dāng)然會使用三維坐標(biāo)荞雏,為什么會使用 4*4 的變換矩陣虐秦。

模型變換矩陣

?從數(shù)學(xué)上講,對于一個三維空間中的對象讯檐,旋轉(zhuǎn)羡疗、縮放這些變換是矩陣乘法問題染服,而平移是矩陣加法問題别洪。使用4個分量來描述三維坐標(biāo)就是為了能夠使得平移過程能夠以乘法表示,從而使得 p’ = m1*p + m2(m1 旋轉(zhuǎn)縮放矩陣柳刮, m2 為平移矩陣挖垛, p 為原向量 ,p’ 為變換后的向量)秉颗。轉(zhuǎn)換到 p’ = M*p的形式痢毒。此處還可以參考鏈接
?同時蚕甥,我們使用四個分量來描述三維世界的坐標(biāo)系統(tǒng)實際上是個齊次坐標(biāo)系統(tǒng)哪替,它可以描述無窮遠點。
?下文引用維基百科:

一條通過原點 (0, 0) 的線之方程可寫作 nx + my = 0菇怀,其中 n 及 m 不能同時為 0凭舶。以參數(shù)表示晌块,則能寫成 x = mt, y = ? nt。令 Z=1/t帅霜,則線上的點之笛卡兒坐標(biāo)可寫作 (m/Z, ? n/Z)匆背。在齊次坐標(biāo)下,則寫成 (m, ? n, Z)身冀。當(dāng) t 趨向無限大钝尸,亦即點遠離原點時,Z 會趨近于 0搂根,而該點的齊次坐標(biāo)則會變成 (m, ?n, 0)珍促。因此,可定義 (m, ?n, 0) 為對應(yīng) nx + my = 0 這條線之方向的無窮遠點之齊次坐標(biāo)剩愧。因為歐氏平面上的每條線都會與透過原點的某一條線平行踢星,且因為平行線會有相同的無窮遠點,歐氏平面每條線上的無窮遠點都有其齊次坐標(biāo)隙咸。

?在實際操作過程中沐悦,我們并不會真的先去計算好這些矩陣,然后再進行變換五督,android.opengl.Matrix 類能夠幫助我們計算好它們藏否,具體可以去查詢相關(guān) API 。

//矩陣旋轉(zhuǎn)
Matrix.rotateM(rotationM,0,90,0,1,0);
//矩陣相乘
Matrix.multiplyMM(transformationM,0,eyesMatrix,0,rotationM,0);

視圖變換

?你可以假設(shè)將一個攝像機朝著某個方向在某個位置觀察著三維對象充包,雖然在 OpenGL ES 中并不存在這樣的設(shè)備副签。我們都知道運動是相對的,移動攝像機對物體進行拍攝基矮,相對而言淆储,也可以是移動物體,以達到通過移動攝像機而從不同角度觀察物體的目的家浇。

視圖坐標(biāo)

?這種變換本砰,從本質(zhì)上而言和矩陣的模型變換并沒有差別,實際上所執(zhí)行的都是矩陣乘法钢悲。即点额,以視圖變換矩陣和目標(biāo)對象相乘。具體的推到過程這里將省略莺琳,我們可以使用 Matrix 類提供的方法獲然估狻:

獲取視圖變換矩陣

?API 原型為:

   /**
     * Defines a viewing transformation in terms of an eye point, a center of
     * view, and an up vector.
     *
     * @param rm returns the result
     * @param rmOffset index into rm where the result matrix starts
     * @param eyeX eye point X
     * @param eyeY eye point Y
     * @param eyeZ eye point Z
     * @param centerX center of view X
     * @param centerY center of view Y
     * @param centerZ center of view Z
     * @param upX up vector X
     * @param upY up vector Y
     * @param upZ up vector Z
     */
    public static void setLookAtM(float[] rm, int rmOffset,
            float eyeX, float eyeY, float eyeZ,
            float centerX, float centerY, float centerZ, float upX, float upY,
            float upZ) {
            ......
}

投影變換

?投影變換,從技術(shù)上講是將對象從視坐標(biāo)系下轉(zhuǎn)義到裁剪坐標(biāo)系下惭等。它是在頂點著色器返回 gl_Position 之前進行的最后一次變換珍手,接著,是通過透視除法(w分量),將裁剪坐標(biāo)系轉(zhuǎn)到歸一化坐標(biāo)系下琳要。
?我們最常用的投影是正交投影和透視投影料扰。

正交投影

?對于正交投影,使用平行光線對三維對象進行投影焙蹭,所以所投影出來的影像沒有現(xiàn)實世界中遠近的概念晒杈。在 Android 應(yīng)用開發(fā)中,可以使用以下函數(shù)來獲得變換矩陣:

public static void orthoM(float[] m, int mOffset,
        float left, float right, float bottom, float top,
        float near, float far)

?由上可知孔厉,至少我們可以通過正交投影來設(shè)置要顯示的區(qū)域拯钻。比如,為了讓顯示圖形在顯示的時候不發(fā)生壓縮等形變:

@Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
        // 根據(jù)屏幕方向設(shè)置投影矩陣
        float ratio= width > height ? (float)width / height : (float)height / width;
        if (width > height) {
            // 橫屏
            Matrix.orthoM(projectionMatrix, 0, -ratio, ratio, -1, 1, 0, 5);
        } else {
            Matrix.orthoM(projectionMatrix, 0, -1, 1, -ratio, ratio, 0, 5);
        }
    }

?下面我們來看下透視投影撰豺。

透視投影

?對于透視投影粪般,觀察空間是一個視椎體,遠端大近端小污桦,投射光線顯然不是平行線亩歹,這樣物體投射出來就有了遠近的概念。離眼睛越遠的地方凡橱,物體越小小作,越近,同一個物體顯示越大稼钩。

public static void frustumM(float[] m, int offset,
            float left, float right, float bottom, float top,
            float near, float far) 

視口變換

?該過程是自動執(zhí)行且固定不變的顾稀,用以進行從歸一化坐標(biāo)系到實際屏幕坐標(biāo)系的轉(zhuǎn)換過程。

小結(jié)

?整個過程坝撑,我覺得有點像拍電影静秆。將若干人物(模型坐標(biāo))集中在一個拍攝場景(世界坐標(biāo))中,在拍攝過程中巡李,會進行鏡頭移動到一個固定角度(視圖坐標(biāo))抚笔,調(diào)好焦距(投影坐標(biāo)),進行拍攝侨拦。

參考鏈接:
GLSL Programming/Vertex Transformations
OpenGL ES 投影變換 Projection
Article - World, View and Projection Transformation Matrices
這次殊橙,徹底搞懂 OpenGL 矩陣轉(zhuǎn)換

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市阳谍,隨后出現(xiàn)的幾起案子蛀柴,更是在濱河造成了極大的恐慌螃概,老刑警劉巖矫夯,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吊洼,居然都是意外死亡训貌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來递沪,“玉大人豺鼻,你說我怎么就攤上這事】羁” “怎么了儒飒?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長檩奠。 經(jīng)常有香客問我桩了,道長,這世上最難降的妖魔是什么埠戳? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任井誉,我火速辦了婚禮,結(jié)果婚禮上整胃,老公的妹妹穿的比我還像新娘颗圣。我一直安慰自己,他們只是感情好屁使,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布在岂。 她就那樣靜靜地躺著,像睡著了一般蛮寂。 火紅的嫁衣襯著肌膚如雪洁段。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天共郭,我揣著相機與錄音祠丝,去河邊找鬼。 笑死除嘹,一個胖子當(dāng)著我的面吹牛写半,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播尉咕,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼叠蝇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了年缎?” 一聲冷哼從身側(cè)響起悔捶,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎单芜,沒想到半個月后蜕该,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡洲鸠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年堂淡,在試婚紗的時候發(fā)現(xiàn)自己被綠了馋缅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡绢淀,死狀恐怖萤悴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情皆的,我是刑警寧澤覆履,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站费薄,受9級特大地震影響内狗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜义锥,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一柳沙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拌倍,春花似錦赂鲤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至梗顺,卻和暖如春泡孩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背寺谤。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工仑鸥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人变屁。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓眼俊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親粟关。 傳聞我的和親對象是個殘疾皇子疮胖,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

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