OpenGL ES入門: 渲染金字塔 - 顏色、紋理、紋理與顏色混合填充以及GLKit實現

系列推薦文章:
OpenGL/OpenGL ES入門:圖形API以及專業名詞解析
OpenGL/OpenGL ES入門:渲染流程以及固定存儲着色器
OpenGL/OpenGL ES入門:圖像渲染實現以及渲染問題
OpenGL/OpenGL ES入門:基礎變換 - 初識向量/矩陣
OpenGL/OpenGL ES入門:紋理初探 - 經常使用API解析
OpenGL/OpenGL ES入門: 紋理應用 - 紋理座標及案例解析(金字塔)
OpenGL/OpenGL ES入門: 頂點着色器與片元着色器(OpenGL過渡OpenGL ES)
OpenGL/OpenGL ES入門: GLKit以及API簡介
OpenGL/OpenGL ES入門: GLKit使用以及案例
OpenGL/OpenGL ES入門: 使用OpenGL ES 渲染圖片
OpenGL/OpenGL ES入門:iOS紋理翻轉策略解析
OpenGL ES入門: 渲染金字塔 - 顏色、紋理、紋理與顏色混合填充以及GLKit實現git

案例目標

  • 熟悉OpenGL ES渲染圖形過程
  • 練習使用索引的方式處理頂點座標
  • 使用顏色填充金字塔
  • 使用紋理填充金字塔
  • 使用紋理與顏色混合填充金字塔
  • OpenGL ES GLSL渲染與GLKit對比

金字塔渲染實現流程

顏色填充 相關代碼實現

關於圖層設置、上下文設置、清空緩衝區、設置renderBuffer、frameBuffer的代碼,與上一篇:OpenGL/OpenGL ES入門: 使用OpenGL ES 渲染圖片的代碼無異,這裏不過多描述,也會附demo一份,供你們參考。github

編輯着色器

頂點着色器

因爲要實現的是一個金字塔,並且是可以旋轉的,因此咱們新增了投影矩陣和模型矩陣數組

attribute vec4 position;
attribute vec4 positionColor;

uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;

varying lowp vec4 varyColor;

void main()
{
    varyColor = positionColor;
    
    vec4 vPos;
    vPos = projectionMatrix * modelViewMatrix * position;
    gl_Position = vPos;
}
複製代碼

片元着色器

varying lowp vec4 varyColor;
void main()
{
    gl_FragColor = varyColor;
}
複製代碼

開始繪製

設置屏幕(清屏顏色、清除屏幕、視口大小),讀取着色器程序,加載shader、連接以及使用program這些步驟的代碼以前你們都接觸過,這裏再也不展現給你們,由於和上一篇:OpenGL/OpenGL ES入門: 使用OpenGL ES 渲染圖片中的代碼也是一摸同樣的,具體參考demo,下面介紹一下不一樣的。緩存

索引數組

先看下面這個俯視圖的金字塔,共有5個頂點bash

由6個三角形構成,找出對應三角形的三個頂點,而後放進索引數組裏ide

// 頂點數組 前3頂點值(x,y,z),後3位顏色值(RGB)
    GLfloat attrArr[] =
    {
        -0.5f, 0.5f, 0.0f,      1.0f, 0.0f, 1.0f,   0.0f, 1.0f,        //左上0
        0.5f, 0.5f, 0.0f,       1.0f, 0.0f, 1.0f,   1.0f, 1.0f,        //右上1
        0.5f, -0.5f, 0.0f,      1.0f, 1.0f, 1.0f,   1.0f, 0.0f,        //右下2
        -0.5f, -0.5f, 0.0f,     1.0f, 1.0f, 1.0f,   0.0f, 0.0f,        //左下3
        0.0f, 0.0f, 1.0f,       0.0f, 1.0f, 0.0f,   0.5f, 0.5f,        //頂點4
    };
    
    // 索引數組
    GLuint indices[] =
    {
        0, 1, 2,
        0, 2, 3,
        0, 4, 1,
        1, 4, 2,
        2, 4, 3,
        3, 4, 0,
    };
複製代碼

處理頂點數據、頂點顏色值

// 判斷頂點緩存區是否爲空,若是爲空則申請一個緩存區標識符
    if (self.myVertices == 0) {
        glGenBuffers(1, &_myVertices);
    }
    
    //9.-----處理頂點數據-------
    //(1).將_myVertices綁定到GL_ARRAY_BUFFER標識符上
    glBindBuffer(GL_ARRAY_BUFFER, _myVertices);
    //(2).把頂點數據從CPU內存複製到GPU上
    glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
    
    //(3).將頂點數據經過myPrograme中的傳遞到頂點着色程序的position
    //1.glGetAttribLocation,用來獲取vertex attribute的入口的.
    //2.告訴OpenGL ES,經過glEnableVertexAttribArray,
    //3.最後數據是經過glVertexAttribPointer傳遞過去的。
    //注意:第二參數字符串必須和shaderv.vsh中的輸入變量:position保持一致
    GLuint position = glGetAttribLocation(self.myProgram, "position");
    //(4).打開position
    glEnableVertexAttribArray(position);
    //(5).設置讀取方式
    //參數1:index,頂點數據的索引
    //參數2:size,每一個頂點屬性的組件數量,1,2,3,或者4.默認初始值是4.
    //參數3:type,數據中的每一個組件的類型,經常使用的有GL_FLOAT,GL_BYTE,GL_SHORT。默認初始值爲GL_FLOAT
    //參數4:normalized,固定點數據值是否應該歸一化,或者直接轉換爲固定值。(GL_FALSE)
    //參數5:stride,連續頂點屬性之間的偏移量,默認爲0;
    //參數6:指定一個指針,指向數組中的第一個頂點屬性的第一個組件。默認爲0
    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 8, NULL);
    
    //10.--------處理頂點顏色值-------
    //(1).glGetAttribLocation,用來獲取vertex attribute的入口的.
    //注意:第二參數字符串必須和shaderv.glsl中的輸入變量:positionColor保持一致
    GLuint positionColor = glGetAttribLocation(self.myProgram, "positionColor");
    //(2).打開positionColor
    glEnableVertexAttribArray(positionColor);
    glVertexAttribPointer(positionColor, 3, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 8, (float *)NULL + 3);
複製代碼

設置投影矩陣、模型矩陣

//11.找到myProgram中的projectionMatrix、modelViewMatrix 2個矩陣的地址。若是找到則返回地址,不然返回-1,表示沒有找到2個對象。
    GLuint projectionMatrixSlot = glGetUniformLocation(self.myProgram, "projectMatrix");
    GLuint modelViewMatrixSlot = glGetUniformLocation(self.myProgram, "modelViewMatrix");
    
    //12.建立4 * 4投影矩陣
    KSMatrix4 _projectMat;
    //(1)獲取單元矩陣
    ksMatrixLoadIdentity(&_projectMat);
    //(2)計算縱橫比例
    float aspect = self.frame.size.width / self.frame.size.height;
    //(3)獲取透視矩陣
    /*
     參數1:矩陣
     參數2:視角,度數爲單位
     參數3:縱橫比
     參數4:近平面距離
     參數5:遠平面距離
     */
    ksPerspective(&_projectMat, 35, aspect, 5, 20);
    //(4)將投影矩陣傳遞到頂點着色器
    /*
     void glUniformMatrix4fv(GLint location,  GLsizei count,  GLboolean transpose,  const GLfloat *value);
     參數列表:
     location:指要更改的uniform變量的位置
     count:更改矩陣的個數
     transpose:是否要轉置矩陣,並將它做爲uniform變量的值。必須爲GL_FALSE
     value:執行count個元素的指針,用來更新指定uniform變量
     */
    glUniformMatrix4fv(projectionMatrixSlot, 1, GL_FALSE, (GLfloat *)&_projectMat.m[0][0]);
    
    //13.建立一個4 * 4 矩陣,模型視圖矩陣
    KSMatrix4 _modelViewMat;
    //(1)獲取單元矩陣
    ksMatrixLoadIdentity(&_modelViewMat);
    //(2)平移,z軸平移-10
    ksTranslate(&_modelViewMat, 0, 0, -10);
    //(3)建立一個4 * 4 矩陣,旋轉矩陣
    KSMatrix4 _rotationMat;
    //(4)初始化爲單元矩陣
    ksMatrixLoadIdentity(&_rotationMat);
    //(5)旋轉 分別繞X、Y、Z軸
    ksRotate(&_rotationMat, _xDegree, 1, 0, 0);
    ksRotate(&_rotationMat, _yDegree, 0, 1, 0);
    ksRotate(&_rotationMat, _zDegree, 0, 0, 1);
    //(6)把變換矩陣相乘.將_modelViewMatrix矩陣與_rotationMatrix矩陣相乘,結合到模型視圖
    ksMatrixMultiply(&_modelViewMat, &_rotationMat, &_modelViewMat);
    //(7)將模型視圖矩陣傳遞到頂點着色器
    /*
     void glUniformMatrix4fv(GLint location,  GLsizei count,  GLboolean transpose,  const GLfloat *value);
     參數列表:
     location:指要更改的uniform變量的位置
     count:更改矩陣的個數
     transpose:是否要轉置矩陣,並將它做爲uniform變量的值。必須爲GL_FALSE
     value:執行count個元素的指針,用來更新指定uniform變量
     */
    glUniformMatrix4fv(modelViewMatrixSlot, 1, GL_FALSE, (GLfloat *)&_modelViewMat.m[0][0]);
複製代碼

使用索引繪圖

//14.開啓剔除操做效果
    glEnable(GL_CULL_FACE);
    
    //15.使用索引繪圖
    /*
     void glDrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices);
     參數列表:
     mode:要呈現的畫圖的模型
     GL_POINTS
     GL_LINES
     GL_LINE_LOOP
     GL_LINE_STRIP
     GL_TRIANGLES
     GL_TRIANGLE_STRIP
     GL_TRIANGLE_FAN
     count:繪圖個數
     type:類型
     GL_BYTE
     GL_UNSIGNED_BYTE
     GL_SHORT
     GL_UNSIGNED_SHORT
     GL_INT
     GL_UNSIGNED_INT
     indices:繪製索引數組
     
     */
    glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(indices[0]), GL_UNSIGNED_INT, indices);
    //16.從渲染緩衝區顯示到屏幕上
    [self.myContext presentRenderbuffer:GL_RENDERBUFFER];
複製代碼

實現效果:post

紋理填充 - 相關代碼

紋理填充,顧名思義,就是使用圖片去填充,聯繫OpenGL/OpenGL ES入門: 使用OpenGL ES 渲染圖片中所說的圖片渲染,若是你們練習了,應該能夠本身寫的出來。下面給出關鍵代碼:ui

紋理座標的添加spa

// 頂點數組 前3頂點值(x,y,z),後3位顏色值(RGB) 後2位紋理座標
    GLfloat attrArr[] =
    {
        -0.5f, 0.5f, 0.0f,      1.0f, 0.0f, 1.0f,   0.0f, 1.0f,        //左上0
        0.5f, 0.5f, 0.0f,       1.0f, 0.0f, 1.0f,   1.0f, 1.0f,        //右上1
        0.5f, -0.5f, 0.0f,      1.0f, 1.0f, 1.0f,   1.0f, 0.0f,        //右下2
        -0.5f, -0.5f, 0.0f,     1.0f, 1.0f, 1.0f,   0.0f, 0.0f,        //左下3
        0.0f, 0.0f, 1.0f,       0.0f, 1.0f, 0.0f,   0.5f, 0.5f,        //頂點4
    };
複製代碼

在繪製過程當中加載紋理,設置紋理採樣器 sampler2D,相信下面兩句代碼,你們並不陌生。3d

//加載紋理
    [self setupTexture:@"test"];
    //設置紋理採樣器 sampler2D
    glUniform1f(glGetAttribLocation(self.myProgram, "colorMap"), 0);
複製代碼

同時須要修改片元着色器代碼

varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main ()
{
    gl_FragColor = texture2D(colorMap, varyTextCoord);
    
}
複製代碼

最終效果:

紋理與顏色混合填充 - 相關代碼

這裏主要是混合,紋理與顏色的混合,在OpenGL系列文章裏說過混合,有相關公式,主要代碼在片元着色器中實現,具體代碼以下:

precision highp float;

varying lowp vec4 varyColor;
varying lowp vec2 varyTextCoord;

uniform sampler2D colorMap;

void main ()
{
    vec4 weakMask = texture2D(colorMap, varyTextCoord);
    vec4 mask = varyColor;
    float alpha = 0.3;
    
    vec4 tempColor = mask * (1.0 - alpha) + weakMask * alpha;
    gl_FragColor = tempColor;
}
複製代碼

最終效果:

GLKit實現代碼

設置圖層

//1.新建圖層
- (void)setupContext {
    //1.新建OpenGL ES上下文
    self.mContext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
    
    GLKView *view = (GLKView *)self.view;
    view.context = self.mContext;
    view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    
    [EAGLContext setCurrentContext:self.mContext];
    glEnable(GL_DEPTH_TEST);
}
複製代碼

渲染圖形

//2.渲染圖形
- (void)render {
    //1.頂點數據
    // 頂點數組 前3頂點值(x,y,z),後3位顏色值(RGB) 後2位紋理座標
    GLfloat attrArr[] =
    {
        -0.5f, 0.5f, 0.0f,      1.0f, 0.0f, 1.0f,   0.0f, 1.0f,        //左上0
        0.5f, 0.5f, 0.0f,       1.0f, 0.0f, 1.0f,   1.0f, 1.0f,        //右上1
        0.5f, -0.5f, 0.0f,      1.0f, 1.0f, 1.0f,   1.0f, 0.0f,        //右下2
        -0.5f, -0.5f, 0.0f,     1.0f, 1.0f, 1.0f,   0.0f, 0.0f,        //左下3
        0.0f, 0.0f, 1.0f,       0.0f, 1.0f, 0.0f,   0.5f, 0.5f,        //頂點4
    };
    
    //2.繪圖索引
    GLuint indices[] =
    {
        0, 1, 2,
        0, 2, 3,
        0, 4, 1,
        1, 4, 2,
        2, 4, 3,
        3, 4, 0,
    };
    
    //頂點個數
    self.count = sizeof(indices) /sizeof(GLuint);

    //將頂點數組放入數組緩衝區中 GL_ARRAY_BUFFER
    GLuint buffer;
    glGenBuffers(1, &buffer);
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_STATIC_DRAW);
    
    //將索引數組存儲到索引緩衝區 GL_ELEMENT_ARRAY_BUFFER
    GLuint index;
    glGenBuffers(1, &index);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    
    //使用頂點數據
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, NULL);
    
    //使用顏色數據
    glEnableVertexAttribArray(GLKVertexAttribColor);
    glVertexAttribPointer(GLKVertexAttribColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL + 3);
    
    //使用紋理數據
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL + 6);
    
    //獲取紋理路徑
    NSString *filePath = [[NSBundle mainBundle]pathForResource:@"timg" ofType:@"jpeg"];
    
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@"1",GLKTextureLoaderOriginBottomLeft, nil];
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
    
    //着色器
    self.mEffect = [[GLKBaseEffect alloc]init];
    self.mEffect.texture2d0.enabled = GL_TRUE;
    self.mEffect.texture2d0.name = textureInfo.name;
    
    //投影視圖
    CGSize size = self.view.bounds.size;
    float aspect = fabs(size.width / size.height);
    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90.0), aspect, 0.1f, 1000.f);
    self.mEffect.transform.projectionMatrix = projectionMatrix;
    
    //模型視圖
    GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -3.0f);
    self.mEffect.transform.modelviewMatrix = modelViewMatrix;
    
    //定時器
    double seconds = 0.1;
    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC, 0.0);
    dispatch_source_set_event_handler(timer, ^{
       
        self.XDegree += 0.1f * self.XB;
        self.YDegree += 0.1f * self.YB;
        self.ZDegree += 0.1f * self.ZB ;
        
    });
    dispatch_resume(timer);

}
複製代碼

場景更新

- (void)update {
    GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -3.0f);
    modelViewMatrix = GLKMatrix4RotateX(modelViewMatrix, self.XDegree);
    modelViewMatrix = GLKMatrix4RotateY(modelViewMatrix, self.YDegree);
    modelViewMatrix = GLKMatrix4RotateZ(modelViewMatrix, self.ZDegree);
    self.mEffect.transform.modelviewMatrix = modelViewMatrix;
}
複製代碼

繪製

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    [self.mEffect prepareToDraw];
    glDrawElements(GL_TRIANGLES, self.count, GL_UNSIGNED_INT, 0);
}
複製代碼

最終實現效果:

該方法實現的代碼,後面整理好以後,也會上傳一份demo給你們參考。

相關文章
相關標籤/搜索