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];

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容