美文网首页
OpenGL-ES 纹理的实现

OpenGL-ES 纹理的实现

作者: LoveToday2020 | 来源:发表于2019-12-15 22:12 被阅读0次

    首先先看一下实现的效果吧

    最终实现的效果图

    原图是一张完整的图,我们把原图做成一个四宫格的样式,当然了,9宫格也是同样的道理

    实现的过程

    步骤一:初始化

    - (instancetype)initWithFrame:(CGRect)frame

    {

        self= [superinitWithFrame:frame];

        if(self) {

            /// 设置显示层

            [selfsetUpLayer];

            /// 设置上下文

            [self setUpContext];

            [self setUpProgram];

            [selfsetupVBO];

            [self setUpTexture];

        }

        return self;

    }

    其中Opengl的显示使用CAEAGLLayer来绘制完成,它是CALayer的一个子类,用来显示任意的OpenGL图形。

    + (Class)layerClass{

        return [CAEAGLLayer class];

    }

    对于CAEAGLLayer的属性配置

    - (void)setUpLayer{

        myLayer = (CAEAGLLayer *)self.layer;

        myLayer.opaque=YES;

        myLayer.drawableProperties = @{

                                       kEAGLDrawablePropertyRetainedBacking:@NO,

                                       kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8

                                       };

    }

    - (void)layoutSubviews{

        [super layoutSubviews];

        [EAGLContext setCurrentContext:myContext];

        [self destoryRenderAndFrameBuffer];

        [self setUpBuffer];

       [selfrender];

    }

    EAGLContext

    在iOS应用程序中,每个线程都会维护一个当前的上下文,在使用Opengl-ES进行绘制时也不例外,Opengl-es是使用EAGLContext进行管理上下文的,一看名字就能知道了,相当好记。当然了,这其中也要对Opengl版本的设置

    - (void)setUpContext{

        myContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];

        if(myContext==nil) {

            NSLog(@"初始化上下文失败");

            return;

        }

        if (![EAGLContext setCurrentContext:myContext]) {

            NSLog(@"设置上下文失败");

            return;

        }

    }

    清除缓冲空间

    - (void)destoryRenderAndFrameBuffer {

        glDeleteFramebuffers(1, &myColorFrameBuffer);

        myColorFrameBuffer = 0;

        glDeleteRenderbuffers(1, &myColorRenderBuffer);

        myColorRenderBuffer = 0;

    }

    设置缓冲空间

    - (void)setUpBuffer{

        //// 1. 创建颜色缓冲对象

        GLuintbuffer =0;

        ///  2. 申请一个缓冲区标记

        glGenRenderbuffers(1, &buffer);

        /// 3.

        myColorRenderBuffer = buffer;

        ///  4. 将缓冲区绑定到指定的空间中,把myColorRenderBuffer绑定在OpenGL ES的渲染缓存GL_RENDERBUFFER上

        glBindRenderbuffer(GL_RENDERBUFFER, myColorRenderBuffer);

        /// 将可绘制对象的存储绑定到OpenGL ES renderbuffer对象

        // target OpenGL ES绑定点用于当前绑定的renderbuffer。该参数的值必须是GL_RENDERBUFFER

        /// drawable 管理renderbuffer的数据存储的对象。在iOS中,此参数的值必须是一个 CAEAGLLayer 对象

        ///赋值

        [myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];

        //// 下面创建帧缓冲对象并绑定

        // 2、申请一个缓存区标记

        glGenFramebuffers(1, &buffer);

        myColorFrameBuffer = buffer;

        // 将缓冲区绑定到指定的空间中

        glBindFramebuffer(GL_FRAMEBUFFER, myColorFrameBuffer);

        //// 将颜色渲染内存 配到 GL_COLOR_ATTACHMENT0 配置点上

        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, myColorRenderBuffer);

    }

    为opengl的绘制写一个程序

    - (void)setUpProgram{

        myProgram = [GLESUtils loadProgram:@"texture_shaderv.glsl" fragShader:@"texture_shaderf.glsl"];

        if(myProgram==0) {

            return;

        }

        glUseProgram(myProgram);

        position_loc = glGetAttribLocation(myProgram, "in_position");

        texture_loc = glGetAttribLocation(myProgram, "in_tex_coord");

        tex1_loc = glGetUniformLocation(myProgram, "tex1");

    //    tex2_loc = glGetUniformLocation(myProgram, "tex2");

    }

    下面是重磅,这个是设置如何进行操作顶点坐标和纹理坐标的,插入一条OpenGL-ES的顶点坐标系是从-1~1,中心点为(0.0f, 0.0f, 0.0f)纹理坐标是左上角为中心(0.0f, 0.0f),大小为0~1

    - (void)setupVBO {

       GLfloatvertices[] = {

            /// 左上边

            0.0f, 1.0f, 1.0f, 0.5f, // 右上 0,1

            0.0f, 0.0f, 1.0f, 1.0f, // 右下 1,1

            -1.0f,0.0f,0.5f,1.0f,// 左下 1,0

            -1.0f,0.0f,0.5f,1.0f,// 左下 1,0

            -1.0f,1.0f,0.5f,0.5f,  // 左上 0,0

            0.0f,1.0f,1.0f,0.5f,    // 右上 0,1

            ///右上边

            1.0f, 1.0f, 0.5f, 0.5f, // 右上 0,1

            1.0f, 0.0f, 0.5f, 1.0f, // 右下 1,1

            0.0f, 0.0f, 0.0f, 1.0f, // 左下 1,0

            0.0f, 0.0f, 0.0f, 1.0f, // 左下 1,0

            0.0f,1.0f,0.0f,0.5f,  // 左上 0,0

            1.0f,1.0f,0.5f,0.5f,    // 右上 0,1

            /// 左下角

            0.0f, 0.0f, 1.0f, 0.0f, // 右上 0,1

            0.0f, -1.0f,1.0f,0.5f,// 右下 1,1

            -1.0f, -1.0f,0.5f,0.5f,// 左下 1,0

            -1.0f, -1.0f,0.5f,0.5f,// 左下 1,0

            -1.0f,0.0f,0.5f,0.0f,  // 左上 0,0

            0.0f,0.0f,1.0f,0.0f,    // 右上 0,1

            /// 右下角

            1.0f,0.0f,0.5f,0.0f,  // 右上 0,1

            1.0f, -1.0f,0.5f,0.5f,// 右下 1,1

            0.0f, -1.0f,0.0f,0.5f,// 左下 1,0

            0.0f, -1.0f,0.0f,0.5f,// 左下 1,0

            0.0f,0.0f,0.0f,0.0f,  // 左上 0,0

            1.0f,0.0f,0.5f,0.0f  // 右上 0,1

        };

        vertCount=sizeof(vertices)/4;

        vbo = [GLESUtils createVBO:GL_ARRAY_BUFFER

                             usage:GL_STATIC_DRAW

                           datSize:sizeof(vertices)

                              data:vertices];

        glEnableVertexAttribArray(position_loc);

        glVertexAttribPointer(position_loc, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, (void *)0);

     glEnableVertexAttribArray(texture_loc);

        glVertexAttribPointer(texture_loc, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, (void *)(sizeof(GLfloat) * 2));

    }

    根据图片生成纹理单元

    - (void)setUpTexture{

        text1 = [GLESUtils createTexture2D:@"test.jpg"];

    //    text2 = [GLESUtils createTexture2D:@"mixture.jpg"];

    }

    其中

    + (GLuint)createTexture2D:(NSString*)fileName{

        GLuinttexture =0;

        // 将图片转换成可操作位图

        CGImageRefspriteImage = [[UIImageimageNamed:fileName]CGImage];

        if(spriteImage ==nil) {

            NSLog(@"failed to load image %@", fileName);

            return0;

        }

        //获取横向的像素点的个数

        size_twidth =CGImageGetWidth(spriteImage);

        size_theight =CGImageGetHeight(spriteImage);

        size_tbitsPerComponent =CHAR_BIT;

        //每一行的像素点占用的字节数,每个像素点的ARGB四个通道各占8个bit(0-255)的空间

        size_tbytesPerRow =4* width;

        CGColorSpaceRef colorSpaceDeviceRGBRef = CGColorSpaceCreateDeviceRGB();

        CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;

        //指定bitmap是否包含alpha通道,像素中alpha通道的相对位置,像素组件是整形还是浮点型等信息的字符串。

        CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(spriteImage);

        if(alphaInfo ==kCGImageAlphaNone|| alphaInfo ==kCGImageAlphaOnly) {

            alphaInfo =kCGImageAlphaNoneSkipFirst;

        }elseif(alphaInfo ==kCGImageAlphaFirst) {

            alphaInfo =kCGImageAlphaPremultipliedFirst;

        }elseif(alphaInfo ==kCGImageAlphaLast) {

            alphaInfo =kCGImageAlphaPremultipliedLast;

        }

        bitmapInfo |= alphaInfo;

        //NSData *spriteData =

        //计算整张图占用的字节数

        NSIntegerbitmapByteCount = (bytesPerRow * height);

        //内存空间的指针,该内存空间的大小等于图像使用RGB通道所占用的字节数。

        void*spriteData =malloc(bitmapByteCount);

        // 创建CoreGraphic的图形上下文,该上下文描述了bitmaData指向的内存空间需要绘制的图像的一些绘制参数

        CGContextRefspriteContext =CGBitmapContextCreate(spriteData, width, height, bitsPerComponent, bytesPerRow, colorSpaceDeviceRGBRef, bitmapInfo);

        //Core Foundation中通过含有Create、Alloc的方法名字创建的指针,需要使用CFRelease()函数释放

        CGColorSpaceRelease(colorSpaceDeviceRGBRef);

        /// 在CGContextRef上绘图

        CGContextDrawImage(spriteContext,CGRectMake(0,0, width, height), spriteImage);

        /// 4. 绑定纹理到默认的纹理ID

        glGenTextures(1, &texture);

        glBindTexture(GL_TEXTURE_2D, texture);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA, (int)width, (int)height,0,GL_RGBA,GL_UNSIGNED_BYTE, spriteData);

        glBindTexture(GL_TEXTURE_2D, 0);

        free(spriteData);

        returntexture;

    }

    最后一步就是绘制了

    - (void)render{

        glClearColor(0.0, 1.0f, 0.0f, 1.0f);

        glClear(GL_COLOR_BUFFER_BIT);

        glViewport(0, 0, self.bounds.size.width, self.bounds.size.height);

        // 激活纹理单元

        glActiveTexture(GL_TEXTURE0);

        // 绑定纹理到指定纹理单元

        glBindTexture(GL_TEXTURE_2D, text1);

        // 给采样器分配位置值

        glUniform1i(tex1_loc, 0);

    //    // 激活纹理单元

    //    glActiveTexture(GL_TEXTURE1);

    //    // 绑定纹理到指定纹理单元

    //    glBindTexture(GL_TEXTURE_2D, text2);

    //    // 给采样器分配位置值

    //    glUniform1i(tex2_loc, 1);

        glDrawArrays(GL_TRIANGLES,0, (int)vertCount);

        [myContext presentRenderbuffer:GL_RENDERBUFFER];

    }

    相关文章

      网友评论

          本文标题:OpenGL-ES 纹理的实现

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