美文网首页
GLKit加载图片(非UIImageview)

GLKit加载图片(非UIImageview)

作者: 尤先森 | 来源:发表于2019-06-05 11:49 被阅读0次

    GLKit简介

    GLKit 框架的设计目标是为了简化基于OpenGL / OpenGL ES 的应用开发 。它的出现加快了OpenGL ES或OpenGL应用程序开发。 使用数学库,背景纹理加载,预先创建的着⾊器效果,以及标准视图和视图控制器来实现渲染循环。

    GLKit框架提供了功能和类,可以减少创建新的基于着⾊器的应⽤程序所需的工作量, 或者支持依赖早期版本的OpenGL ES或OpenGL提供的固定函数顶点或片段处理的现有应用程序。

    总的来说,GLKit就是用更友好的语法便于开发者开发基于OpenGL / OpenGL ES 的应用。

    EGL & EAGL 简介

    OpenGL ES 命令需要渲染上下文和绘制表面才能完成图形图像的绘制,由于OpenGL ES API 没有提供创建渲染上下文或者上下文连接到原生窗口系统,于是就有了EGL。EGL是Khronos 渲染API(如OpenGL ES) 和原⽣窗口系统之间的接口。
    iOS支持OpenGL ES但却不⽀持EGL。Apple 为iOS提供⾃己的EGL API,称为EAGL。

    EGL的主要功能如下:
    1. 和本地窗⼝系统(native windowing system)通讯;
    2. 查询可⽤的配置;
    3. 创建OpenGL ES可⽤用的“绘图表面”(drawing surface);
    4. 同步不同类别的API之间的渲染,⽐如在OpenGL ES和OpenVG之间同步,或者在OpenGL和本地窗口的绘图命令之间;
    5. 管理“渲染资源”,⽐如纹理映射(rendering map)。

    说明

    这次要做的东西,效果看起来很简单,就只是加载一张图片到屏幕上。当然,如果用UIImageView来加载,那就没有写这篇文章的必要的。这次是用GLKit加载图片。

    GLKit加载图片.png

    初始化

    1. 创建viewController,继承UIViewController
    2. import
    #import <GLKit/GLKit.h>
    #import <OpenGLES/ES3/gl.h>
    #import <OpenGLES/ES3/glext.h>
    
    3. 变量声明

    这里声明属性也是可以的。

    @interface GLKitViewController ()<GLKViewDelegate>
    {
        //绘制视图内容时使⽤用的OpenGL ES 上下⽂文
        EAGLContext *context;
        //⼀种简单光照/着⾊系统,⽤于基于着⾊器OpenGL 渲染
        GLKBaseEffect *effect;
    }
    @end
    
    4. 创建EAGLContext并设置当前的context
        context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES3];
        if (!context) {
            return;
        }
        [EAGLContext setCurrentContext:context];
    
    5. 创建GLKView 并且initWithContext并且遵循GLKViewDelegate
        GLKView *view = [[GLKView alloc]initWithFrame:self.view.bounds context:context];
        view.delegate = self;
        self.view = view;
    
    6. 设置背景颜色

    一般情况,我们为一个View设置背景颜色都是直接view.backgroundColor,
    但是对于GLKView并不管用,正确的使用方式是我们在前几篇文章中经常用到的一个方法glClearColor(r,g,b,a)

    glClearColor(0.8, 0.8, 0.8, 1);
    

    设置顶点数据

    1.顶点数组

    开发者可以选择设定函数指针,在调用绘制方法的时候,直接由内存传入顶点数据,也就是说这部分数据之前是存储在内存当中的,被称为顶点数组。

    每一行的前三个数据代表一个顶点坐标(x,y,z)。
    后两个数据代表纹理坐标
    纹理坐标系取值范围为[0,1],原点是左下角(0,0);
    故而(0,0)是纹理图像的左下角, 点(1,1)是右上角。

    这次要绘制的图形是一个方形,一个方形由两个三角形组成,两个三角形则有6个顶点组成。

         GLfloat vertexData[] = {
            0.5, -0.25, 0.0f,    1.0f, 0.0f, //右下
            0.5, 0.25, -0.0f,    1.0f, 1.0f, //右上
            -0.5, 0.25, 0.0f,    0.0f, 1.0f, //左上
            
            0.5, -0.25, 0.0f,    1.0f, 0.0f, //右下
            -0.5, 0.25, 0.0f,    0.0f, 1.0f, //左上
            -0.5, -0.25, 0.0f,   0.0f, 0.0f, //左下
        };
    
    2.开辟顶点缓冲区
        //(1).创建顶点缓冲区标识符
        GLuint bufferID;
        glGenBuffers(1, &bufferID);
        //(2).绑定顶点缓冲区
        glBindBuffer(GL_ARRAY_BUFFER, bufferID);
        //(3).将顶点数组的数据copy到顶点缓冲区中
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
    
    3.读取顶点数据、纹理数据

    glEnableVertexAttribArray(GLuint index)
    在iOS中, 默认情况下,出于性能考虑,所有顶点着色器的属性(Attribute)变量都是关闭的。
    意味着我们使用glBufferData方法,将顶点数据从内存拷贝到顶点缓冲区中,顶点数据在着色器中是不可用的。
    所以, 必须由glEnableVertexAttribArray 方法打开通道。指定访问属性.才能让顶点着色器能够访问到从CPU复制到GPU的数据。

    glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid ptr)

    这个方法百度百科有介绍,可以点这里看看

    • 功能:
      上传顶点数据到显存的方法(设置合适的方式从buffer里面读取数据)
    • 参数说明:
      • index:指定要修改的顶点属性的索引值,这里与glEnableVertexAttribArray中的参数保持一致即可。
      • size:每次读取数量。如position是由3个(x,y,z)组成,而颜色是4个(r,g,b,a),纹理则是2个
      • type:指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED,GL_FLOAT,初始值为GL_FLOAT
      • normalized:指定当被访问时,固定点数据值是否应该被归一化(GL_TRUE)或者直接转换为固定点值(GL_FALSE),一般直接用GL_FALSE
      • stride :指定连续顶点属性之间的偏移量。可以理解为从第一个x坐标到第二个x坐标要跨越几个参数,例如在本案例中,就需要跨越5个参数。
      • ptr:指定一个指针,指向数组中第一个顶点属性的第一个组件。可以这么理解,我们当前读取的是顶点坐标,那么顶点坐标从第一个就开始了,就是0,如果要读取的是纹理坐标,那么就是3
        glEnableVertexAttribArray(GLKVertexAttribPosition);
        glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE,sizeof(GLfloat)* 5,(GLfloat *)NULL + 0);
        
        glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
        glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)* 5, (GLfloat *)NULL + 3);
    

    tips:参数务必老老实实照着写,要不然就会不出效果...

    读取并设置纹理

    相关属性

    1.获取纹理(图片)路径
        NSString *path = [[NSBundle mainBundle]pathForResource:@"test" ofType:@"png"];
    
    2.设置纹理属性

    纹理坐标原点是左下角,但是图片显示原点应该是左上角。

    NSDictionary *option = @{GLKTextureLoaderOriginBottomLeft:@(YES)};
    
    3.通过GLKTextureLoader加载GLKTextureInfo

    GLKTextureInfo : OpenGL 纹理信息

    • name : OpenGL 上下文中纹理名称
    • target : 纹理绑定的⽬目标
    • height : 加载的纹理高度
    • width : 加载纹理的宽度
    • textureOrigin : 加载纹理中的原点位置
    • alphaState: 加载纹理中alpha分量状态
    • containsMipmaps: 布尔值,加载的纹理是否包含mip贴图

    GLTextureLoader :从各种资源文件中加载纹理(相对于OpenGL加载方便了非常多)

        //从⽂件加载2D纹理图像并从数据中创建新的纹理
        GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:path options:dic error:nil];
    
    4.使用GLKit 提供GLKBaseEffect 完成着色器工作(顶点/片元)
    effect = [[GLKBaseEffect alloc]init];
    effect.texture2d0.enabled = GL_TRUE;
    effect.texture2d0.name = textureInfo.name;
    

    GLKViewDelegate

    绘制视图的内容
    GLKView对象使其OpenGL ES上下文成为当前上下文,并将其framebuffer绑定为OpenGL ES呈现命令的目标。然后,委托方法应该绘制视图的内容。

    glDrawArrays(GLenum mode, GLint first, GLsizei count)
    参数说明

    • mode:绘制方式,OpenGL2.0以后提供以下参数:GL_POINTS、GL_LINES、GL_LINE_LOOP、GL_LINE_STRIP、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN
    • first:从数组缓冲中的哪一位开始绘制,一般为0。
    • count:数组中顶点的数量。
    -(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
        //清除缓冲区
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        //准备绘制
        [effect prepareToDraw];
        //绘制
        glDrawArrays(GL_TRIANGLES, 0, 6);  
    }
    

    以上,便是用GLKit加载图片的全部流程。

    最终效果

    image.png

    相关文章

      网友评论

          本文标题:GLKit加载图片(非UIImageview)

          本文链接:https://www.haomeiwen.com/subject/ocqjxctx.html