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;\n"
"uniform sampler2DArray texture_array;\n"
...
...
"  color = texture(texture_array, vec3(texCoord.xy, layer));\n"

注意:如果上傳三維的紋理坐標,假設我們有兩張紋理圖片,我們上傳的z值只有 0 和 1 兩個,但是在光柵化階段的插值計算會生成一些處於0和1之間的非整數的z值,這不是我們想要的,所以不能使用三維紋理坐標。我們需要單獨上傳這個數據,然后在shader內構造出一個新的三維的向量,這個時候z值就只有0、1兩個值了。


參考資料:Array-Texture-confusion 討論帖子
例子1--zwqxin
例子2--老外的


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM