問(wèn)題是這樣,項(xiàng)目中有蜜汁代碼綁定的是GLES20.GL_TEXTURE_2D紋理目標(biāo),采樣器又使用samplerExternalOES采樣數(shù)據(jù),然后竟然可以正常展示,于是追蹤了下原因。
一些概念
一個(gè)正常的紋理渲染過(guò)程(簡(jiǎn)化),從創(chuàng)建開(kāi)始:
紋理創(chuàng)建
1. 創(chuàng)建紋理
int[] texture = new int[1];
GLES20.glGenTextures(1, texture, 0);
2. 綁定紋理,紋理目標(biāo) & 紋理對(duì)象句柄
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);
3. 設(shè)置紋理目標(biāo)的 紋理過(guò)濾 & 紋理坐標(biāo)包裝模式,注意是紋理目標(biāo),與紋理對(duì)象句柄無(wú)直接關(guān)系
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
渲染
1. 激活紋理單元,后續(xù)glBindTexture將紋理綁定到當(dāng)前活動(dòng)的紋理單元
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
2. 綁定紋理目標(biāo) & 紋理對(duì)象句柄
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, getTextureId());
片段著色器
1. 采樣器將加載一個(gè)指定紋理綁定的紋理單元的數(shù)值,如前面激活的GLES20.GL_TEXTURE0
uniform sampler2D vTexture;
下圖展示流程

SurfaceTexture
SurfaceTexture用于捕獲相機(jī)、解碼器的圖像,渲染到Surface上并綁定到對(duì)應(yīng)紋理,由于相機(jī)采集的圖像是YUV數(shù)據(jù),而紋理的數(shù)據(jù)是RGB,所以O(shè)penGL提供GLES11EXT擴(kuò)展接口,紋理目標(biāo)增加GL_TEXTURE_EXTERNAL_OES用于轉(zhuǎn)換數(shù)據(jù)等。
于是,通過(guò)SurfaceTexture獲取的相機(jī)數(shù)據(jù),正常會(huì)綁定到GL_TEXTURE_EXTERNAL_OES紋理目標(biāo)上,在片段著色器中,采樣器變化為
uniform samplerExternalOES vTexture;
如果一切標(biāo)準(zhǔn)規(guī)范的方式來(lái)寫(xiě),是沒(méi)問(wèn)題的,項(xiàng)目中有一種寫(xiě)法讓我對(duì)SurfaceTexture與紋理產(chǎn)生迷惑,寫(xiě)法如下(簡(jiǎn)化):
1. 創(chuàng)建時(shí),紋理綁定0或者任意整數(shù)
SurfaceTexture surfaceTexture = new SurfaceTexture(0);
(猜測(cè)紋理對(duì)象句柄是一個(gè)范圍整數(shù),規(guī)范下使用glGenTextures來(lái)創(chuàng)建,是防止錯(cuò)將該環(huán)境下其他紋理句柄誤使用,導(dǎo)致錯(cuò)亂)
2. 渲染時(shí),激活紋理單元GLES20.GL_TEXTURE0,并綁定GLES20.GL_TEXTURE_2D的紋理目標(biāo),且綁定任意的紋理對(duì)象句柄
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, getTextureId());
3. 片段著色器
uniform samplerExternalOES vTexture;
如上寫(xiě)法,可以正常預(yù)覽相機(jī),那么相機(jī)的圖像是如何與片段中采樣器關(guān)聯(lián)的呢?紋理單元,紋理目標(biāo),紋理句柄對(duì)象之間是什么關(guān)系呢?
OpenGL提供GLES20.GL_TEXTURE0~GLES20.GL_TEXTURE31共32個(gè)紋理單元,每個(gè)紋理單元可以有多個(gè)紋理目標(biāo)(GLES20.GL_TEXTURE_2D、GLES20.GL_TEXTURE_3D等),每個(gè)目標(biāo)又可以綁定多個(gè)紋理對(duì)象句柄,但解釋不通上述的綁定2D,但片段著色器中使用samplerExternalOES采樣呀,于是看看SurfaceTexture的源碼。
- SurfaceTexture初始化,會(huì)調(diào)用nativeInit,傳遞texName

- nativeInit會(huì)創(chuàng)建GLConsumer對(duì)象,將texName傳遞過(guò)去 & 寫(xiě)死textureTarget = GL_TEXTURE_EXTERNAL_OES

-
每次更新數(shù)據(jù)updateTexImage時(shí)會(huì)調(diào)用bindTextureImageLocked方法,里面會(huì)調(diào)用glBindTexture綁定紋理目標(biāo)
image.png
所以上述寫(xiě)法中,去掉 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, getTextureId());,采樣器也是能夠正確采樣數(shù)據(jù)的,解惑。
