OpenGL ES 金字塔紋理、顏色混合

我們還是來先看一下效果圖:

了解OpenGL的同學(xué)應(yīng)該知道,使用固定著色器可以繪制這樣一個金字塔。今天我們來講解一下如何使用GLSL繪制這樣一個金字塔。
學(xué)習(xí)這片文章需要先了解一下上一篇文章 OpenGL ES 紋理繪制 。

我們先來準備頂點著色程序和片元著色程序的代碼。

頂點著色程序shaderv.glsl文件:

attribute vec4 position;
attribute vec4 positionColor;
attribute vec2 textureCoordinate;

uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;

varying lowp vec4 varyColor;
varying lowp vec2 varyTextCoord;
void main()
{
    varyColor = positionColor;
    varyTextCoord = textureCoordinate;
    
    vec4 transPos;
    transPos = projectionMatrix * modelViewMatrix * position;
    gl_Position = transPos;
}

position:頂點坐標。
positionColor:頂點顏色坐標。
textureCoordinate:紋理坐標。
projectionMatrix:投影矩陣。
modelViewMatrix: 模型視圖矩陣。
varyColor:用于將傳positionColor遞到片元著色器。varyColor名字和類型需要跟片元著色程序保持一致。
varyTextCoord:用于將傳textureCoordinate遞到片元著色器。varyTextCoord名字和類型需要跟片元著色程序保持一致。

片元著色程序shaderf.glsl文件:

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; 
}

precision highp float:默認精度。
colorMap:紋理采樣器。
varyTextCoord:從頂點著色器傳遞過來的紋理坐標。
varyColor:從頂點著色器傳遞過來的顏色坐標。
tempColor:紋素和顏色轉(zhuǎn)換后的的顏色值。我們本案例繪制的是顏色和紋理混合的效果,所以需要轉(zhuǎn)換。

下面我們來看下代碼的核心流程。
我們在上一篇文章已 OpenGL ES 紋理繪制 中經(jīng)介紹過紋理填充的流程。本案例主流程其實是一樣的。

    //1.設(shè)置layer
    [self setupPyramidLayer];
    //2.設(shè)置上下文
    [self setupPyramidContext];
    //3.清空renderBuffer和frameBuffer
    [self deleteBuffer];
    //4.設(shè)置renderBuffer
    [self setupRenderBuffer];
    //5.設(shè)置frameBuffer
    [self setupFrameBuffer];
    //6.繪制
    [self draw];

前五步準備工作的代碼,跟上一篇文章 OpenGL ES 紋理繪制 中是一樣的,這里就不多介紹了。

我們重點介紹一下核心代碼第六步繪制:
6.1 基本操作

    glClear(GL_COLOR_BUFFER_BIT);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    CGFloat scale = [[UIScreen mainScreen] scale];
    glViewport(self.frame.origin.x * scale, self.frame.origin.y * scale, self.frame.size.width * scale, self.frame.size.height * scale);

6.2 加載shader程序

    NSString *vShaderPath = [[NSBundle mainBundle] pathForResource:@"shaderv" ofType:@"glsl"];
    NSString *fShaderPath = [[NSBundle mainBundle] pathForResource:@"shaderf" ofType:@"glsl"];
    
    if (self.program) {
        glDeleteProgram(self.program);
        self.program = 0;
    }
    //加載程序program
    self.program = [self loadProgramWithShadervPath:vShaderPath shaderfPath:fShaderPath];

6.3 鏈接

    glLinkProgram(self.program);
    GLint linkSuccess;
    glGetProgramiv(self.program, GL_LINK_STATUS, &linkSuccess);
    if (linkSuccess == GL_FALSE) {
        GLchar message[512];
        glGetProgramInfoLog(self.program, sizeof(message), 0, &message[0]);
        NSString *messageString = [NSString stringWithUTF8String:message];
        NSLog(@"Link program failed: %@", messageString);
        return;
    }
    NSLog(@"Link program success!");

6.4 使用

glUseProgram(self.program);

到此前面的代碼都是我們上篇文章 OpenGL ES 紋理繪制 介紹過的,一樣的代碼。



6.5 處理頂點數(shù)據(jù)

我們這里繪制的金字塔,既有顏色也有圖片,所以我們的頂點坐標需要包含金字塔的 頂點坐標、顏色坐標、紋理坐標。

     //頂點坐標
    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,   0.0f, 0.0f, //左下2
        
        0.5f, -0.5f, 0.0f,      1.0f, 1.0f, 1.0f,   1.0f, 0.0f, //右下3
        0.0f, 0.0f, 1.0f,       0.0f, 1.0f, 0.0f,   0.5f, 0.5f, //頂點4
    };
    
    //索引數(shù)組
    GLuint indices[] =
    {
        0, 3, 2,
        0, 1, 3,
        0, 2, 4,
        0, 4, 1,
        2, 3, 4,
        1, 4, 3,
    };
    if (self.vertices == 0) {
        glGenBuffers(1, &_vertices);
    }
    glBindBuffer(GL_ARRAY_BUFFER, self.vertices);
    glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), &attrArr, GL_DYNAMIC_DRAW);

這里引入了索引數(shù)組 indices[],用于制定頂點的連接方式。我們用一張圖來標注一下金字塔的5個頂點:


索引數(shù)組 indices[]中代表了哪三個點連接成一個三角形。

6.6 設(shè)置讀取方式

    GLsizei s = (GLsizei)sizeof(GLfloat)*8;
    GLuint position = glGetAttribLocation(self.program, "position");
    glEnableVertexAttribArray(position);
    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, s, NULL);
    
    GLuint positionColor = glGetAttribLocation(self.program, "positionColor");
    glEnableVertexAttribArray(positionColor);
    glVertexAttribPointer(positionColor, 3, GL_FLOAT, GL_FALSE, s, (float *)NULL + 3);
    
   
    GLuint textureCoordinate = glGetAttribLocation(self.program, "textureCoordinate");
    glEnableVertexAttribArray(textureCoordinate);
    glVertexAttribPointer(textureCoordinate, 2, GL_FLOAT, GL_FALSE, s, (float *)NULL + 6);
  • glGetAttribLocation(self.program, "position");
    program讀取頂點數(shù)據(jù)position,注意這里的"position"一定要跟shaderv.vsh文件中的position保持一致。
  • glEnableVertexAttribArray(position);
    打開頂點數(shù)據(jù)讀取通道,默認是關(guān)閉的。
  • glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, NULL);設(shè)置讀取方式:

6.7 設(shè)置投影矩陣、模型視圖矩陣

    GLint projectionMatrixSlot = glGetUniformLocation(self.program, "projectionMatrix");
    KSMatrix4 _projectionMatrix;
    ksMatrixLoadIdentity(&_projectionMatrix);
    float width = self.frame.size.width;
    float height = self.frame.size.height;
    float aspect = width / height;
    ksPerspective(&_projectionMatrix, 30.0, aspect, 5.0f, 20.0f);
    
    glUniformMatrix4fv(projectionMatrixSlot, 1, GL_FALSE, (GLfloat *)&_projectionMatrix.m[0][0]);
    
    KSMatrix4 _modelViewMatrix;
    ksMatrixLoadIdentity(&_modelViewMatrix);
    ksTranslate(&_modelViewMatrix, 0.0, 0.0, -10.0);
    
    KSMatrix4 _rotationMatrix;
    ksMatrixLoadIdentity(&_rotationMatrix);
    ksRotate(&_rotationMatrix, xDegree, 1.0, 0.0, 0.0);
    ksRotate(&_rotationMatrix, yDegree, 0.0, 1.0, 0.0);
    ksRotate(&_rotationMatrix, zDegree, 0.0, 0.0, 1.0);
    
    ksMatrixMultiply(&_modelViewMatrix, &_rotationMatrix, &_modelViewMatrix);
    GLuint modelViewMatrixSlot = glGetUniformLocation(self.program, "modelViewMatrix");
    glUniformMatrix4fv(modelViewMatrixSlot, 1, GL_FALSE, (GLfloat *)&_modelViewMatrix.m[0][0]);
  • glGetUniformLocation(self.program, "projectionMatrix"):從program讀取投影矩陣projectionMatrix,注意這里的"projectionMatrix"一定要跟shaderv.glsl文件中的projectionMatrix保持一致。

  • glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
    location:該變量在shader中的位置。
    count:被賦值的矩陣的數(shù)目(因為uniform變量可以是一個數(shù)組)。
    transpose:表明在向uniform變量賦值時該矩陣是否需要轉(zhuǎn)置。
    value:傳遞給uniform變量的數(shù)據(jù)的指針。

  • xDegree, yDegree, zDegree 是我們在旋轉(zhuǎn)中修改的角度。

這段代碼中KS開頭的使用到了三方庫中的API。

6.8 加載紋理

[self setupTexture:@"scence"];

該段代碼的內(nèi)容在上一篇文章 OpenGL ES 紋理繪制 中有詳解。

6.9 設(shè)置紋理采樣器 sampler2D

    GLint colorMap = glGetUniformLocation(self.program, "colorMap");
    glUniform1i(colorMap, 0);
    //開啟剔除模式
    glEnable(GL_CULL_FACE);

colorMap需要跟shaderf.fsh文件中保持一致。

6.10 繪制

    glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]), GL_UNSIGNED_INT, indices);

繪制方法跟上篇文章的有所不同。

  • 參數(shù)一:繪制圖元裝配方式。
  • 參數(shù)二:索引數(shù)組的個數(shù)。
  • 參數(shù)三:索引數(shù)組中的類型。
  • 參數(shù)四:索引數(shù)組。

6.11 從渲染緩存區(qū)顯示到屏幕上

    [self.currentContext presentRenderbuffer:GL_RENDERBUFFER];

最后實現(xiàn)轉(zhuǎn)轉(zhuǎn)我們還需要創(chuàng)建個定時器修改角度 xDegree, yDegree, zDegree , 然后重新繪制。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容