美文网首页OpenGLOpenGLES
iOS-OpenGL ES入门教程(二)最简单的纹理Demo

iOS-OpenGL ES入门教程(二)最简单的纹理Demo

作者: 安东_Ace | 来源:发表于2018-04-25 16:30 被阅读554次

前言

上一篇介绍了绘制OpenGL ES的Hello world也就是一个三角形。现在我们介绍下OpenGL ES的一个另一个基础,纹理,并且编写一个最简单的demo绘制一张图片。

纹理

初学呢,我们可以把纹理理解为一张图片,我们可以将整张图片绘制到圆形,矩形等目标图形中,既可以绘制部分图,也可以重复使用图片绘制,也就是纹理了哈。

矩形图

我们目标是绘制一个矩形图,在OpenGL ES中任何复杂的图形都是由点,线和三角形组成的哈。很简单,一个矩形就是两个三角形组成。嚯嚯。So easy。

矩形

好滴,那么矩形的六个顶点有了哈

const GLfloat vertices[] = {
        1, -1, 0.0f,   //D
        1, 1,  0.0f,   //B
        -1, 1, 0.0f,   //A
        
        1, -1, 0.0f,   //D
        -1, 1, 0.0f,   //A
        -1, -1, 0.0f,   //C 
}; 

很明显我们的顶点是需要和纹理坐标一一对应的,如下图,


顶点和纹理映射图

需要注意的是:纹理坐标系是左下角为坐标系顶点,而顶点坐标系屏幕中心为顶点

好滴,那么我们的数据源就有了哈。

//顶点数据
typedef struct {
    GLKVector3 positionCoords; 
    GLKVector2 textureCoords;//纹理
}SceneVertex;

//矩形的六个顶点
static const SceneVertex vertices[] = {
    {{1, -1, 0.0f,},{1.0f,0.0f}}, //右下
    {{1, 1,  0.0f},{1.0f,1.0f}}, //右上
    {{-1, 1, 0.0f},{0.0f,1.0f}}, //左上
    
    {{1, -1, 0.0f},{1.0f,0.0f}}, //右下
    {{-1, 1, 0.0f},{0.0f,1.0f}}, //左上
    {{-1, -1, 0.0f},{0.0f,0.0f}}, //左下
};

textureCoords即是纹理位置。

设置OpenGLES上下文

//新建OpenGLES 上下文
    GLKView *view = (GLKView *)self.view;
    view.context = [[EAGLContext alloc]initWithAPI: kEAGLRenderingAPIOpenGLES2];
    //设置当前上下文
    [EAGLContext setCurrentContext:view.context];
    
    self.baseEffect = [[GLKBaseEffect alloc]init];
    self.baseEffect.useConstantColor = GL_TRUE;
    self.baseEffect.constantColor = GLKVector4Make(1.0f, 1.0f, 1.0f, 1.0f);

这是第一步。

设置顶点缓存buffer

- (void)fillVertexArray{
    glGenBuffers(1, &vertextBufferID);
    glBindBuffer(GL_ARRAY_BUFFER, vertextBufferID); //绑定指定标识符的缓存为当前缓存
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    
    glEnableVertexAttribArray(GLKVertexAttribPosition); //顶点数据缓存
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(SceneVertex), NULL + offsetof(SceneVertex, positionCoords));
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0); //纹理
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(SceneVertex), NULL + offsetof(SceneVertex, textureCoords));
    
}

这里我们生成绑定了顶点和纹理buffer,并且设置了对应的指针偏移量。

生成纹理

这里我们使用GLkit中的GLKTextureInfo方便的生成图片纹理。

   //获取图片
    CGImageRef imageRef = [[UIImage imageNamed:@"Demo.jpg"] CGImage];
    
    //通过图片数据产生纹理缓存
    //GLKTextureInfo封装了纹理缓存的信息,包括是否包含MIP贴图
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:imageRef options:nil error:NULL];
    self.baseEffect.texture2d0.name = textureInfo.name;
    self.baseEffect.texture2d0.target = textureInfo.target;

GLKBaseEffect让我们避开了写shader Language。

绘制 & 释放

最后一步就是绘制了,这步非常简单

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    //清除背景色
    glClearColor(0.0f,0.0f,0.0f,1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    [self.baseEffect prepareToDraw];
    glDrawArrays(GL_TRIANGLES, 0, 6);
}


- (void)dealloc{
    GLKView *view = (GLKView *)self.view;
    [EAGLContext setCurrentContext:view.context];
    if ( 0 != vertextBufferID) {
        glDeleteBuffers(1,
                        &vertextBufferID);
        vertextBufferID = 0;
    }
    [EAGLContext setCurrentContext:nil];
}

小思考:因为这次绘制的是静态图,所以我们直接在viewdidload里面就生成绑定好了顶点数据缓存,而不是在drawInRect方法中。如果要做一些动态变化,就需要在drawInRect方法中动态刷新缓存数据

看下最后运行结果


运行结果-彭于晏

图片正常显示了,但是倒立了,这个是因为CoreGraphics的坐标系问题。我们生成纹理的时候option加个坐标系变换就OK了。

 NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:@(1), GLKTextureLoaderOriginBottomLeft, nil];
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:imageRef options:options error:NULL];

小思考: 我们这里实现了最简单的纹理图片绘制,但是由于图标本身的尺寸被全屏展示后出现了拉伸,怎么保证图片按比例的绘制在屏幕中呢?

Demo代码地址:LearnOpenGLESDemo

参考书籍:1. OpenGL ES应用开发实践指南:iOS卷

相关文章

网友评论

    本文标题:iOS-OpenGL ES入门教程(二)最简单的纹理Demo

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