OpenGL ES入门: 渲染金字塔 - 颜色、纹理、纹理与颜色混合填充以及GLKit实现

栏目: 后端 · 发布时间: 6年前

内容简介:关于图层设置、上下文设置、清空缓冲区、设置renderBuffer、frameBuffer的代码,与由于要实现的是一个金字塔,而且是能够旋转的,所以我们新增了投影矩阵和模型矩阵设置屏幕(清屏颜色、清除屏幕、视口大小),读取着色器程序,加载shader、链接以及使用program这些步骤的代码之前大家都接触过,这里不再展示给大家,因为和
OpenGL ES入门: 渲染金字塔 - 颜色、纹理、纹理与颜色混合填充以及GLKit实现

案例目标

  • 熟悉OpenGL ES渲染图形过程
  • 练习使用索引的方式处理顶点坐标
  • 使用颜色填充金字塔
  • 使用纹理填充金字塔
  • 使用纹理与颜色混合填充金字塔
  • OpenGL ES GLSL渲染与GLKit对比

金字塔渲染实现流程

OpenGL ES入门: 渲染金字塔 - 颜色、纹理、纹理与颜色混合填充以及GLKit实现

颜色填充 相关代码实现

关于图层设置、上下文设置、清空缓冲区、设置renderBuffer、frameBuffer的代码,与 上一篇:OpenGL/OpenGL ES入门: 使用OpenGL ES 渲染图片 的代码无异,这里不过多描述,也会附 demo 一份,供大家参考。

编辑着色器

顶点着色器

由于要实现的是一个金字塔,而且是能够旋转的,所以我们新增了投影矩阵和模型矩阵

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个顶点

OpenGL ES入门: 渲染金字塔 - 颜色、纹理、纹理与颜色混合填充以及GLKit实现

由6个三角形构成,找出对应三角形的三个顶点,然后放进索引数组里

OpenGL ES入门: 渲染金字塔 - 颜色、纹理、纹理与颜色混合填充以及GLKit实现
// 顶点数组 前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];
复制代码

实现效果:

OpenGL ES入门: 渲染金字塔 - 颜色、纹理、纹理与颜色混合填充以及GLKit实现

纹理填充 - 相关代码

纹理填充,顾名思义,就是使用图片去填充,联系 OpenGL/OpenGL ES入门: 使用OpenGL ES 渲染图片 中所说的图片渲染,如果大家练习了,应该可以自己写的出来。下面给出关键代码:

纹理坐标的添加

// 顶点数组 前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,相信下面两句代码,大家并不陌生。

//加载纹理
    [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 ES入门: 渲染金字塔 - 颜色、纹理、纹理与颜色混合填充以及GLKit实现

纹理与颜色混合填充 - 相关代码

这里主要是混合,纹理与颜色的混合,在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;
}
复制代码

最终效果:

OpenGL ES入门: 渲染金字塔 - 颜色、纹理、纹理与颜色混合填充以及GLKit实现

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);
}
复制代码

最终实现效果:

OpenGL ES入门: 渲染金字塔 - 颜色、纹理、纹理与颜色混合填充以及GLKit实现

该方法实现的代码,后面整理好之后,也会上传一份demo给大家参考。


以上所述就是小编给大家介绍的《OpenGL ES入门: 渲染金字塔 - 颜色、纹理、纹理与颜色混合填充以及GLKit实现》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Computational Advertising

Computational Advertising

by Kushal Dave、Vasudeva Varma / Now Publishers Inc / 2014

Computational Advertising (CA), popularly known as online advertising or Web advertising, refers to finding the most relevant ads matching a particular context on the Web. The context depends on the t......一起来看看 《Computational Advertising》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具