纹理贴图算是 OpenGLES 的基础内容了,其实这部分的文章网上太多了,我就不一一做介绍了,今天要介绍的内容在于纹理贴图的细节部分需要注意的东西,拿出来给大家分享一下,也算是自己的一个积累沉淀。
OK废话不多说,纹理贴图必经的几个步骤为:
- 生成Texture
- 绑定纹理缓存到纹理单元
- 设置纹理采样,拉伸方式
- 指定纹理图片生成2D纹理
- 激活纹理
- 绑定纹理
- 把纹理序号传值给片源着色器
无非就这几个步骤而已,看起来非常的简单,但是里面的几个函数确一直搞得我头痛不已,一直没搞清楚里面的具体含义,虽然用起来没有问题,但是就是另我不舒服,所以专门花时间研究了下才有了这篇文章,具体来说是下面4个函数:
GLES20.glGenTextures(1, textures, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
glUniform1i(iTextureUniform, 0);
这四个函数以及里面的参数一直困扰着我,于是我一个一个的解决他们,首先:
int [] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
这句话的意思是生产一个纹理对象,三个参数分别为:生产纹理的个数,生成纹理的数组(生成成功会填充这个数组),生成时候的偏移量(一般设置为0)
OK很简单下一个:
glActiveTexture(GL_TEXTURE0);
这句话的字面意思是激活一个纹理,你也大致也可以这么理解,里面的参数可以有0号纹理:GL_TEXTURE0 ,1号纹理 :GL_TEXTURE1 ,2号纹理:GL_TEXTURE2 以此类推,激活有什么用,可以不可以不激活呢?
首先激活是为了下面绑定纹理做准备的,有些人会说我使用的时候发现这个函数激不激活都没有影响,为什么要激活,说得好!那是因为默认程序是激活了0号纹理:GL_TEXTURE0 ,如果你程序简单只有一个纹理你激不激活他无所谓,反正默认激活0号纹理
下面看第三个函数
glBindTexture(GL_TEXTURE_2D, textureID);
这个函数的意思是把纹理对象绑定到激活的纹理序列,注意里面有两个点:
- 一个是纹理对象
- 一个是激活的纹理
什么是纹理对象呢?就是参数 textureID 指定的纹理ID,也就是第一句话生成的textureID数组里面的 textureID[0] 号元素
什么是激活的纹理序列呢?这个就是上面提到的 glActiveTexture(GL_TEXTURE0) 里面的参数
最后一句话:
glUniform1i(iTextureUniform, 0);
把激活的纹理序列号传给着色器使用,第一个参数是着色器的获取的参数比如:
int textureHandle1 = GLES20.glGetUniformLocation(mFrameBufferProgram, "uTexture");
第二个参数指的是 纹理序列号 ,有些人说了为什么我的程序这里一直都是写0啊?那是因为上面 glActiveTexture 函数里面的是0号纹理,所以刚好这里能对应得上罢了
好了,大致介绍清楚了,下面举个例子来说明下多个纹理下怎么使用这些函数
public void draw(float[] mvpMatrix, float[] mMatrix) {
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
// 生成Texture
int [] textures = new int[2];
GLES20.glGenTextures(2, textures, 0);
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), (R.drawable.texture1));
int colorTxtureId = textures[0];
//绑定纹理缓存到纹理单元
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, colorTxtureId);
//设置采样,拉伸方式
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.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_MIRRORED_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_MIRRORED_REPEAT);
//指定纹理图片生成2D纹理
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
//释放bitmap
bitmap.recycle();
//解除绑定
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
Bitmap bitmap1 = BitmapFactory.decodeResource(mContext.getResources(), (R.drawable.pic));
int colorTxtureId1 = textures[1];
//绑定纹理缓存到纹理单元
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, colorTxtureId1);
//设置采样,拉伸方式
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.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_MIRRORED_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_MIRRORED_REPEAT);
//指定纹理图片生成2D纹理
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap1, 0);
//释放bitmap
bitmap1.recycle();
//解除绑定
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
//从这开始到下面,大家可以不关心因为这个是固定格式和本文重点无关
int frameBufferVertexShader = loaderShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int frameBufferFagmentShader = loaderShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
mFrameBufferProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mFrameBufferProgram, frameBufferVertexShader);
GLES20.glAttachShader(mFrameBufferProgram, frameBufferFagmentShader);
GLES20.glLinkProgram(mFrameBufferProgram);
GLES20.glUseProgram(mFrameBufferProgram);
int positionHandle1 = GLES20.glGetAttribLocation(mFrameBufferProgram, "aPosition");
int textureCoordHandle1 = GLES20.glGetAttribLocation(mFrameBufferProgram, "aTextureCoord");
int textureHandle1 = GLES20.glGetUniformLocation(mFrameBufferProgram, "uTexture");
mSqureBufferfbo.position(0);
GLES20.glVertexAttribPointer(positionHandle1, 2, GLES20.GL_FLOAT, false, (2+2) * 4, mSqureBufferfbo);
mSqureBufferfbo.position(2);
GLES20.glVertexAttribPointer(textureCoordHandle1, 2, GLES20.GL_FLOAT, false, (2+2) * 4, mSqureBufferfbo);
GLES20.glEnableVertexAttribArray(positionHandle1);
GLES20.glEnableVertexAttribArray(textureCoordHandle1);
//从这上面到这里,大家可以不关心因为这个是固定格式和本文重点无关
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, colorTxtureId);
GLES20.glUniform1i(textureHandle1, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}
第一句话:
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
这个是清除缓存,有时间你的程序调试半天都是黑屏就是搞不清楚原因很可能是你渲染之前没有加这句话,大家渲染前养成好习惯加上清缓存。
再下面生成了两个纹理 GLES20.glGenTextures(2, textures, 0);
第一个纹理绑定了到了 colorTxtureId ,然后 设置采样,拉伸方式 ,然后 指定纹理图片生成2D纹理 bitmap ,最后面释放资源;
第二个纹理绑定了到了 colorTxtureId1 ,然后 设置采样,拉伸方式 ,然后 指定纹理图片生成2D纹理 bitmap1 ,最后面释放资源;
绑定完成记得释放资源,养成好习惯
//释放bitmap
bitmap1.recycle();
//解除绑定
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
最后面使用的时候怎么使用呢:下面是渲染bitmap图片的代码:也就是激活纹理0号,然后再把绑定纹理号colorTxtureId绑定到0号序列,最后面再使用0号序列的贴图即可:
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, colorTxtureId);
GLES20.glUniform1i(textureHandle1, 0);
如果想渲染bitmap1图片那么就很简单了:也就是激活纹理1号,然后再把绑定纹理号colorTxtureId1绑定到1号序列,最后面再使用1号序列
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, colorTxtureId1);
GLES20.glUniform1i(textureHandle1, 1);
tips:其实大家应该看出来了只要glActiveTexture的参数里面的纹理需要与glUniform1i参数里面的纹理序号对应起来就可以了,只不过你的程序你最好控制好这个纹理的序号,使他可读性好一点,其实你完全可以用下面的方法来渲染bitmp1
GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, colorTxtureId);
GLES20.glUniform1i(textureHandle1, 4);
好了理解了原理以后使用就非常简单,希望喜欢的小伙伴给我留言,多多支持下我,😁谢谢···
网友评论