OpenGLES學習之路-三維變換

學習之路系列

OpenGLES學習之路

今天我們實現一個三維空間中物體的變換操作

本篇主要內容

三維坐標變換

效果圖

實現過程

首先我們跟之前一樣給出以下頂點數據

//4個頂點(分別表示xyz軸)
static const float Vertices[] = {
    
    -0.5, -0.5, 0,  //左下
     0.5, -0.5, 0,  //右下
    -0.5,  0.5, 0,  //左上
     0.5,  0.5, 0,  //右上
};

//4個點的顏色(分別表示RGBA值)
static const float Colors[] = {
    
    1, 0, 0, 1,
    0, 1, 0, 1,
    0, 0, 1, 1,
    0, 0, 0, 1,
};

然后進行渲染, 中間的渲染緩沖區、幀緩沖區、編譯著色器我們暫時先省略,有不明白的小伙伴可以參考這篇文章

- (void)render:(CADisplayLink *)displayLink {
    
    //用指定的顏色清除,清除顏色被設置為(0.5f, 0.5f, 0.5f, 1.0f), 所以為黑色
    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    
    //設定窗口的范圍(如果不是很明白, 可以自己動手修改下試試)
    //他這個是左下角為(0,0) 右上角為(width,height)
    glViewport(0, 0, _width, _height);
    
    //指定了渲染時索引值為 index 的頂點屬性數組的數據格式和位置。
    /*
     *  indx:指定要修改的頂點屬性的索引值
     *  size:指定每個頂點屬性的組件數量。(必須坐標xyz軸就是3, 顏色rgba就是4)
     *  type:指定數組中每個組件的數據類型。(一般為GL_FLOAT)
     *  normalized:一般為GL_FALSE
     *  stride:指定連續頂點屬性之間的偏移量。如果為0,那么頂點屬性會被理解為:它們是緊密排列在一起的。初始值為0。
     *  ptr:指向數據的指針
     */
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, Vertices);
    glVertexAttribPointer(_colorSlot,    4, GL_FLOAT, GL_FALSE, 0, Colors);
    
    glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(Vertices) / (sizeof(int) * 3));
    
    //把緩沖區的數據呈現到UIView上
    [_context presentRenderbuffer:GL_RENDERBUFFER];
}
渲染結果

我們接下來需要把他弄成正方形的,由于還沒有學習投影,我們先改動渲染的窗口來達成這一目的
render:方法中的

glViewport(0, 0, _width, _height);

改成

glViewport(0, 0, _width, _width);
看下效果

這樣子就實現了正方形了

三維變換

給大家介紹一個網址LearnOpenGL, 上面對三維變換的講解很詳細, 下面就來實現下這三種操作(縮放、位移、旋轉)


系統已經提供了矩陣操作的框架, 網上也有一些大神提供的矩陣操作的第三方庫,我們可以直接拿到使用,不會矩陣的小伙伴也可以玩轉三維操作O(∩_∩)O。這里我們直接使用系統的

我們先修改下頂點著色器

attribute vec4 Position;

attribute vec4 InColor;
varying   vec4 OutColor;

uniform mat4 Model;     //new

void main(void){
    OutColor = InColor;
//    gl_Position = Position;
    gl_Position = Model * Position;
}

并在編譯著色器(compileShaders:)的地方獲取著色器中的ModelView變量

_modelView = glGetUniformLocation(_program, "ModelView");

下面的的代碼直接在

  • 縮放
GLKMatrix4 modelView = GLKMatrix4MakeScale(_transformScale[0],
                                           _transformScale[1],
                                           _transformScale[2]);
    
    //給著色器變量賦值
    /*
        location:   變量的位置
        count   :   要更改變量的個數
        transpose:  是否需要轉置
        value   :   給出對應count個元素的指針
    */
    glUniformMatrix4fv(_modelView, 1, GL_FALSE, modelView.m);

GLKMatrix4MakeScale是系統初始化縮放矩陣的函數
看下效果:

  • 位移
GLKMatrix4 modelView = GLKMatrix4MakeTranslation(_transformTranslation[0],
                                                 _transformTranslation[1],
                                                 _transformTranslation[2]);
    
    //給著色器變量賦值
    /*
        location:   變量的位置
        count   :   要更改變量的個數
        transpose:  是否需要轉置
        value   :   給出對應count個元素的指針
    */
    glUniformMatrix4fv(_modelView, 1, GL_FALSE, modelView.m);

GLKMatrix4MakeTranslation是系統初始化平移矩陣的函數
看下效果:

  • 旋轉
    GLKMatrix4 modelView = GLKMatrix4MakeRotation(_transformRotation[0],1,0,0);
    modelView = GLKMatrix4Rotate(modelView, _transformRotation[1], 0, 1, 0);
    modelView = GLKMatrix4Rotate(modelView, _transformRotation[2], 0, 0, 1);
    
    //給著色器變量賦值
    /*
        location:   變量的位置
        count   :   要更改變量的個數
        transpose:  是否需要轉置
        value   :   給出對應count個元素的指針
    */
    glUniformMatrix4fv(_modelView, 1, GL_FALSE, modelView.m);

旋轉操作需要將3個軸(x、y、z)分開單獨操作
上面的旋轉函數需要用弧度。

角度 = 弧度 * (180.0f / PI)
弧度 = 角度 * (PI / 180.0f)

看下效果:

  • 矩陣組合

學過矩陣的童鞋都知道,矩陣相乘不遵守交換律
縮放、位移、旋轉三種矩陣按照不同的順序相乘會產生不一樣的效果
舉個例子: 先縮放位移那么當你縮放完以后,你的位移向量一樣會被縮放,比如你要向右移動兩個單位,這時候縮小兩倍,那么的平移的向量一樣會縮小兩倍,就變成了一個單位

順序的話一般都沒有硬性規定, 看需求, 本文順序位移->旋轉->縮放

下面我們把三種效果組合試一下

GLKMatrix4 modelView = GLKMatrix4MakeTranslation(_transformTranslation[0],
                                                     _transformTranslation[1],
                                                     _transformTranslation[2]);
    
    modelView = GLKMatrix4Rotate(modelView, _transformRotation[0], 1, 0, 0);
    modelView = GLKMatrix4Rotate(modelView, _transformRotation[1], 0, 1, 0);
    modelView = GLKMatrix4Rotate(modelView, _transformRotation[2], 0, 0, 1);
    
    modelView = GLKMatrix4Scale(modelView,
                                _transformScale[0],
                                _transformScale[1],
                                _transformScale[2]);
    
    //給著色器變量賦值
    /*
        location:   變量的位置
        count   :   要更改變量的個數
        transpose:  是否需要轉置
        value   :   給出對應count個元素的指針
    */
    glUniformMatrix4fv(_modelView, 1, GL_FALSE, modelView.m);

看下效果:

本來想著這篇文章到這樣就結束了,但是回頭一看發現內容有點少,就順便在實現多一個效果吧

先看下下面這段頂點數據

//4個頂點(分別表示xyz軸)
static const float Vertices[] = {
    
    -0.5, -0.5, 0,  //左下
     0.5, -0.5, 0,  //右下
    -0.5,  0.5, 0,  //左上
     0.5,  0.5, 0,  //右上
};

這里有個Z軸還沒用到的,上面是其中一個面
我們還需要把后面的4個坐標點加上,才能湊夠一個立方體(8個點)

//4個頂點(分別表示xyz軸)
static const float Vertices[] = {
    
    //前面4個坐標
    -0.5, -0.5,  0.5,
     0.5, -0.5,  0.5,
    -0.5,  0.5,  0.5,
     0.5,  0.5,  0.5,
    
    //后面4個坐標
    -0.5, -0.5, -0.5,
     0.5, -0.5, -0.5,
    -0.5,  0.5, -0.5,
     0.5,  0.5, -0.5,
};

//4個點的顏色(分別表示RGBA值)
static const float Colors[] = {
    
    1, 0, 0, 1,
    0, 1, 0, 1,
    0, 0, 1, 1,
    0, 0, 0, 1,
    
    1, 0, 0, 1,
    0, 1, 0, 1,
    0, 0, 1, 1,
    0, 0, 0, 1,
};

由于我們只給了8個點的坐標, 所以我們用原來的這個方法有點不合適

glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(Vertices) / (sizeof(float) * 3));

我們來介紹另一個方法glDrawElements, 這個方法跟glDrawArrays一樣都是渲染

這兩種方法的介紹,可以看下這篇文章

創建索引數組

static const GLubyte Indices[] = {
    
    0,  1,  2,
    2,  3,  1,
    
    4,  5,  6,
    6,  7,  5,
    
    2,  3,  6,
    6,  7,  3,
    
    0,  1,  4,
    4,  5,  1,
    
    0,  4,  2,
    2,  6,  4,
    
    1,  5,  3,
    3,  7,  5
};

渲染

/*
*  mode   :    渲染的方式
*  count  :    索引數組元素的數量
*  type   :    索引值的類型
*  indices:    索引數組的指針
*/
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, Indices);

很明顯的看到,層次有點不對

我們需要新增一個深度緩沖區
深度緩沖區簡單來說就是讓物體的渲染有層次感, 詳解看這篇文章

下面這段代碼需要在渲染緩沖區前調用

/**
 *  設置深度緩沖區
 */
- (void)setupDepthBuffer {
    
    glGenRenderbuffers(1, &_depthRenderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, _width, _height);
}

在幀緩沖區中新增一段代碼

/**
 *  設置幀緩沖區
 */
- (void)setupFrameBuffer {
    
    glGenFramebuffers(1, &_frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _renderBuffer);

    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRenderBuffer);    //new
}

render:中的glClearColor修改下

    glClearColor(0.8f, 0.8f, 0.8f, 1.0f);
//    glClear(GL_COLOR_BUFFER_BIT); 
    glEnable(GL_DEPTH_TEST);        //new
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  //new
效果:
結語

自從把這個三維的立方體實現以后,突然感覺OpenGLES很好玩,雖然在這過程中不斷的踩坑調試,但是實現以后又有了滿滿的信心.(??????)??加油
后面的例子會越來越好玩的,一起一步一步的學下去吧
Demo

1.可以嘗試著把縮放、位移、旋轉三種方式的順序換一下,看會有怎么樣子的效果
2.感興趣的小伙伴可以把紋理加上
3.下篇文章我們來實現一個更好玩的坐標系統

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

推薦閱讀更多精彩內容

  • 變換(Transformations) 我們可以嘗試著在每一幀改變物體的頂點并且重設緩沖區從而使他們移動,但這太繁...
    IceMJ閱讀 4,159評論 0 1
  • 版本記錄 前言 OpenGL 圖形庫項目中一直也沒用過,最近也想學著使用這個圖形庫,感覺還是很有意思,也就自然想著...
    刀客傳奇閱讀 5,228評論 0 3
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,662評論 25 708
  • WebGL從2012年開始接觸,后面因為開始專注前端其他方面的事情,慢慢地就把它給遺忘。最近前端開始又流行起繪畫制...
    我不是傳哥閱讀 4,119評論 1 22
  • 作詞:板藍根 作曲:板藍根 F G 眼睛里有光, Em Am 是因為心里住著善良, F...
    耽九閱讀 827評論 0 1