OpenGLES-04 绘制带颜色的立方体

前面几篇文章都只是绘制了平面图形,接下来我们开始绘制一个真正的3D立方体图形。代码在前一篇文章基础上修改。 绘制立方体之前,我们需要知道这个立方体的各个顶点坐标(找不到图,自己画的,请将就将就):

IMG_0004.JPG

一个立方体有8个顶点,在这里是:

GLfloat vertices[] = {
        -0.5f, -0.5f, 0.5f,
        -0.5f, 0.5f, 0.5f,
        0.5f, 0.5f, 0.5f,
        0.5f, -0.5f, 0.5f,
        
        0.5f, -0.5f, -0.5f,
        0.5f, 0.5f, -0.5f,
        -0.5f, 0.5f, -0.5f,
        -0.5f, -0.5f, -0.5f,
    };

它的索引是:

GLubyte indices[] = {
        // Front face
        0, 3, 2, 0, 2, 1,
        
        // Back face
        7, 5, 4, 7, 6, 5,
        
        // Left face
        0, 1, 6, 0, 6, 7,
        
        // Right face
        3, 4, 5, 3, 5, 2,
        
        // Up face
        1, 2, 5, 1, 5, 6,
        
        // Down face
        0, 7, 4, 0, 4, 3
    };

所以我们修改render函数的代码如下:

-(void)render
{
    //设置清屏颜色,默认是黑色,如果你的运行结果是黑色,问题就可能在这儿
    glClearColor(0.3, 0.5, 0.8, 1.0);
    /*
    glClear指定清除的buffer
    共可设置三个选项GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT
    也可组合如:glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    这里我们只用了color buffer,所以只需清除GL_COLOR_BUFFER_BIT
     */
    glClear(GL_COLOR_BUFFER_BIT);
    
    // Setup viewport
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);

    GLfloat vertices[] = {
        -0.5f, -0.5f, 0.5f,
        -0.5f, 0.5f, 0.5f,
        0.5f, 0.5f, 0.5f,
        0.5f, -0.5f, 0.5f,
        
        0.5f, -0.5f, -0.5f,
        0.5f, 0.5f, -0.5f,
        -0.5f, 0.5f, -0.5f,
        -0.5f, -0.5f, -0.5f,
    };
    
    GLubyte indices[] = {
        // Front face
        0, 3, 2, 0, 2, 1,
        
        // Back face
        7, 5, 4, 7, 6, 5,
        
        // Left face
        0, 1, 6, 0, 6, 7,
        
        // Right face
        3, 4, 5, 3, 5, 2,
        
        // Up face
        1, 2, 5, 1, 5, 6,
        
        // Down face
        0, 7, 4, 0, 4, 3
    };
    
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices);
    glEnableVertexAttribArray(_positionSlot);
    glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, indices);
     
    
    [_context presentRenderbuffer:_renderBuffer];
}

运行结果如下:

运行结果.png

诶,我们不是画了个立方体吗?代码画的怎么跟我在纸上画的那个不一样呢? 事实上,我们代码画的确实是一个立方体,只是我们观察的角度是从正方体正面看过去的,立体的部分全被前面的面挡住了,只要我们旋转一下立方体,就能看到立体的部分了,不过这个问题会在下一篇讲到,这里先绘制立方体,只修改它的颜色。 而且,事实上我们画的是个正方体,这里展示是个长方体,这是由于没有进行宽高等比的投影矩阵处理,这里opengl坐标是按着屏幕来的,所以是个长方体。

图中立方体的颜色是我们在片元着色器脚本文件自己定义的固定颜色

precision mediump float;

void main()
{
    gl_FragColor = vec4(0.9, 0.5, 0.7, 1.0);
}

如果我们想在外面的代码中动态修改它的颜色,我们需要定义一个变量来接收传入的颜色。 1.修改顶点着色器脚本文件:

attribute vec4 vPosition;

attribute vec4 vSourceColor;      //新加
varying vec4 vDestinationColor;   //新加

void main(void)
{
    gl_Position = vPosition;
    vDestinationColor = vSourceColor; //新加
}

2.修改片元着色器脚本文件

precision mediump float;

varying vec4 vDestinationColor;  //新加

void main()
{
    gl_FragColor = vDestinationColor;  //修改
}

以上着色器代码在《OpenGLES-02 绘制基本图元(点、线、三角形)》中有介绍,详细了解glsl请点这里 (也希望你确实做过《拨开迷雾》里的准备工作,如果到这里你还有很多概念不理解,希望你停下来,先去查询资料,理解概念): http://www.cnblogs.com/kex1n/p/3941680.html

好啦,着色器语言已经写好了,接下来我们开始使用

3.代码绘制 我们在MyGLView中新定义一个变量:GLuint _colorSlot; //颜色槽位

@interface MyGLView ()
{
    CAEAGLLayer *_eaglLayer;  //OpenGL内容只会在此类layer上描绘
    EAGLContext *_context;    //OpenGL渲染上下文
    GLuint _renderBuffer;     //
    GLuint _frameBuffer;      //

    GLuint _programHandle;
    GLuint _positionSlot; //顶点槽位
    GLuint _colorSlot;   //颜色槽位
}

然后在setupProgram函数中获取这个_colorSlot:

_positionSlot = glGetAttribLocation(_programHandle, "vPosition");
_colorSlot    = glGetAttribLocation(_programHandle, "vSourceColor"); //新加

接下来我们需要构造自己的颜色数据,对于OpenGL,它支持两种着色模式:单调着色(Flat)与平滑着色(smooth,也称Gouraud着色)。单调着色就是整个图元的颜色就是它的任何一个顶点的颜色,比如上面固定颜色的三角形效果;平滑着色下每个顶点都是单独进行的,顶点之间的点是所有顶点颜色的均匀插值计算而得,顶点与顶点颜色是在一起的,如下:

GLfloat vertices[] = {
        -0.5f, -0.5f, 0.5f, 1.0, 0.0, 0.0, 1.0,     // red
        -0.5f, 0.5f, 0.5f, 1.0, 1.0, 0.0, 1.0,      // yellow
        0.5f, 0.5f, 0.5f, 0.0, 0.0, 1.0, 1.0,       // blue
        0.5f, -0.5f, 0.5f, 1.0, 1.0, 1.0, 1.0,      // white
        
        0.5f, -0.5f, -0.5f, 1.0, 1.0, 0.0, 1.0,     // yellow
        0.5f, 0.5f, -0.5f, 1.0, 0.0, 0.0, 1.0,      // red
        -0.5f, 0.5f, -0.5f, 1.0, 1.0, 1.0, 1.0,     // white
        -0.5f, -0.5f, -0.5f, 0.0, 0.0, 1.0, 1.0,    // blue
    };

索引数据是不变的,然后我们需要使用颜色槽位数据,修改render函数如下:

-(void)render
{
    //设置清屏颜色,默认是黑色,如果你的运行结果是黑色,问题就可能在这儿
    glClearColor(0.3, 0.5, 0.8, 1.0);
    /*
    glClear指定清除的buffer
    共可设置三个选项GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT
    也可组合如:glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    这里我们只用了color buffer,所以只需清除GL_COLOR_BUFFER_BIT
     */
    glClear(GL_COLOR_BUFFER_BIT);
    
    // Setup viewport
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);
    
    GLfloat vertices[] = {
        -0.5f, -0.5f, 0.5f, 1.0, 0.0, 0.0, 1.0,     // red
        -0.5f, 0.5f, 0.5f, 1.0, 1.0, 0.0, 1.0,      // yellow
        0.5f, 0.5f, 0.5f, 0.0, 0.0, 1.0, 1.0,       // blue
        0.5f, -0.5f, 0.5f, 1.0, 1.0, 1.0, 1.0,      // white
        
        0.5f, -0.5f, -0.5f, 1.0, 1.0, 0.0, 1.0,     // yellow
        0.5f, 0.5f, -0.5f, 1.0, 0.0, 0.0, 1.0,      // red
        -0.5f, 0.5f, -0.5f, 1.0, 1.0, 1.0, 1.0,     // white
        -0.5f, -0.5f, -0.5f, 0.0, 0.0, 1.0, 1.0,    // blue
    };
    
    GLubyte indices[] = {
        // Front face
        0, 3, 2, 0, 2, 1,
        
        // Back face
        7, 5, 4, 7, 6, 5,
        
        // Left face
        0, 1, 6, 0, 6, 7,
        
        // Right face
        3, 4, 5, 3, 5, 2,
        
        // Up face
        1, 2, 5, 1, 5, 6,
        
        // Down face
        0, 7, 4, 0, 4, 3
    };
    
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), vertices);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), vertices+3);
    glEnableVertexAttribArray(_positionSlot);
    glEnableVertexAttribArray(_colorSlot);
    glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, indices);
     
    
    [_context presentRenderbuffer:_renderBuffer];
}

到这里就得回过来看glVertexAttribPointer()了,

void glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);

参数 index :为顶点数据(如顶点,颜色,法线,纹理或点精灵大小)在着色器程序中的槽位;
参数 size :指定每一种数据的组成大小,比如顶点由 x, y, z 3个组成部分,纹理由 u, v 2个组成部分;
参数 type :表示每一个组成部分的数据格式;
参数 normalized : 表示当数据为法线数据时,是否需要将法线规范化为单位长度,对于其他顶点数据设置为 GL_FALSE 即可。如果法线向量已经为单位长度设置为 GL_FALSE 即可,这样可免去不必要的计算,提升效率;
stride : 表示上一个数据到下一个数据之间的间隔(同样是以字节为单位),OpenGL ES根据该间隔来从由多个顶点数据混合而成的数据块中跳跃地读取相应的顶点数据;
ptr :值得注意,这个参数是个多面手。这里它指向 CPU 内存中的顶点数据数组;

代码中我们给stride填值,以前都是写的0,现在是写出了具体步长,写0是针对单一数据,如只有顶点数据或颜色数据的时候,系统会自己计算匹配,这时候可以写0,若不是单一数据,如上有顶点有颜色,需要自己计算出具体步长。 再看后面ptr的填值,对颜色数据,我们给出的是vertices+3,表示颜色数据从vertices的第4位开始,往后4位是颜色数据(size为4)。

代码的运行结果如下:

颜色运行结果.png

结果显示了我们立方体正面的颜色,顶点用到了(0,1,2,3),所以颜色是红黄蓝白的线性插值。下一篇文章,我们将对这个立方体进行3D变换以看清它确实是个立方体。

所有教程代码在此 : https://github.com/qingmomo/iOS-OpenGLES-

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏贾志刚-OpenCV学堂

手撕OpenCV源码之filter2D(二)

前文对这个函数的分析是为了了解filter的实现结构,所以比较粗略,本文将更细致的分析opencv中filter2D的c++实现的细节,不涉及各种加速的实现方式...

4203
来自专栏Kirito的技术分享

Java随机数探秘

一提到 Java 中的随机数,很多人就会想到 Random,当出现生成随机数这样需求时,大多数人都会选择使用 Random 来生成随机数。Random 类是线程...

1935
来自专栏landv

C语言_愤怒的小鸟

2273
来自专栏包子铺里聊IT

[Google最新面试题] continental divider

给一个矩阵,其中0代表海洋,其他数字代表高度, 秉着水往低处流的原则,求出能够 流向任意海洋的点。 比如说 0 0 0 1 2 3 0 0 1 2 2 4 3 ...

2774
来自专栏移动开发面面观

OpenGL ES——一个平平无奇的三角形

2066
来自专栏数据结构与算法

7828:最大公约数与最小公倍数

7828:最大公约数与最小公倍数 查看 提交 统计 提问 总时间限制: 1000ms 内存限制: 65536kB描述 两个正整数的最大公约数是G,最小公倍数是...

4268
来自专栏菩提树下的杨过

Flash/Flex学习笔记(19):颜色合成与分解的基本原理

传统的RGB颜色体系中,每一个分量值的范围都是0到255,如果转换为2进制的话最多需要8位(比如:十进制的255变成二进制则为11111111),三个分量加起来...

2188
来自专栏拂晓风起

cocos2d-js Shader系列1:cocos2d-js Shader和OpenGL ES2.0

1333
来自专栏tkokof 的技术,小趣及杂念

HGE系列之五 管中窥豹(基础类别)

继上次我们编写了那个小程序之后,想必大家对于HGE的认识都有了进一步的提高,那么现在,我想则是时候来一番“管中窥豹”,睹一睹HGE的源码实现了 :)而相应的源...

951
来自专栏aCloudDeveloper

LeetCode: 221_Maximal Square | 二维0-1矩阵中计算包含1的最大正方形的面积 | Medium

题目: Given a 2D binary matrix filled with 0's and 1's, find the largest square co...

2817

扫码关注云+社区