美文网首页程序员
OpenGL ES 3.0编程指南:第九章. Texturing

OpenGL ES 3.0编程指南:第九章. Texturing

作者: 别卡机 | 来源:发表于2016-11-01 16:00 被阅读506次

    [TOC]

    Texture Objects and Loading Textures

    纹理应用的第一步就是创建一个纹理对象。纹理对象是一个容器对象,包含着渲染所需的图像数据,过滤模式和wrap模式。在OpenGL ES中,纹理对象用一个无符号整数表示。纹理对象的生成方法如下:

    void glGenTextures (GLsizei n, GLuint * textures)

    • n : 要创建的纹理对象的个数
    • textures : 储存新创建的纹理对象ID的无符号整数数组

    新创建的纹理对象是一个空的容器对象,用来加载纹理数据。当应用程序不在需要纹理对象时,需要将它们进行删除:

    void glDeleteTextures (GLsizei n, GLuint * textures)

    • n : 要删除的纹理对象的个数
    • textures :储存要删除的纹理对象ID的无符号整数数组

    纹理对象创建之后,需要进行绑定。一旦绑定纹理对象后,后续的操作例如glTexImage2D和glTexParameter都将会影响绑定的纹理对象。绑定纹理对象的方法如下:

    void glBindTexture (GLenum target, GLuint texture)

    • target : 可取值为
      GL_TEXTURE_2D,
      GL_TEXTURE_3D,
      GL_TEXTURE_2D_ARRAY,
      GL_TEXTURE_CUBE_MAP
    • texture : 要绑定的纹理对象

    绑定纹理对象之后,下一步就可以加载图像数据了。加载2D纹理和立方图纹理的基础方法是glTexImage2D。另外,在OpenGL ES中,还有其他方法可以指定2D纹理,包括使用不可变纹理(glTexStorage2D)结合glTexSubImage2D的方法。我们这里先介绍基础方法,稍后再介绍不可变纹理。为了获得最佳性能,推荐使用不可变纹理。

    void glTexImage2D (GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels)

    • target : 可取值为
      GL_TEXTURE_2D,
      立方图的一面,例如 GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X
    • level : mip等级。第一级是0,后续递增。
    • internalFormat : 纹理储存的内部格式,可以是未确定大小的格式,也可以是确定大小的格式。
      未确定大小的格式可取值为:
      GL_RGBA, GL_RGB,
      GL_LUMINANCE_ALPHA, GL_LUMINANCE,
      GL_ALPHA
      确定大小的格式可取值为:
      GL_R8, GL_R8_SNORM, GL_R16F, GL_R32F,
      GL_R8UI, GL_R16UI, GL_R32UI, GL_R32I,
      GL_RG8, GL_RG8_SNORM, GL_RG16F, GL_RG32F,
      GL_RG8UI, GL_RG8I, GL_RG16UI, GL_RG32UI. GL_ RG32I,
      GL_RGB8, GL_SRGB8, GL_RGB565, GL_RGB8_SNORM,
      GL_R11F_G11F_B10F, GL_RGB9_E5,
      GL_RGB16F, GL_RGB32F,
      GL_RGB8UI, GL_RGB16UI, GL_RGB16I, GL_RGB32UI, GL_RGB32I,
      GL_RGBA8, GL_SRGB8_ALPHA8, GL_RGBA8_SNORM,
      GL_RGB5_A1, GL_RGBA4, GL_RGB10_A2,
      GL_RGBA16F, GL_RGBA32F, GL_RGBA8UI, GL_RGBA8I,
      GL_RGB10_A2UI,
      GL_RGBA16UI, GL_RGBA16I, GL_RGBA32I, GL_RGBA32UI,
      GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32F,
      GL_DEPTH24_STENCIL8, GL_DEPTH24F_STENCIL8
    • width : 图像的像素宽度
    • height : 图像的像素高度
    • border : 这个参数在OpenGL ES中忽略,为了和桌面OpengL兼容才保留,值写0即可
    • format : 输入的纹理数据的格式,可取值为
      GL_RED, GL_RED_INTEGER,
      GL_RG, GL_RG_INTEGER,
      GL_RGB, GL_RGB_INTEGER,
      GL_RGBA, GL_RGBA_INTEGER,
      GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL,
      GL_LUMINANCE_ALPHA, GL_ALPHA
    • type : 输入的像素数据的类型,可取值为
      GL_UNSIGNED_BYTE, GL_BYTE,
      GL_UNSIGNED_SHORT, GL_SHORT,
      GL_UNSIGNED_INT, GL_INT,
      GL_HALF_FLOAT, GL_FLOAT,
      GL_UNSIGNED_SHORT_5_6_5,
      GL_UNSIGNED_SHORT_4_4_4_4,
      GL_UNSIGNED_SHORT_5_5_5_1,
      GL_UNSIGNED_INT_2_10_10_10_REV,
      GL_UNSIGNED_INT_10F_11F_11F_REV,
      GL_UNSIGNED_INT_5_9_9_9_REV,
      GL_UNSIGNED_INT_24_8,
      GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
      GL_UNSIGNED_SHORT_5_6_5
    • pixels : 包含图像的实际像素数据,数据必须包含 width * height 个像素,每一个像素根据format和type有相应的字节数。像素行必须按照用glPixelStorei设置的GL_UNPACK_ALIGNMENTD的方式对齐。

    下面看一个具体例子:

    GLuint textureId;
    
    // 2 * 2 image, 3 bytes per pixel
    GLubyte pixels[4 * 3] = 
    {
        255, 0, 0,    // red
        0, 255, 0,    // green
        0, 0, 255,    // blue
        255, 255, 0    // yellow
    };
    
    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
    
    glGenTextures (1, &textureId);
    
    glBindTexture (GL_TEXTURE_2D, textureId);
    
    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
    
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    

    在本例中的开始部分,我们创建了一个2x2的纹理数据,数据的范围是[0, 255] 。在shader中,该数据会由[0,255]映射到浮点范围[0.0, 1.0]。一般情况下,纹理数据通过读取图像文件获得,而不是例子中的这样直接定义。

    在本例中调用glTexImage2D方法之前,先调用了glPixelStorei方法设置unpack alignment。当通过glTexImage2D加载纹理数据时,像素行被认定为按照GL_UNPACK_ALIGNMENT的值进行对齐。默认情况下,这个值是4,意味着像素行从4字节的边界开始排列。(意思应该是按照4的整数倍字节数来排列,例如第一个像素有3个字节,占据了1、2、3位置,那么第二个像素也会从第5个字节开始,而不是第4个)本例中,将这个值设为了1,也就意味着紧密排列。

    void glPixelStorei (GLenum pname, GLint param)

    • pname : 指明要设置的像素储存类型。
      下列选项影响当调用glTexImage2D, glTexImage3D, glTexSubImage2D, glTexSubImage3D时,数据如何从内存中解包(unpack):
      GL_UNPACK_ROW_LENGTH, GL_UNPACK_IMAGE_HEIGHT,
      GL_UNPACK_SKIP_PIXELS, GL_UNPACK_SKIP_ROWS,
      GL_UNPACK_SKIP_IMAGES, GL_UNPACK_ALIGNMENT
      下列选项影响当调用glReadPixels时,数据如何被打包到内存中(pack):
      GL_PACK_ROW_LENGTH, GL_PACK_IMAGE_HEIGHT,
      GL_PACK_SKIP_PIXELS, GL_PACK_SKIP_ROWS,
      GL_PACK_SKIP_IMAGES, GL_PACK_ALIGNMENT
    • param : 要设置的值

    通过glPixelStorei设置的pack和unpack选项,是一个全局状态,不由纹理对象储存或关联。实际上,在声明纹理时,除了GL_UNPACK_ALIGNMENT,其他选项很少用到。下表是对所有选项的一个说明:

    Pixel Storage Option Initial Value Description
    GL_UNPACK_ROW_LENGTH, GL_PACK_ROW_LENGTH 4 表示一个图像中各行的对齐方式
    GL_UNPACK_ROW_LENGTH, GL_PACK_ROW_LENGTH 0 如果该值非0,则表示图像行中的像素数据;如果该值为0,则表示图像行的长度为图像的宽度
    GL_UNPACK_IMAGE_HEIGHT, GL_PACK_IMAGE_HEIGHT 0 如果该值非0,则表示作为3D纹理一部分的图像的每个列中像素的数量。这个选项可以用于在3D纹理的每个切片之间填充列。如果该值为0,则图像中的列数等于高度
    GL_UNPACK_SKIP_PIXELS, GL_PACK_SKIP_PIXELS 0 如果该值非0,则表示在行开始处跳过的像素数
    GL_UNPACK_SKIP_ROWS,GL_PACK_SKIP_ROWS 0 如果该值非0,则表示在图像开始处跳过的行数
    GL_UNPACK_SKIP_IMAGES, GL_PACK_SKIP_IMAGES 0 如果该值非0,则表示在3D纹理中跳过的图像数

    在本例的最后一部分,是通过glTexParameteri将缩小和放大过滤模式设为GL_NEAREST。这部分代码是必须的,因为我们没有为纹理加载完整的mipmap链,所以必须选择一个非mipmap的缩小过滤器。纹理过滤和mipmap的更多细节将在下节进行介绍。

    相关文章

      网友评论

        本文标题:OpenGL ES 3.0编程指南:第九章. Texturing

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