IOS 中openGL使用教程3(openGL ES 入门篇 | 纹理贴图(texture)使用)


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

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

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

首先我们来看看如何通过图片获取一张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];
复制代码
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值