zoukankan      html  css  js  c++  java
  • iOS-----openGL--openGL ES iOS 入门篇3---> 纹理贴图(texture)

    在这篇文章中,我们将学习如何在openGL中使用纹理贴图。

    penGL中纹理可以分为1D,2D和3D纹理,我们在绑定纹理对象的时候需要指定纹理的种类。由于本文将以一张图片为例,因此我们为我们的纹理对象绑定一个GL_TEXTURE_2D的纹理。

    本文将分为两个部分,一部分是如何通过图片获取一个2D的纹理,另一部分是如何使用一个纹理。

    上一篇中,我们介绍了如何使用shader来绘制一个多边形,本文是基于上一篇的提高,我们也将继续使用shader,对于shader使用不熟的童鞋可以看上一篇

    首先我们来看看如何通过图片获取一张2D的纹理。

    复制代码
    + (GLuint)createTextureWithImage:(UIImage *)image{
      //转换为CGImage,获取图片基本参数 CGImageRef cgImageRef = [image CGImage]; GLuint width = (GLuint)CGImageGetWidth(cgImageRef); GLuint height = (GLuint)CGImageGetHeight(cgImageRef); CGRect rect = CGRectMake(0, 0, width, height);
      //绘制图片 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); void *imageData = malloc(width * height * 4); CGContextRef context = CGBitmapContextCreate(imageData, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmap    ByteOrder32Big); CGContextTranslateCTM(context, 0, height); CGContextScaleCTM(context, 1.0f, -1.0f); CGColorSpaceRelease(colorSpace); CGContextClearRect(context, rect); CGContextDrawImage(context, rect, cgImageRef);
     //纹理一些设置,可有可无
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      
    //生成纹理
    glEnable(GL_TEXTURE_2D);
      GLuint textureID;
      glGenTextures(1, &textureID);
      glBindTexture(GL_TEXTURE_2D, textureID);  
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
      //绑定纹理位置  glBindTexture(GL_TEXTURE_2D, 0);
      //释放内存 CGContextRelease(context); free(imageData); return textureID; }
    复制代码

    获取纹理之后,我们就要开始使用纹理了。

    和之前绘制多边形的过程一样,我们要先把参数传入shader中。在绘制多边形时我们只需要传入各个顶点的位置,但为了使用纹理,我们需要把纹理传入shader,

    此外,还要传入所使用的纹理的范围(使用纹理的哪一部分来映射)。

    Vertex Shader代码如下:

    复制代码
    attribute vec4 Position;
    attribute vec2 TextureCoords;
    varying vec2 TextureCoordsOut;
    
    void main(void)
    {
    //用来展现纹理的多边形顶点 gl_Position = Position;
    //表示使用的纹理的范围的顶点,因为是2D纹理,所以用vec2类型 TextureCoordsOut = TextureCoords; }
    复制代码

    Fragment Shader代码如下:

    复制代码
    precision mediump float;
    
    uniform sampler2D Texture;
    varying vec2 TextureCoordsOut;
    
    void main(void)
    {
    //获取纹理的像素 vec4 mask = texture2D(Texture, TextureCoordsOut);
    gl_FragColor = vec4(mask.rgb, 1.0); }
    复制代码

    注意:

    attribute属性只能通过Vertex Shader传入,再传给Fragment Shader,而uniform属性可以直接传入Fragment Shader。

    同理的,与绘制多边形的过程一样,我们要编译shader,生成一个glProgram。不同的是,这次我们要传入着色器程序的参数有三个

    复制代码
      GLuint fragmentShader = [self compileShader:@"MTShaderFragment"
                                           withType:GL_FRAGMENT_SHADER];
        _glProgram = glCreateProgram();
        glAttachShader(_glProgram, vertexShader);
        glAttachShader(_glProgram, fragmentShader);
        glLinkProgram(_glProgram);
        glUseProgram(_glProgram);
        
        _positionSlot = glGetAttribLocation(_glProgram, "Position");
      //uniform类型的参数获取方式不同 _textureSlot = glGetUniformLocation(_glProgram, "Texture"); _textureCoordsSlot = glGetAttribLocation(_glProgram, "TextureCoords");
    复制代码

    接下来就到了最后一步,将纹理“贴”到多边形上。

    首先将纹理传入,激活索引为1的纹理。表示接下来的操作都是针对纹理1

    glActiveTexture(GL_TEXTURE1);
    //载入纹理 glBindTexture(GL_TEXTURE_2D, _textureID);
    //为当前程序对象指定Uniform变量的值,参数1代表使用的新值(GL_TEXTURE1) glUniform1i(_textureSlot, 1);

    在指定区域绘制纹理。

    注意:用于表示纹理范围时的坐标表示方式与UIKit和openGL的坐标都不同,范围从(0,0)左下到(1,1)右上。

    复制代码
    //纹理使用范围顶点
    const GLfloat texCoords[] = { 0, 0,//左下 1, 0,//右下 0, 1,//左上 1, 1,//右上 }; glVertexAttribPointer(_textureCoordsSlot, 2, GL_FLOAT, GL_FALSE, 0, texCoords); glEnableVertexAttribArray(_textureCoordsSlot); //绘图区域顶点 const GLfloat vertices[] = { -1, -1, 0, //左下 1, -1, 0, //右下 -1, 1, 0, //左上 1, 1, 0 }; //右上 glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices); glEnableVertexAttribArray(_positionSlot); const GLubyte indices[] = { 0,1,2, 1,2,3 }; glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]), GL_UNSIGNED_BYTE, indices); [_context presentRenderbuffer:GL_RENDERBUFFER];
    复制代码

    下一篇我们会讲解如何进行一些动态的操作和简单滤镜,让手指划过的区域变成灰色。

  • 相关阅读:
    Redis 字符串(String)
    Redis 哈希(Hash)
    Redis 键(key)
    Redis 命令
    Redis 数据类型
    Redis 配置
    Log4j 2X 日志文件路径问题
    shiro项目从 log4j1X 迁移到 log4j2X
    shiro+SpringMVC 项目 配置404页面
    邮件发送-》http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256
  • 原文地址:https://www.cnblogs.com/LifeTechnologySupporter/p/6604618.html
Copyright © 2011-2022 走看看