Refrence:
- https://blog.csdn.net/n5/article/details/90045648
- https://blog.csdn.net/hankern/article/details/112058229
- https://blog.csdn.net/huazi5dgan/article/details/76160334
- https://blog.csdn.net/zhuyingqingfen/article/details/19968341
- https://blog.csdn.net/candycat1992/article/details/8974719
簡單的了解:GPU(顯示卡)中有N個
texture unit
紋理單元(具體數量依賴你的GPU能力),每個 texture unit 紋理單元(GL_TEXTURE0、GL_TEXTURE1…)都有GL_TEXTURE_1D、GL_TEXTURE_2D等
textureTarget
紋理目标接口。
Android系統預設有從
GL_TEXTURE0
到
GL_TEXTURE31
共32個紋理單元,不過不同的平台或不同的系統,可用的紋理單元數量是不同的。
比如,在Pixel3XL+Android11上,可用的TextureUnit共有96個:
// [GL_TEXTURE0 ~ GL_TEXTURE31 + 64]
// "(不在這個區間就會列印警告“bindTextureImage: clearing GL error: 0x500”)"
GLES20.glActiveTexture(GL_TEXTURE0);
glActiveTexture函數
預設情況下目前活躍的紋理單元為0,即如果不調用 glActiveTexture
函數,預設使用紋理單元0。
struct TextureUnit
{
GLuint targetTexture1D;
GLuint targetTexture2D;
GLuint targetTexture3D;
GLuint targetTextureCube;
...
};
TextureUnit textureUnits[GL_MAX_TEXTURE_IMAGE_UNITS]
GLuint currentTextureUnit = 0;
從下面代碼中可以看到:當調用
glBindTexture
綁定紋理對象到紋理目标時,所作用的是目前活躍的紋理單元:
void glActiveTexture(GLenum textureUnit)
{
currentTextureUnit = textureUnit - GL_TEXTURE0 ;
}
void glBindTexture(GLenum textureTarget, GLuint textureObject)
{
TextureUnit *texUnit = &textureUnits[currentTextureUnit];
switch(textureTarget)
{
case GL_TEXTURE_1D: texUnit->targetTexture1D = textureObject; break;
case GL_TEXTURE_2D: texUnit->targetTexture2D = textureObject; break;
case GL_TEXTURE_3D: texUnit->targetTexture3D = textureObject; break;
case GL_TEXTURE_CUBEMAP: texUnit->targetTextureCube = textureObject; break;
}
}
glBindTexture函數
将一個命名的紋理綁定到一個紋理目标上
//這個更好了解 void glBindTexture(GLenum textureTarget, GLuint textureObject)
void glBindTexture(GLenum target, GLuint texture);
-
target
紋理對象要綁定到的目标。必須是下面中的一個:GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_1D_ARRAY, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_RECTANGLE, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_BUFFER, GL_TEXTURE_2D_MULTISAMPLE 或者 GL_TEXTURE_2D_MULTISAMPLE_ARRAY。
-
texture
紋理對象(紋理對象配置設定号),取值範圍為從
到Integer.MIN_VALUE
,可通過Integer.MAX_VALUE
得到。glGenTextures
int[] textures = new int[3];
GLES20.glGenTextures(textures.length, textures, 0);
// --------
// SurfaceTexture texture = new SurfaceTexture(textures[0]);
// texture.detachFromGLContext(); // 不調用會抛異常
// texture.attachToGLContext(textures[1]);
// --------
// 将surfaceTexture紋理對象附加到目前的GLContext上下文中
// surfaceTexture紋理對象在目前GLContext上下文中的配置設定号是textures[0]
surfaceTexure.attachToGLContext(textures[0]);
...
// 選擇目前活動的紋理單元,不調用此代碼預設使用紋理單元0
GLES20.glActiveTexture(GL_TEXTURE0);
// 将配置設定号為textures[0]的紋理對象綁定到目前活動紋理單元的紋理目标GLES11Ext.GL_TEXTURE_EXTERNAL_OES上
// 紋理對象配置設定号的取值為Integer.MIN_VALUE~Integer.MAX_VALUE
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]);
...
當一張紋理被綁定後,GL對于這個紋理目标的操作都會影響到這個被綁定的紋理。也就是說,這個紋理目标成為了被綁定到它上面的紋理的别名,而紋理名稱為0則會引用到它的預設紋理。之後可能還會調用如下方法:
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,512,512,0,GL_RGBA, GL_UNSIGNED_BYTE,NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
這些函數裡面的GL_TEXTURE_2D就等價與我們之前綁定的紋理,是以我們對GL_TEXTURE_2D的操作就會影響到之前的紋理,這和C++中的引用有點類似。
glBindTexture的使用方法實際上展現在兩個地方:
- 首先是第一次載入紋理對象時,将載入的紋理對象(int型的紋理配置設定号)與紋理單元綁定在一起。也就是給目前的紋理配置設定相應的紋理号。
- 其次是載入多個紋理之後,需要在多個紋理之間進行切換,此時也需要使用glBindTexture函數進行切換。(這裡是有正确? 應該是可通過需要glActiveTexture切換)
- 在openGL中,存在一系列的
,通過 glActiveTexture 選擇目前的texture unit
,預設的unit是0。而目前的texture unit
中存在多個texture unit
,例如GL_TEXTURE_2D, GL_TEXTURE_CUBEMAP…。texture target
- 通過
建立glCreateTexture
後,第一次調用glBindTexture時,決定了texture object
的類型,比如調用的是texture object
,那麼這個glBindTexture(GL_TEXTURE_2D,0)
就是一個2D texture,其内部狀态被初始化為2D texture的狀态,它不能再被bind到其他類型的texture target上,否則會産生運作時錯誤。texture object
- 通過glBindTexture将一個texture object綁定到目前激活的texture unit的texture target上。然後通過glTexImage2D, glTexParameteri等函數改變texture object的狀态。
-
建立texture object的時候需要指定texture unit嗎?
并不需要,無論目前是哪個texture unit,不影響建立texture object。建立好的texture object可以綁定到其他texture unit的texture target上使用。
-
什麼時候需要關心texture unit?
當使用多重紋理的時候,也就是說在shader裡面要同時使用多于一個sampler的時候。通過glUniform1i将texture unit傳給sampler,讓sampler知道應該去哪個texture unit中擷取texture object,那麼應該擷取哪個texture target指向的texture object呢?這就要看sampler的類型了。比如sampler2D,就會擷取sampler被指向的texture unit中的GL_TEXTURE_2D texture targert。
總結:
openGL中紋理的狀态分為texture unit和texture object包含的狀态。texture unit的狀态包括目前激活的unit,每個unit下面的各個target分别指向哪些texture object。texture object的狀态包含type, texParam, format等等。
什麼時候需要調用glActiveTexture以及glBindTexture就要看狀态是否會改變。
對于shader來說,他可以通路所有的texture unit中指定的texture object。隻要你告訴他某個sampler使用哪個unit就行。如果每個unit的内容指定後不需要改變,則即便shader使用了多個sampler也不需要來回切換unit的狀态。當然更常見的是渲染完一個pass後,需要改變目前texture unit中某target中的texture object,也就是需要換貼圖了。那麼标準的操作就是先glActiveTexture,然後glBindTexture。當然如果你隻使用unit0,則不需要調用glActiveTexture。
- glActiveTexture負責選擇目前活躍的紋理單元
- glBindTexture負責使用紋理單元中的某一種紋理類型
一個紋理單元可以有多種紋理類型GL_TEXTURE_1D、GL_TEXTURE_2D等,但是隻能使用一種,不可以多種同時使用。或者可以了解為紋理單元有多種綁定點,但一次隻能綁定到一種類型上。給着色器上傳的是紋理單元号。
調用順序:先調用glActiveTexture,再調用glBindTexture
如果使用了幀緩沖區,則調用順序為glBindFramebuffer、glBindTexture,不需要glActiveTexture
glBindFramebuffer後調用glActiveTexture會有什麼效果,應該沒有直接影響,但是glActiveTexture會影響紋理貼圖,進而會影響渲染到幀緩沖區中的内容。
也就是glBindFramebuffer是确定畫布,glActiveTexture是确定繪畫的顔料。