OpenGL-ES 纹理的实现

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

最终实现的效果图

原图是一张完整的图,我们把原图做成一个四宫格的样式,当然了,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 纹理的实现)