iOS-OpenGLES-入門-立方體

前言

這是一篇OpenGlES 系統(tǒng)學(xué)習(xí)教程,記錄自己的學(xué)習(xí)過程英妓。
環(huán)境: Xcode10.2 + OpenGL ES 3.0
目標(biāo): 3D 立方體
這里是demo也拜,你的star和fork是對我最好的支持和動力。

效果展示

立方體.jpg

坐標(biāo)系統(tǒng)

主要有5個不同的坐標(biāo)系統(tǒng):

  • 局部空間(Local Space丑瞧,或者稱為物體空間(Object Space))
  • 世界空間(World Space)
  • 觀察空間(View Space,或者稱為視覺空間(Eye Space))
  • 裁剪空間(Clip Space)
  • 屏幕空間(Screen Space)

變換
為了將坐標(biāo)從一個坐標(biāo)系變換到另一個坐標(biāo)系蜀肘,我們需要用到幾個變換矩陣绊汹,最重要的幾個分別是模型(Model)、觀察(View)扮宠、投影(Projection)三個矩陣西乖。我們的頂點坐標(biāo)起始于局部空間(Local Space),在這里它稱為局部坐標(biāo)(Local Coordinate)坛增,它在之后會變?yōu)?code>世界坐標(biāo)(World Coordinate)获雕,觀察坐標(biāo)(View Coordinate),裁剪坐標(biāo)(Clip Coordinate)收捣,并最后以屏幕坐標(biāo)[圖片上傳中...(坐標(biāo)系變換.png-d41a13-1555986546530-0)]
(Screen Coordinate)的形式結(jié)束届案。下面的這張圖展示了整個流程以及各個變換過程做了什么:

坐標(biāo)系變換.png
  • 局部坐標(biāo)是對象相對于局部原點的坐標(biāo),也是物體起始的坐標(biāo)罢艾。
  • 下一步是將局部坐標(biāo)變換為世界空間坐標(biāo)楣颠,世界空間坐標(biāo)是處于一個更大的空間范圍的。這些坐標(biāo)相對于世界的全局原點咐蚯,它們會和其它物體一起相對于世界的原點進(jìn)行擺放童漩。
  • 接下來我們將世界坐標(biāo)變換為觀察空間坐標(biāo),使得每個坐標(biāo)都是從攝像機或者說觀察者的角度進(jìn)行觀察的春锋。
  • 坐標(biāo)到達(dá)觀察空間之后矫膨,我們需要將其投影到裁剪坐標(biāo)。裁剪坐標(biāo)會被處理至-1.0到1.0的范圍內(nèi)期奔,并判斷哪些頂點將會出現(xiàn)在屏幕上
  • 最后侧馅,我們將裁剪坐標(biāo)變換為屏幕坐標(biāo),我們將使用一個叫做視口變換(Viewport Transform)的過程呐萌。視口變換將位于-1.0到1.0范圍的坐標(biāo)變換到由glViewport函數(shù)所定義的坐標(biāo)范圍內(nèi)施禾。最后變換出來的坐標(biāo)將會送到光柵器,將其轉(zhuǎn)化為片段搁胆。
    以上摘自這里,感興趣的朋友可以細(xì)讀一番邮绿。

投影變換

透視投影
在現(xiàn)實生活中近大遠(yuǎn)小的效果稱之為透視渠旁。如鐵軌的兩條軌道,由于透視船逮,在很遠(yuǎn)的地方看起來會相交一樣顾腊,這就是透視投影想要模仿的效果,它通過透視投影矩陣來完成挖胃,推導(dǎo)過程可以看這里杂靶。

透視投影.png

上圖是視椎體梆惯,透視投影圖形化的過程。
如果要對視椎體進(jìn)行完全控制吗垮,可以使用frustum方法垛吗,或者也可以使用更為直觀的lookA方法。

    // 根據(jù)給定的視椎體設(shè)置返回一個透視投影矩陣烁登。近平面的矩形通過left怯屉、right、bottom和top定義饵沧。近平面和遠(yuǎn)平面的距離通過near和far定義
    static func frustum(resultM4 result:UnsafeMutablePointer<MatrixArray<Float>>, _ left:Float, _ right:Float, _ bottom:Float, _ top:Float, _ nearZ:Float, _ farZ:Float)

    // 根據(jù)eye朝向target的視線锨络,以及up定義的上方向,返回一個透視投影矩陣狼牺。
    static func lookAt(resultM4 result:UnsafeMutablePointer<MatrixArray<Float>>, eye:UnsafePointer<Vec3>, target:UnsafePointer<Vec3>, up:UnsafePointer<Vec3>)

正交投影
當(dāng)使用正射投影時羡儿,每一個頂點坐標(biāo)都會直接映射到裁剪空間中而不經(jīng)過任何精細(xì)的透視除法(它仍然會進(jìn)行透視除法,只是w分量沒有被改變(它保持為1)是钥,因此沒有起作用)掠归。因為正射投影沒有使用透視,遠(yuǎn)處的物體不會顯得更小咏瑟,所以產(chǎn)生奇怪的視覺效果拂到。由于這個原因,正射投影主要用于二維渲染以及一些建筑或工程的程序码泞,在這些場景中我們更希望頂點不會被透視所干擾

正交投影.png

組合

把以上每個步驟創(chuàng)建的變換矩陣:模型矩陣兄旬、觀察矩陣和投影矩陣組合起來。一個頂點坐標(biāo)將會根據(jù)以下過程被變換到剪裁坐標(biāo)系:


變換過程.png

注意矩陣運算的順序是相反的(記住我們需要從右往左閱讀矩陣的乘法)余寥。最后的頂點應(yīng)該被賦值到頂點著色器中的gl_Position领铐,OpenGL將會自動進(jìn)行透視除法和裁剪。

3D立方體

頂點數(shù)據(jù)

let vertices: [GLfloat] = [
            // 前面
            -0.5, 0.5, 0.5,      0.0, 1.0, // 前左上 0
            -0.5, -0.5, 0.5,     0.0, 0.0, // 前左下 1
            0.5, -0.5, 0.5,      1.0, 0.0, // 前右下 2
            0.5, 0.5, 0.5,       1.0, 1.0, // 前右上 3
            // 后面
            -0.5, 0.5, -0.5,     1.0, 1.0, // 后左上 4
            -0.5, -0.5, -0.5,    1.0, 0.0, // 后左下 5
            0.5, -0.5, -0.5,     0.0, 0.0, // 后右下 6
            0.5, 0.5, -0.5,      0.0, 1.0, // 后右上 7
            // 左面
            -0.5, 0.5, -0.5,     0.0, 1.0, // 后左上 8
            -0.5, -0.5, -0.5,    0.0, 0.0, // 后左下 9
            -0.5, 0.5, 0.5,      1.0, 1.0, // 前左上 10
            -0.5, -0.5, 0.5,     1.0, 0.0, // 前左下 11
            // 右面
            0.5, 0.5, 0.5,       0.0, 1.0, // 前右上 12
            0.5, -0.5, 0.5,      0.0, 0.0, // 前右下 13
            0.5, -0.5, -0.5,     1.0, 0.0, // 后右下 14
            0.5, 0.5, -0.5,      1.0, 1.0, // 后右上 15
            // 上面
            -0.5, 0.5, 0.5,      0.0, 0.0, // 前左上 16
            0.5, 0.5, 0.5,       1.0, 0.0, // 前右上 17
            -0.5, 0.5, -0.5,     0.0, 1.0, // 后左上 18
            0.5, 0.5, -0.5,      1.0, 1.0, // 后右上 19
            // 下面
            -0.5, -0.5, 0.5,     0.0, 1.0, // 前左下 20
            0.5, -0.5, 0.5,      1.0, 1.0, // 前右下 21
            -0.5, -0.5, -0.5,    0.0, 0.0, // 后左下 22
            0.5, -0.5, -0.5,     1.0, 0.0, // 后右下 23
        ]
        
        
        // 索引
        let indices:[GLubyte] = [
            // 前面
            0, 1, 2,
            0, 2, 3,
            // 后面
            4, 5, 6,
            4, 6, 7,
            // 左面
            8, 9, 11,
            8, 11, 10,
            // 右面
            12, 13, 14,
            12, 14, 15,
            // 上面
            18, 16, 17,
            18, 17, 19,
            // 下面
            20, 22, 23,
            20, 23, 21
        ]

矩陣變換過程

let width = frame.size.width
        let height = frame.size.height
        
        var projectionMatrix = Matrix.matrix4(0)
        Matrix.matrixLoadIdentity(resultM4: &projectionMatrix)
        let aspect = width / height
        
        //        我們設(shè)置視錐體的近裁剪面到觀察者的距離為 0.1宋舷, 遠(yuǎn)裁剪面到觀察者的距離為 100绪撵,視角為 35度,然后裝載投影矩陣祝蝠。默認(rèn)的觀察者位置在原點音诈,視線朝向 -Z 方向,因此近裁剪面其實就在 z = -0.01 這地方绎狭,遠(yuǎn)裁剪面在 z = -100 這地方细溅,z 值不在(-0.01, -100) 之間的物體是看不到的
        Matrix.perspective(resultM4: &projectionMatrix, 35, Float(aspect), 0.1, 100)  //透視變換,視角30°
        
        // 設(shè)置glsl投影矩陣
        glUniformMatrix4fv(GLint(projectionMatrixSlot), 1, GLboolean(GL_FALSE), projectionMatrix.array)
        
        var modelViewMatrix = Matrix.matrix4(0)
        Matrix.matrixLoadIdentity(resultM4: &modelViewMatrix)
        
        
        var viewMatrix = Matrix.matrix4(0)
        Matrix.matrixLoadIdentity(resultM4: &viewMatrix)
        var eyeVec3 = Vec3(x:0,y:0,z:3)
        var targetVec3 = Vec3(x:0,y:0,z:0)
        var upVec3 = Vec3(x:0,y:1,z:0)
        
        
        Matrix.lookAt(resultM4: &viewMatrix, eye: &eyeVec3, target: &targetVec3, up: &upVec3)
        glUniformMatrix4fv(GLint(viewSlot), 1, GLboolean(GL_FALSE), viewMatrix.array)
        
        // 平移
        // 設(shè)置 z 值 (-0.01,-100)之間
        Matrix.matrixTranslate(resultM4: &modelViewMatrix, tx: 0, ty: 0, tz: -3)
        
        var rotationMatrix = Matrix.matrix4(0)
        Matrix.matrixLoadIdentity(resultM4: &rotationMatrix)
        
        // 旋轉(zhuǎn)
        Matrix.matrixRotate(resultM4: &rotationMatrix, angle: degreeY, x: 1, y: 0, z: 0)
        Matrix.matrixRotate(resultM4: &rotationMatrix, angle: degreeX, x: 0, y: 1, z: 0)
        
        var modelViewMatrixCopy = modelViewMatrix
        Matrix.matrixMultiply(resultM4: &modelViewMatrix, aM4: &rotationMatrix, bM4: &modelViewMatrixCopy)
        
        glUniformMatrix4fv(GLint(modelViewMatrixSlot), 1, GLboolean(GL_FALSE), modelViewMatrix.array);

最后注意點

  • 需要手動開啟深度緩存儡嘶,否則立方體將丟失深度信息 glEnable(GLenum(GL_DEPTH_TEST))
    注:OpenGL應(yīng)該只需要開啟就ok了喇聊,OpenGlES 還需要手動創(chuàng)建深度緩存(這點還未深究,有知道朋友可以留言)蹦狂。如下
        // 創(chuàng)建深度緩沖區(qū)
        var depthRenderBuffer:GLuint = 0
        glGenRenderbuffers(1, &depthRenderBuffer)
        glBindRenderbuffer(GLenum(GL_RENDERBUFFER), depthRenderBuffer)
        glRenderbufferStorage(GLenum(GL_RENDERBUFFER), GLenum(GL_DEPTH_COMPONENT16), width, height)
        myDepthRenderBuffer = depthRenderBuffer
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末誓篱,一起剝皮案震驚了整個濱河市朋贬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌窜骄,老刑警劉巖锦募,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異啊研,居然都是意外死亡御滩,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門党远,熙熙樓的掌柜王于貴愁眉苦臉地迎上來削解,“玉大人,你說我怎么就攤上這事沟娱》胀裕” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵济似,是天一觀的道長矫废。 經(jīng)常有香客問我,道長砰蠢,這世上最難降的妖魔是什么蓖扑? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮台舱,結(jié)果婚禮上律杠,老公的妹妹穿的比我還像新娘。我一直安慰自己竞惋,他們只是感情好柜去,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拆宛,像睡著了一般嗓奢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上浑厚,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天股耽,我揣著相機與錄音,去河邊找鬼钳幅。 笑死豺谈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的贡这。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼厂榛,長吁一口氣:“原來是場噩夢啊……” “哼盖矫!你這毒婦竟也來了丽惭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤辈双,失蹤者是張志新(化名)和其女友劉穎责掏,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體湃望,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡换衬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了证芭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瞳浦。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖废士,靈堂內(nèi)的尸體忽然破棺而出叫潦,到底是詐尸還是另有隱情,我是刑警寧澤官硝,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布矗蕊,位于F島的核電站,受9級特大地震影響氢架,放射性物質(zhì)發(fā)生泄漏傻咖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一岖研、第九天 我趴在偏房一處隱蔽的房頂上張望卿操。 院中可真熱鬧,春花似錦缎玫、人聲如沸硬纤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽筝家。三九已至,卻和暖如春邻辉,著一層夾襖步出監(jiān)牢的瞬間溪王,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工值骇, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留莹菱,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓吱瘩,卻偏偏與公主長得像道伟,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

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