前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OpenGLES绘制立体多边形加纹理

OpenGLES绘制立体多边形加纹理

作者头像
清墨
发布2018-05-07 16:08:54
1.8K0
发布2018-05-07 16:08:54
举报
文章被收录于专栏:清墨_iOS分享

前面写了OpenGLES的入门篇,一些朋友觉得还不错,找到我问了一些知识,这次我有针对性的写下这篇文章,也为我OpenGLES进阶篇做个开始。

我已认证微信,感兴趣朋友可进我个人主页,点击微信小图标加我微信。 代码已传GitHub: https://github.com/qingmomo/OpenGLES

效果如下:

最终结果.png

由于是进阶篇,对基础的介绍就不会那么多了:

绘制立体多边形

绘制多边形我们是需要多边形的顶点数据的,这些数据我从网上下载了一个obj文件,从中取出了3个多边形的顶点数据,并给它加上了颜色数据。 但这些多边形的索引数据,obj里的并不是很清楚(可能是我不会用),我使用了自己开发项目的代码来构造。关于构造代码,由于公司利益,这里不会给出,直接会使用构造后的结果。

好了,闲话少讲,步入正题:

新建一个自定义的NewOpenGLView继承自UIView,为了能使用openGLES,我们得做一些基础的配置:

代码语言:javascript
复制
//重写initWithFrame方法便于方法调用
-(instancetype)initWithFrame:(CGRect)frame{
    if (self==[super initWithFrame:frame]) {
        
        [self setupLayerAndContext];
        [self setupBuffers];
        [self setupProgram];
        [self render];
        
    }
    return self;
}
代码语言:javascript
复制
+(Class)layerClass{
    //OpenGL内容只会在此类layer上描绘
    return [CAEAGLLayer class];
}

- (void)setupLayerAndContext
{
    _eaglLayer = (CAEAGLLayer*) self.layer;
    
    // CALayer 默认是透明的,必须将它设为不透明才能让其可见,性能最好
    _eaglLayer.opaque = YES;
    
    // 设置描绘属性,在这里设置不维持渲染内容以及颜色格式为 RGBA8
    _eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                     [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
    
    // 指定 OpenGLES 渲染API的版本,在这里我们使用OpenGLES 3.0,由于3.0兼容2.0并且功能更强,为何不用更好的呢,不过注意:3.0支持的手机最低为5s,系统最低为iOS7
    EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES3;
    _context = [[EAGLContext alloc] initWithAPI:api];
    if (!_context) {
        NSLog(@"Failed to initialize OpenGLES 3.0 context");
    }
    
    // 设置为当前上下文
    [EAGLContext setCurrentContext:_context];
}

-(void)setupBuffers{
//    1.depth
    glGenRenderbuffers(1, &_depthBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, _depthBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, self.frame.size.width, self.frame.size.height);
    
//    2.color
    glGenRenderbuffers(1, &_colorBuffer); //生成和绑定render buffer的API函数
    glBindRenderbuffer(GL_RENDERBUFFER, _colorBuffer);
    //为其分配空间
    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
    
//    3.frame
    glGenFramebuffers(1, &_frameBuffer);   //生成和绑定frame buffer的API函数
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
    //将renderbuffer跟framebuffer进行绑定
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorBuffer);
    //将depthBuffer跟frame buffer进行绑
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer);

}

上面所涉及的变量都在类声明的扩展中定义,以下是全部变量定义:

代码语言:javascript
复制
@interface NewOpenGLView ()
{
    CAEAGLLayer *_eaglLayer;
    EAGLContext *_context;
    GLuint _depthBuffer;
    GLuint _colorBuffer;
    GLuint _frameBuffer;
    
    GLuint _programHandle; //着色器程序
    GLuint _positionSlot; //顶点槽位
    GLuint _colorSlot;   //颜色槽位
    GLuint _projectionSlot;  //投影矩阵槽位
    GLuint _modelViewSlot;   //模型矩阵槽位
    GLKMatrix4 _projectionMatrix; //投影矩阵
    GLKMatrix4 _modelViewMatrix;  //模型(其实是观察)矩阵
    
    //纹理
    GLuint _textureProgram;
    GLuint _texPositionSlot; //顶点槽位
    GLuint _texCoordSlot;   //纹理坐标槽位
    GLuint _ourTextureSlot; //纹理采样对象槽位
    GLuint _texProjectionSlot;  //投影矩阵槽位
    GLuint _texModelViewSlot;   //模型矩阵槽位
    GLKMatrix4 _texProjectionMatrix; //投影矩阵
    GLKMatrix4 _texModelViewMatrix;  //模型(其实是观察)矩阵
    
    //3个纹理对象
    GLuint _textureID1;  //纹理对象
    GLuint _textureID2;  //纹理对象
    GLuint _textureID3;  //纹理对象
}
@end

Demo中还使用了入门篇中详细介绍过的2个工具类: GLESUtils类 :配置着色器程序 TextureManager类 :配置纹理图片

接下来我们介绍如何配置着色器程序: 在入门篇里,我们要么只绘制图形,要么只绘制纹理,没有把它们结合起来绘制过,而这里我们需要把他们结合起来绘制。这个时候,glsl语言的写法就有区别了,可以把它们写在同一个文件里,也可以分别写出来,这里我是分别写出了图形所对应的VertexShader.glsl、FragmentShader.glsl和纹理所对应的TextureVertex.glsl、TextureFragment.glsl。

先来介绍绘制图形的glsl语言(Vertex和Fragment):

代码语言:javascript
复制
uniform mat4 projection;
uniform mat4 modelView;

attribute vec4 vPosition;

attribute vec4 vSourceColor;
varying vec4 vDestinationColor;

void main(void)
{
    gl_Position = projection * modelView * vPosition;
    vDestinationColor = vSourceColor;
}
代码语言:javascript
复制
precision medium float;

varying vec4 vDestinationColor;

void main()
{
    gl_FragColor = vDestinationColor;
}

关于shader语言这里就不多赘述了。 然后我们配置图形着色器程序:

代码语言:javascript
复制
-(void)setupProgram{
    //1.多边体program
    NSString *vertexShaderPath   = [[NSBundle mainBundle] pathForResource:@"VertexShader"
                                          ofType:@"glsl"];
    NSString *fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@"FragmentShader"
                                                                    ofType:@"glsl"];
    _programHandle = [GLESUtils loadProgram:vertexShaderPath withFragmentShaderFilepath:fragmentShaderPath];
    
    //获取槽位
    _positionSlot   = glGetAttribLocation(_programHandle, "vPosition");
    _colorSlot      = glGetAttribLocation(_programHandle, "vSourceColor");
    _projectionSlot = glGetUniformLocation(_programHandle, "projection");
    _modelViewSlot  = glGetUniformLocation(_programHandle, "modelView");
    
    glEnableVertexAttribArray(_positionSlot);
    glEnableVertexAttribArray(_colorSlot);
}

着色器程序配置好,我们还需设置着色器里的投影矩阵和观察矩阵(这里是观察矩阵,根据功能理解为模型矩阵其实也没差):

代码语言:javascript
复制
-(void)setupProjectionMatrixAndModelViewMatrix{
    //1.多边体
    float aspect = self.frame.size.width/self.frame.size.height;
    _projectionMatrix = GLKMatrix4MakePerspective(45.0*M_PI/180.0, aspect, 0.1, 100);
    glUniformMatrix4fv(_projectionSlot, 1, GL_FALSE, _projectionMatrix.m);
    
    _modelViewMatrix = GLKMatrix4MakeTranslation(0, 0, -5); //平移
    _modelViewMatrix = GLKMatrix4RotateX(_modelViewMatrix, 0.6);  //旋转X轴,0.6是弧度值
    glUniformMatrix4fv(_modelViewSlot, 1, GL_FALSE, _modelViewMatrix.m);
}

做完这些,我们就可以开始绘制了:

代码语言:javascript
复制
-(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);
     */
    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // Setup viewport
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);

    [_context presentRenderbuffer:_colorBuffer];
}

做到这里,我们运行Demo,得到的结果应该是这样的:

初始结果.png

下面我们开始构造立体多边形的数据(x,y,z,r,g,b,a)并绘制出来(Demo使用最基本的数据格式,如需优化,请自行构造buffer、VAO):

代码语言:javascript
复制
-(void)drawFirstCube{
    //顶点数据
    GLfloat ver[] = {
        -0.508680,0.260000,-0.725382,0.345678,0.678943,0.812332,0.900000,
        0.306216,0.260000,-0.725382,0.345678,0.678943,0.812332,0.900000,
        0.306216,0.260000,-0.244226,0.345678,0.678943,0.812332,0.900000,
        -0.508680,0.260000,-0.244226,0.345678,0.678943,0.812332,0.900000,
        -0.508680,0.010000,-0.725382,0.345678,0.678943,0.812332,0.900000,
        0.306216,0.010000,-0.725382,0.345678,0.678943,0.812332,0.900000,
        0.306216,0.010000,-0.244226,0.345678,0.678943,0.812332,0.900000,
        -0.508680,0.010000,-0.244226,0.345678,0.678943,0.812332,0.900000,
    };
    
    //顶面和底面索引
    GLubyte ind_top[] = {
        3,0,1,1,2,3,
    };
    
    GLubyte ind_bot[] = {//+4是因为数据是顶面底面一起的,顶面数据4个,底面4个
        3+4,0+4,1+4,1+4,2+4,3+4,
    };
    
    //侧面索引
    GLubyte side[] = {
        0,4,1,5,2,6,3,7,0,4,
    };
    
    //    绘制
    //    顶面
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver+3);
    glDrawElements(GL_TRIANGLES, sizeof(ind_top)/sizeof(GLubyte), GL_UNSIGNED_BYTE, ind_top);
    
    //    底面
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver+3);
    glDrawElements(GL_TRIANGLES, sizeof(ind_bot)/sizeof(GLubyte), GL_UNSIGNED_BYTE, ind_bot);
    
    //    侧面
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver+3);
    glDrawElements(GL_TRIANGLE_STRIP, sizeof(side)/sizeof(GLubyte), GL_UNSIGNED_BYTE, side);
    
    //需要画的线  顶面和底面线
    GLfloat line[] = {
        -0.508680,0.260000,-0.725382,0.965789,0.677845,0.812332,1.0,
        0.306216,0.260000,-0.725382,0.965789,0.677845,0.812332,1.0,
        0.306216,0.260000,-0.244226,0.965789,0.677845,0.812332,1.0,
        -0.508680,0.260000,-0.244226,0.965789,0.677845,0.812332,1.0,
        -0.508680,0.010000,-0.725382,0.965789,0.677845,0.812332,1.0,
        0.306216,0.010000,-0.725382,0.965789,0.677845,0.812332,1.0,
        0.306216,0.010000,-0.244226,0.965789,0.677845,0.812332,1.0,
        -0.508680,0.010000,-0.244226,0.965789,0.677845,0.812332,1.0,
    };
    
    GLubyte line_top[] = {
        0,1,2,3,
    };
    
    GLubyte line_bot[] = { //+4是因为数据是顶面底面一起的,顶面数据4个,底面4个
        0+4,1+4,2+4,3+4,
    };
    
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), line);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), line+3);
    glDrawElements(GL_LINE_LOOP, sizeof(line_top)/sizeof(GLubyte), GL_UNSIGNED_BYTE, line_top);
    
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), line);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), line+3);
    glDrawElements(GL_LINE_LOOP, sizeof(line_bot)/sizeof(GLubyte), GL_UNSIGNED_BYTE, line_bot);

}

数据不算太复杂,太复杂了我也没想法去处理构造它,在顶点数据中,我们集合了顶面顶点数据和底面顶点数据,然后分别构造出它顶面和底面需要绘制的三角形索引,最后还有它需要绘制的侧面的所有三角形索引。 绘制的时候根据顶面、底面、侧面使用合适的glDraw方法绘制,为什么后面还会绘制顶面和底面的线呢,这是因为如果不绘制线的话,绘出来结果会不够理想,让人区分不出来这是立方体。

不画线.png

画线.png

然后我们以同样的方式分别绘制第二、第三个多边体:

代码语言:javascript
复制
-(void)drawSecondCube{

    //顶点数据
    GLfloat ver[] = {
        -0.304217,0.260000,0.814439,0.345678,0.678943,0.465789,0.900000,
        -0.304217,0.260000,0.344297,0.345678,0.678943,0.465789,0.900000,
        0.429602,0.260000,0.344297,0.345678,0.678943,0.465789,0.900000,
        0.426395,0.260000,0.718223,0.345678,0.678943,0.465789,0.900000,
        0.169820,0.260000,0.718223,0.345678,0.678943,0.465789,0.900000,
        0.169820,0.260000,0.814439,0.345678,0.678943,0.465789,0.900000,
        -0.304217,0.010000,0.814439,0.345678,0.678943,0.465789,0.900000,
        -0.304217,0.010000,0.344297,0.345678,0.678943,0.465789,0.900000,
        0.429602,0.010000,0.344297,0.345678,0.678943,0.465789,0.900000,
        0.426395,0.010000,0.718223,0.345678,0.678943,0.465789,0.900000,
        0.169820,0.010000,0.718223,0.345678,0.678943,0.465789,0.900000,
        0.169820,0.010000,0.814439,0.345678,0.678943,0.465789,0.900000,
    };
    
    //顶面和底面索引
    GLubyte ind_top[] = {
        5,0,1,1,2,3,4,5,1,1,3,4,
    };
    
    GLubyte ind_bot[] = {
        5+6,0+6,1+6,1+6,2+6,3+6,4+6,5+6,1+6,1+6,3+6,4+6,
    };
    
    //侧面索引
    GLubyte side[] = {
        0,6,1,7,2,8,3,9,4,10,5,11,0,6,
    };
    
    //    绘制
    //    顶面
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver+3);
    glDrawElements(GL_TRIANGLES, sizeof(ind_top)/sizeof(GLubyte), GL_UNSIGNED_BYTE, ind_top);
    
    //    底面
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver+3);
    glDrawElements(GL_TRIANGLES, sizeof(ind_bot)/sizeof(GLubyte), GL_UNSIGNED_BYTE, ind_bot);
    
    //    侧面
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver+3);
    glDrawElements(GL_TRIANGLE_STRIP, sizeof(side)/sizeof(GLubyte), GL_UNSIGNED_BYTE, side);
    
    //需要画的线
    GLfloat line[] = {
        -0.304217,0.260000,0.814439,0.965789,0.678943,0.465789,1.000000,
        -0.304217,0.260000,0.344297,0.965789,0.678943,0.465789,1.000000,
        0.429602,0.260000,0.344297,0.965789,0.678943,0.465789,1.000000,
        0.426395,0.260000,0.718223,0.965789,0.678943,0.465789,1.000000,
        0.169820,0.260000,0.718223,0.965789,0.678943,0.465789,1.000000,
        0.169820,0.260000,0.814439,0.965789,0.678943,0.465789,1.000000,
        -0.304217,0.010000,0.814439,0.965789,0.678943,0.465789,1.000000,
        -0.304217,0.010000,0.344297,0.965789,0.678943,0.465789,1.000000,
        0.429602,0.010000,0.344297,0.965789,0.678943,0.465789,1.000000,
        0.426395,0.010000,0.718223,0.965789,0.678943,0.465789,1.000000,
        0.169820,0.010000,0.718223,0.965789,0.678943,0.465789,1.000000,
        0.169820,0.010000,0.814439,0.965789,0.678943,0.465789,1.000000,
    };
    
    GLubyte line_top[] = {
        0,1,2,3,4,5,
    };
    
    GLubyte line_bot[] = {
        0+6,1+6,2+6,3+6,4+6,5+6,
    };
    
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), line);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), line+3);
    glDrawElements(GL_LINE_LOOP, sizeof(line_top)/sizeof(GLubyte), GL_UNSIGNED_BYTE, line_top);
    
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), line);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), line+3);
    glDrawElements(GL_LINE_LOOP, sizeof(line_bot)/sizeof(GLubyte), GL_UNSIGNED_BYTE, line_bot);

}

-(void)drawThirdCube{
    //顶点数据
    GLfloat ver[] = {
        0.306216,0.260000,-0.725382,0.778943,0.378943,0.465789,0.900000,
        0.429602,0.260000,-0.725382,0.778943,0.378943,0.465789,0.900000,
        0.602136,0.260000,-0.725382,0.778943,0.378943,0.465789,0.900000,
        0.602136,0.260000,-0.816786,0.778943,0.378943,0.465789,0.900000,
        0.987652,0.260000,-0.816786,0.778943,0.378943,0.465789,0.900000,
        0.987652,0.260000,-0.430321,0.778943,0.378943,0.465789,0.900000,
        0.901058,0.260000,-0.430321,0.778943,0.378943,0.465789,0.900000,
        0.901058,0.260000,-0.319931,0.778943,0.378943,0.465789,0.900000,
        0.622946,0.260000,-0.319931,0.778943,0.378943,0.465789,0.900000,
        0.306216,0.260000,-0.319931,0.778943,0.378943,0.465789,0.900000,
        0.306216,0.010000,-0.725382,0.778943,0.378943,0.465789,0.900000,
        0.429602,0.010000,-0.725382,0.778943,0.378943,0.465789,0.900000,
        0.602136,0.010000,-0.725382,0.778943,0.378943,0.465789,0.900000,
        0.602136,0.010000,-0.816786,0.778943,0.378943,0.465789,0.900000,
        0.987652,0.010000,-0.816786,0.778943,0.378943,0.465789,0.900000,
        0.987652,0.010000,-0.430321,0.778943,0.378943,0.465789,0.900000,
        0.901058,0.010000,-0.430321,0.778943,0.378943,0.465789,0.900000,
        0.901058,0.010000,-0.319931,0.778943,0.378943,0.465789,0.900000,
        0.622946,0.010000,-0.319931,0.778943,0.378943,0.465789,0.900000,
        0.306216,0.010000,-0.319931,0.778943,0.378943,0.465789,0.900000,
    };
    
    //顶面和底面索引
    GLubyte ind_top[] = {
        9,0,1,2,3,4,4,5,6,6,7,8,8,9,1,2,4,6,6,8,1,1,2,6,
    };
    
    GLubyte ind_bot[] = {
        9+10,0+10,1+10,2+10,3+10,4+10,4+10,5+10,6+10,6+10,7+10,8+10,8+10,9+10,1+10,2+10,4+10,6+10,6+10,8+10,1+10,1+10,2+10,6+10,
    };
    
    //侧面索引
    GLubyte side[] = {
        0,10,1,11,2,12,3,13,4,14,5,15,6,16,7,17,8,18,9,19,0,10,
    };
    
    //    绘制
    //    顶面
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver+3);
    glDrawElements(GL_TRIANGLES, sizeof(ind_top)/sizeof(GLubyte), GL_UNSIGNED_BYTE, ind_top);
    
    //    底面
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver+3);
    glDrawElements(GL_TRIANGLES, sizeof(ind_bot)/sizeof(GLubyte), GL_UNSIGNED_BYTE, ind_bot);
    
    //    侧面
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), ver+3);
    glDrawElements(GL_TRIANGLE_STRIP, sizeof(side)/sizeof(GLubyte), GL_UNSIGNED_BYTE, side);
    
    //需要画的线
    GLfloat line[] = {
        0.306216,0.260000,-0.725382,0.345678,0.678943,0.465789,1.000000,
        0.429602,0.260000,-0.725382,0.345678,0.678943,0.465789,1.000000,
        0.602136,0.260000,-0.725382,0.345678,0.678943,0.465789,1.000000,
        0.602136,0.260000,-0.816786,0.345678,0.678943,0.465789,1.000000,
        0.987652,0.260000,-0.816786,0.345678,0.678943,0.465789,1.000000,
        0.987652,0.260000,-0.430321,0.345678,0.678943,0.465789,1.000000,
        0.901058,0.260000,-0.430321,0.345678,0.678943,0.465789,1.000000,
        0.901058,0.260000,-0.319931,0.345678,0.678943,0.465789,1.000000,
        0.622946,0.260000,-0.319931,0.345678,0.678943,0.465789,1.000000,
        0.306216,0.260000,-0.319931,0.345678,0.678943,0.465789,1.000000,
        0.306216,0.010000,-0.725382,0.345678,0.678943,0.465789,1.000000,
        0.429602,0.010000,-0.725382,0.345678,0.678943,0.465789,1.000000,
        0.602136,0.010000,-0.725382,0.345678,0.678943,0.465789,1.000000,
        0.602136,0.010000,-0.816786,0.345678,0.678943,0.465789,1.000000,
        0.987652,0.010000,-0.816786,0.345678,0.678943,0.465789,1.000000,
        0.987652,0.010000,-0.430321,0.345678,0.678943,0.465789,1.000000,
        0.901058,0.010000,-0.430321,0.345678,0.678943,0.465789,1.000000,
        0.901058,0.010000,-0.319931,0.345678,0.678943,0.465789,1.000000,
        0.622946,0.010000,-0.319931,0.345678,0.678943,0.465789,1.000000,
        0.306216,0.010000,-0.319931,0.345678,0.678943,0.465789,1.000000,
    };
    
    GLubyte line_top[] = {
        0,1,2,3,4,5,6,7,8,9,
    };
    
    GLubyte line_bot[] = {
        0+10,1+10,2+10,3+10,4+10,5+10,6+10,7+10,8+10,9+10,
    };
    
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), line);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), line+3);
    glDrawElements(GL_LINE_LOOP, sizeof(line_top)/sizeof(GLubyte), GL_UNSIGNED_BYTE, line_top);
    
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), line);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), line+3);
    glDrawElements(GL_LINE_LOOP, sizeof(line_bot)/sizeof(GLubyte), GL_UNSIGNED_BYTE, line_bot);

}

我们在render方法里调用方法绘制这三个多边体,这时render该是这样的:

代码语言:javascript
复制
-(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);
     */
    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // Setup viewport
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);
    
    //开启深度测试
    glEnable(GL_DEPTH_TEST);
    //绘制3个多边体
    glUseProgram(_programHandle);
    [self setupProjectionMatrixAndModelViewMatrix];
    [self drawFirstCube];
    [self drawSecondCube];
    [self drawThirdCube];

    [_context presentRenderbuffer:_colorBuffer];
}

我们在绘制多边体前先开启了深度测试,然后使用多边体着色器程序,再配置多边体的投影和观察矩阵,注意每次使用program后需要重新配置矩阵。 做完这些,运行结果如下:

三个多边体.png

绘制纹理

然后...我们再把纹理绘制上去,要绘纹理,我们得设置纹理的着色器语言(Vertex和Fragment):

代码语言:javascript
复制
attribute vec4 Position;

attribute vec2 TexCoordIn;
varying vec2 TexCoordOut;

uniform mat4 Projection;
uniform mat4 ModelView;

void main(){

    gl_Position = Projection * ModelView * Position;

    TexCoordOut = vec2(TexCoordIn.x, TexCoordIn.y);
}
代码语言:javascript
复制
uniform sampler2D ourTexture;

varying mediump vec2 TexCoordOut;

void main(){
    gl_FragColor = texture2D(ourTexture, TexCoordOut);
}

然后代码配置着色器程序,整个setupProgram方法变为:

代码语言:javascript
复制
-(void)setupProgram{
    //1.多边体program
    NSString *vertexShaderPath   = [[NSBundle mainBundle] pathForResource:@"VertexShader"
                                          ofType:@"gals"];
    NSString *fragmentShaderPath = [[NSBundle mainBundle] pathForResource:@"FragmentShader"
                                                                    ofType:@"gals"];
    _programHandle = [GLESUtils loadProgram:vertexShaderPath withFragmentShaderFilepath:fragmentShaderPath];
    
    //获取槽位
    _positionSlot   = glGetAttribLocation(_programHandle, "vPosition");
    _colorSlot      = glGetAttribLocation(_programHandle, "vSourceColor");
    _projectionSlot = glGetUniformLocation(_programHandle, "projection");
    _modelViewSlot  = glGetUniformLocation(_programHandle, "modelView");
    
    glEnableVertexAttribArray(_positionSlot);
    glEnableVertexAttribArray(_colorSlot);
    
    
//    ------------------------------------------------------------------------
    
    //2.纹理program
    NSString *texVertexPath   = [[NSBundle mainBundle] pathForResource:@"TextureVertex"
                                                                 ofType:@"glsl"];
    NSString *texFragmentPath = [[NSBundle mainBundle] pathForResource:@"TextureFragment"
                                                                   ofType:@"glsl"];
    _textureProgram = [GLESUtils loadProgram:texVertexPath withFragmentShaderFilepath:texFragmentPath];
    
    //获取槽位
    _texPositionSlot = glGetAttribLocation(_textureProgram, "Position");
    _texCoordSlot    = glGetAttribLocation(_textureProgram, "TexCoordIn");
    glEnableVertexAttribArray(_texPositionSlot);
    glEnableVertexAttribArray(_texCoordSlot);
    
    _ourTextureSlot    = glGetUniformLocation(_textureProgram, "ourTexture");
    _texProjectionSlot = glGetUniformLocation(_textureProgram, "Projection");
    _texModelViewSlot  = glGetUniformLocation(_textureProgram, "ModelView");
    
    //获取纹理对象
    _textureID1 = [TextureManager getTextureImage:[UIImage imageNamed:@"猫头鹰"]];
    _textureID2 = [TextureManager getTextureImage:[UIImage imageNamed:@"乌龟"]];
    _textureID3 = [TextureManager getTextureImage:[UIImage imageNamed:@"变色龙"]];
}

接着新建一个方法来配置纹理的投影和观察矩阵:

代码语言:javascript
复制
-(void)setupTextureProjectionMatrixAndModelViewMatrix{
    //2.纹理
    float aspect = self.frame.size.width/self.frame.size.height;
    _texProjectionMatrix = GLKMatrix4MakePerspective(45.0*M_PI/180.0, aspect, 0.1, 100);
    glUniformMatrix4fv(_texProjectionSlot, 1, GL_FALSE, _texProjectionMatrix.m);
    
    _texModelViewMatrix = GLKMatrix4MakeTranslation(0, 0, -5); //平移
    _texModelViewMatrix = GLKMatrix4RotateX(_texModelViewMatrix, 1.4);  //旋转X轴
    glUniformMatrix4fv(_texModelViewSlot, 1, GL_FALSE, _texModelViewMatrix.m);
}

再接下来,我们就需要构造纹理数据并绘制出来了,对于纹理顶点的坐标数据,由于不知道多边体的中心点在何处,我就自己构造了:

代码语言:javascript
复制
//    第一个
    GLfloat vertices1[] = {
        //   x    y    z
        -0.9,  0.3, -0.9,  //左下
        -0.6,  0.3, -0.9,  //右下
        -0.9,  0.3, -0.6,  //左上
        -0.6,  0.3, -0.6,  //右上
    };
    
    //    第二个
    GLfloat vertices2[] = {
        //   x    y    z
        -0.5,  0.3, -0.5,  //左下
        -0.2,  0.3, -0.5,  //右下
        -0.5,  0.3, -0.2,  //左上
        -0.2,  0.3, -0.2,  //右上
    };
    
    //    第三个
    GLfloat vertices3[] = {
    //   x    y    z
        -0.9,  0.3, -0.1,  //左下
        -0.6,  0.3, -0.1,  //右下
        -0.9,  0.3, 0.2,  //左上
        -0.6,  0.3, 0.2,  //右上
    };

而对于纹理的纹理坐标数据,都是:

代码语言:javascript
复制
//纹理4个顶点对应纹理坐标,三个都是一样的
    GLfloat textureCoord[] = {
        0, 0,
        1, 0,
        0, 1,
        1, 1,
    };

整个方法里构造加上绘制,代码如下:

代码语言:javascript
复制
//绘制纹理
-(void)drawTextrue{
//    构造3个纹理的顶点坐标
    //四个顶点(分别表示xyz轴)

    //    第一个
    GLfloat vertices1[] = {
        //   x    y    z
        -0.9,  0.3, -0.9,  //左下
        -0.6,  0.3, -0.9,  //右下
        -0.9,  0.3, -0.6,  //左上
        -0.6,  0.3, -0.6,  //右上
    };
    
    //    第二个
    GLfloat vertices2[] = {
        //   x    y    z
        -0.5,  0.3, -0.5,  //左下
        -0.2,  0.3, -0.5,  //右下
        -0.5,  0.3, -0.2,  //左上
        -0.2,  0.3, -0.2,  //右上
    };
    
    //    第三个
    GLfloat vertices3[] = {
    //   x    y    z
        -0.9,  0.3, -0.1,  //左下
        -0.6,  0.3, -0.1,  //右下
        -0.9,  0.3, 0.2,  //左上
        -0.6,  0.3, 0.2,  //右上
    };
    
    //纹理4个顶点对应纹理坐标,三个都是一样的
    GLfloat textureCoord[] = {
        0, 0,
        1, 0,
        0, 1,
        1, 1,
    };

    //绘制
    glVertexAttribPointer(_texPositionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices1);
    glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, 0, textureCoord);
    //使用纹理单元
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, _textureID1);
    glUniform1i(_ourTextureSlot, 0);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
    glVertexAttribPointer(_texPositionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices2);
    glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, 0, textureCoord);
    //使用纹理单元
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, _textureID2);
    glUniform1i(_ourTextureSlot, 0);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
    glVertexAttribPointer(_texPositionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices3);
    glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, 0, textureCoord);
    //使用纹理单元
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, _textureID3);
    glUniform1i(_ourTextureSlot, 0);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
}

然后我们在render方法里调用纹理绘制的方法:

代码语言:javascript
复制
//绘制纹理
    glUseProgram(_textureProgram);
    [self setupTextureProjectionMatrixAndModelViewMatrix];
    [self drawTextrue];

得到最终的绘制结果:

最终结果.png

从上面的图片我们能看出来,效果是不够好的,比如边、线锯齿,多边体和纹理模糊,也没有进行矩阵变换重绘等问题,这些涉及到公司产品的竞争,我目前不会分享出来,还请自行寻找解决方案。

最后,给出整个个Demo的目录结构吧

整个Demo目录结构.png

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.02.07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 绘制立体多边形
  • 绘制纹理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档