« Shadow Map Demo1Terrain Texture-Array Demo »

学一学, Texture Array纹理数组

今天偶尔碰到一种叫texture array的opengl技术,因为看起来不怎么难掌握,因此就地学了学,做了点小小的东西。恩,就这样。——ZwqXin.com

本文来源于 ZwqXin (http://www.zwqxin.com/), 转载请注明
      原文地址:http://www.zwqxin.com/archives/opengl/learn-texture-array.html

Texture Array,一种opengl拓展,从名字就可以看出它是什么:存储纹理的数组。当然,数组存什么不可以?但是我真的第一次见它用来存储数组的 - -   纹理是什么?一块内存区域。(OpenGL Shading Language里作者称它为一种“抽象的复杂的数据类型”,好了,与其深究,还是把它看作存储区域吧...)我们通过什么操纵这种内存?纹理单元+纹理ID。前者就是一种object,类似FBO的容器,用来装纹理——但是一般一个纹理单元只装载一张纹理。然而,你可以随意更改一个纹理单元里面那张纹理图:通过纹理ID。可以说,一张纹理图对应一个纹理ID,这个ID在生成纹理(glGenTextures)的时候就唯一指定了,OpenGL靠它标识你载入的纹理。纹理单元(或者你干脆叫它纹理对象[texture object]好了)默认只开启一个,叫“0号纹理单元”,当然你可以用glActive(GL_TEXTUREi)来开启其他的,不多说。一个纹理单元每个瞬间只能绑定一张纹理图(glBindTexture),你不开启其他纹理单元情况下,看到你的程序里面花花绿绿的纹理,其实只不过是该纹理单元不停绑定一个纹理ID,然后解开再绑定下一个——它们不是同时发生的,只不过因为太快(一帧内完成),你的“幻觉”。

好了,小小基础讲到这里。Texture Array纹理数组的最显著特性,就是它不同于以上传统的经验:同样一个纹理单元,却可以在它身上同时绑定多张纹理图。当然不变的仍是纹理单元与纹理ID一一对应,因为这多张纹理图共享一个纹理ID。这可怎么用呢?且听我说。

首先,如何生成一个纹理数组?这跟我们平时载入纹理的过程是很相似的,更确切地说,是跟生成三维纹理的过程相似。(注意,我这里谈论二维纹理数组,Texture Array支持一维与二维纹理。)但是关键的“目标Target”要设成GL_TEXTURE_2D_ARRAY_EXT。注意这里filename是一个指向文件名数组的指针,我载入了Texnum张纹理,把其信息暂存入pImagex数组内,再用载入三维纹理的方法一一载入纹理ID,texid中。

  1. bool CMainFrame::SetTextureArray(char* *filename, GLuint& texid)
  2. {
  3.     bool Status=false;
  4.     AUX_RGBImageRec *pImagex[Texnum] ;
  5.  
  6.     memset(pImagex, 0,sizeof(void *) *Texnum);
  7.  
  8.     for(int i = 0; i < Texnum; i++)
  9.     {
  10.         pImagex[i]  =auxDIBImageLoad(filename[i]);
  11.         if(!pImagex[i]) return false;
  12.     }
  13.    Status=true;
  14.  
  15.     glGenTextures(1, &texid);
  16.     glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, texid);
  17.     glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  18.     glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
  19.     glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  20.     glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  21.     glTexParameteri( GL_TEXTURE_2D_ARRAY_EXT, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
  22.  
  23.     glTexImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0, GL_RGBA8, pImagex[0]->sizeX, pImagex[0]->sizeY, Texnum, 0, GL_RGB,  GL_UNSIGNED_BYTE, NULL);
  24.     for(int j = 0; j < Texnum; j++)
  25.     {
  26.     glTexSubImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0,  0,0,j, pImagex[j]->sizeX, pImagex[j]->sizeY,1, GL_RGB, GL_UNSIGNED_BYTE, pImagex[j]->data);
  27.     }
  28.  
  29. //..................
  30.    return Status;
  31. }

用法也很简单,不过得fragment shader配合。注意设定纹理坐标得时候要指定r纹理坐标,它表明该顶点选择的是纹理数组中第几张纹理图的相应st纹理坐标。纹理图的排列顺序是上面载入时候的顺序(因此这里也就是filename数组中相应文件名的顺序),载入纹理数组后,用“Layer”来标识(相当于数组下标)。Layer 0就是第一张纹理,依此类推。glTexCoord3f(1.0, 0.0, 1.0)表示对当前顶点应用第二张纹理(Layer2)中(1.0, 0.0)的st坐标。虽然r纹理坐标是浮点数,但因为这里它只起指涉作用,因此只有整数部分有作用(别以为可以偏移,至少我试过,不可以。小数部分依然对选择有影响,但这种影响是混乱的),在shader中,我们要用floor取整。

应用纹理,不能通过以往“绑定纹理ID”的做法,而要通过shader,在需要应用纹理数组做纹理的图元应用shader:

  1. #extension GL_EXT_gpu_shader4 : enable 
  2.  
  3. uniform sampler2DArray texarray;
  4. void main()
  5. {
  6.     vec4 texCoord = vec4(gl_TexCoord[0].xy, floor(gl_TexCoord[0].z),gl_TexCoord[0].w);   
  7.     vec4 color1 = texture2DArray(texarray, texCoord.xyz);
  8.      float bl = fract(gl_TexCoord[0].z);   
  9.     
  10.     texCoord += vec4(0.0, 0.0, 1.0,0.0);
  11.     vec4 color2 = texture2DArray(texarray, texCoord.xyz); 
  12.     float al = fract(gl_TexCoord[0].z);
  13.  
  14.     gl_FragColor = mix( color1, color2, al*bl);
  15. }

其中vertex shader没什么用,直接去掉(disattach)也可 - -不过我还是习惯让顶点shader和像素shader在一起。注意的是在vertex shader传递过来的(或者从应用直接过来的)gl_TexCoord[0]的r坐标(shader中叫p坐标,这里用z表示)要取整(floor),因为在像素处理前各像素的纹理坐标是经过插值的(栅格化Rasterization,这里有提到),而对每个像素真正有用的r坐标只为了指出该像素位置用的是第几张纹理的纹理坐标。采样变量sampler2DArray和纹理颜色获取函数texture2DArray用于texture array版本的纹理处理,应用前要#extension GL_EXT_gpu_shader4 : enable 启用拓展。shader这里如果直接输出color1会是如下结果(举例):

texture array demo
注意纹理坐标是怎么被应用的

texture array demo
而用我的shader做pingpong后可以有这样的边界朦胧效果(另举例)

这里mix混合了两次具有偏移的纹理坐标采样所得的颜色。注意我偏移的是r纹理坐标(偏移1单位),这样就可在隔壁纹理图上采样了。用小数部分做混合因子,得到的是相邻纹理的边界混合。美妙!

texture array demo
改变r纹理坐标可有这样的结果

texture array demo
把4个这样的矩形按螺旋顺序拼接起来......

texture array demo
然后适当改变r纹理坐标(进而改变混合因子)......

texture array demo
哈哈,雪融化后是春天啊(怀念小透)

试试把上面的效果应用到一座山怎么样?呵呵,我试了,还做了demo呵呵。就附在下面的演示demo里。看看下篇文章:Terrain Texture-Array Demo看看我是怎么做的吧~
本日志demo放出:TextureArrayDemobyzwqxin.rar
DEMO使用了shader,需要下载glew库到指定目录,下载见此:OpenGL常用的库
按键:
    ↑   ↓   在自动放映完毕后可手动调节矩形角点r纹理坐标

本文来源于 ZwqXin (http://www.zwqxin.com/), 转载请注明
      原文地址:http://www.zwqxin.com/archives/opengl/learn-texture-array.html

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

IE下本页面显示有问题?

→点击地址栏右侧【兼容视图】←

日历

Search

网站分类

最新评论及回复

最近发表

Powered By Z-Blog 1.8 Walle Build 100427

Copyright 2008-2013 ZwqXin. All Rights Reserved. Theme edited from ipati.