zoukankan      html  css  js  c++  java
  • OpenGL ES: Array Texture初体验

    Array Texture这个东西的意思是,一个纹理对象,可以存储不止一张图片信息,就是说是是一个数组,每个元素都是一张图片。这样免了频繁地去切换当前需要bind的纹理,而且可以节省系统资源。本文主要讨论的是2D array textures. 1D的使用很少 不讨论。

    那么,在shader里面应该怎么去访问我想要的纹理呢?普通的纹理坐标是 (x,y) 这里就不够了,这里需要 (x,y,z) 三个值,XY代表2d纹理坐标,Z值代表选择读取哪一张纹理的数据,从0开始。

    初始化Array Texture

    普通 2D texture对象

    初始化一个普通的2D纹理对象的方式是这样的:

    genTexture-->BindTexture-->指定图片信息(使用 glTexImage2D 函数)

    2D texture array对象

    前两步一样的,指定图片信息的时候不一样。这里需要两歩操作,开辟存储空间和上传数据。

    第一步,开辟空间:

    爲纹理开辟内存,确定存储的结构

    glTexImage3D (这个和glTexImage2D长得很像的函数)

    target :GL_TEXTURE_2D_ARRAY

    depth: 用于指定我们的数组的长度(若是3D texture就是纹理的深度信息了,我们用的是2D texture array)。

    mipmap的level,一般我们给0,也就是說每次只能确定一个mipmap的level.

    需要注意的是,我们生成普通纹理的时候数据是在这个地方指定的,同样,这个函数的最后一个参数也代表源像素数据,但是这里可以指定也可以写NULL,后面再上传数据。我推荐这样做。

    以上是旧的做法,目前官方更推荐使用 glTexStorage3D 函数,功能类似。

    glTexStorage3D — simultaneously specify storage for all levels of a three-dimensional or two-dimensional array texture

    void glTexStorage3D( 	GLenum target,
      	GLsizei levels,
      	GLenum internalformat,
      	GLsizei width,
      	GLsizei height,
      	GLsizei depth);
    

    参数和上面的相同,需要注意:levels 最小设置爲1;

    这个函数比上面的好在什么地方呢?根据大牛的解释,glTexImage3D生成的纹理对象是不完整的,比如缺少mipmap的信息,缺少环绕方式等等,而且是可变的,这一秒创建好下一秒被改的乱七八糟了。而这个函数生成一个完整的不可变的对象,更可靠更安全。而且不用再显式地去调用glGenerateMipmap 。它已经自动帮你做好了处理。

    第二步,指定数据

    glTexSubImage3D

    这个函数用于上传真正的纹理数据,参数较多,可以参考官方的文档。提供指定xyz的offset,即偏移量。一般xy的设置0,z方向的便宜就代表了是第几张纹理,所以这个需要按需要设置。后面的设置宽高很简单,然后是depth,这一次调用上传的数据的depth,如果两张纹理图片放在一起,然后一起上传(这样只需要调用一次这个函数),那么需要設爲2.后面再设置format data等等即可。如果需要指定mipmap(level大于1) 那么还需要把每个level的数据都上传。

    Example:

    TexStorage3D(...3... W, H, 2);
     // allocates W x H x 2 level0, W/2 x H/2 x 2 level1, W/4 x H/4 x 2 level2. 
    // Contents are undefined at this point.
    
    TexSubImage3D(...level0, 0, 0, 0, W, H, 1... lod0_slice0_pixels);
    TexSubImage3D(...level0, 0, 0, 1, W, H, 1... lod0_slice1_pixels);
    TexSubImage3D(...level1, 0, 0, 0, W/2, H/2, 1... lod1_slice0_pixels);
    TexSubImage3D(...level1, 0, 0, 1, W/2, H/2, 1... lod1_slice1_pixels);
    TexSubImage3D(...level2, 0, 0, 0, W/4, H/4, 1... lod2_slice0_pixels);
    TexSubImage3D(...level2, 0, 0, 1, W/4, H/4, 1... lod2_slice1_pixels);   
    // all slices of all mipmaps now transferred
    

    如果相同mipmap的两张纹理是前后相连地存储在一起的,可以这样做:

    TexSubImage3D(...level0, 0, 0, 0, W, H, 2... lod0_slice0and1_pixels);
    TexSubImage3D(...level1, 0, 0, 0, W/2, H/2, 2... lod1_slice0and1_pixels);
    TexSubImage3D(...level2, 0, 0, 0, W/4, H/4, 2... lod2_slice0and1_pixels);
    

    shader内访问

    需要定义2darray的sampler,然后还是调用texture函数,但是第二个参数需要三维的纹理坐标,z值代表在第几张纹理上面取值,从 0 开始。

    "precision mediump sampler2DArray;
    "
    "uniform sampler2DArray texture_array;
    "
    ...
    ...
    "  color = texture(texture_array, vec3(texCoord.xy, layer));
    "
    

    注意:如果上传三维的纹理坐标,假设我们有两张纹理图片,我们上传的z值只有 0 和 1 两个,但是在光栅化阶段的插值计算会生成一些处于0和1之间的非整数的z值,这不是我们想要的,所以不能使用三维纹理坐标。我们需要单独上传这个数据,然后在shader内构造出一个新的三维的向量,这个时候z值就只有0、1两个值了。


    参考资料:Array-Texture-confusion 讨论帖子
    例子1--zwqxin
    例子2--老外的

  • 相关阅读:
    设计模式 ( 十七) 状态模式State(对象行为型)
    Intellij13 IDEA常用快捷键 (mac 10.5 +),优化,使用出现的问题汇总
    Web服务器及Web应用服务器
    阮一峰的网络日志
    双击退出的实现
    完成3DM以后的总结(2).Xutils的简单使用
    完成3DM以后的总结(1).PullToRefresh
    软考之路之j2se总结
    2013-2014年终总结
    牛腩新闻发布系统之获取IP
  • 原文地址:https://www.cnblogs.com/psklf/p/5713791.html
Copyright © 2011-2022 走看看