本文主要是介绍OpenGLES帧缓冲,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
https://www.jianshu.com/p/78a64b8fb315
FBO
Frame Buffer object
为什么要用FBO
我们需要对纹理进行多次渲染采样时,而这些渲染采样是不需要展示给用户看的,所以我们就可以用一个单独的缓冲对象(离屏渲染)来存储我们的这几次渲染采样的结果,等处理完后才显示到窗口上
优势
提高渲染效率,避免闪屏,可以很方便的实现纹理共享等。
渲染方式
- 渲染到纹理(Texture)- 图像渲染
- 渲染到缓冲区(Render)- 深度测试和模板测试
FBO纹理的坐标系
FBO坐标系
渲染到纹理
工作流程
创建FBO的步骤:
//1. 创建FBO
int[] fbos = new int[1];
GLES20.glGenFramebuffers(1, fbos, 0);
fboId = fbos[0];//2. 绑定FBO
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);//3. 创建FBO纹理
fboTextureId = createTexture();//4. 把纹理绑定到FBO
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,GLES20.GL_TEXTURE_2D, fboTextureId, 0);//5. 设置FBO分配内存大小
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA,bitmap.getWidth(), bitmap.getHeight(),0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);//6. 检测是否绑定从成功
if (GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER)!= GLES20.GL_FRAMEBUFFER_COMPLETE) {Log.e("zzz", "glFramebufferTexture2D error");
}//7. 解绑纹理和FBO
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
使用FBO的步骤:
//1. 绑定fbo
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);//2. FBO绘制
GLES20.glUseProgram(program);
//绑定渲染纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, imageTextureId);
//...
//解绑纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
//解绑fbo
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);//3. 根据绑定到fbo上的纹理id,渲染GLES20.glUseProgram(program);
//绑定渲染纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);//...
示例代码如下:
TexureRender.java
import android.content.Context;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;public class TexureRender implements EglSurfaceView.Renderer {private BitmapFboTexture bitmapFboTexture;private BitmapRenderTexture bitmapRenderTexture;public TexureRender(Context context) {bitmapFboTexture = new BitmapFboTexture(context);bitmapFboTexture.setBitmap(BitmapFactory.decodeResource(context.getResources(),R.mipmap.bg));bitmapRenderTexture = new BitmapRenderTexture(context);}@Overridepublic void onSurfaceCreated() {bitmapFboTexture.onSurfaceCreated();bitmapRenderTexture.onSurfaceCreated();}@Overridepublic void onSurfaceChanged(int width, int height) {//宽高GLES20.glViewport(0, 0, width, height);bitmapFboTexture.onSurfaceChanged(width, height);bitmapRenderTexture.onSurfaceChanged(width, height);}@Overridepublic void onDrawFrame() {//清空颜色GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);//设置背景颜色GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);//FBO处理bitmapFboTexture.draw();//通过FBO处理之后,拿到纹理id,然后渲染bitmapRenderTexture.draw(bitmapFboTexture.getFboTextureId());}
}
FBO处理类: BitmapFboTexture.java
import android.content.Context;
import android.graphics.Bitmap;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Log;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;//纹理 根据坐标系映射
public class BitmapFboTexture {//顶点坐标static float vertexData[] = { // in counterclockwise order:-1f, -1f, 0.0f, // bottom left1f, -1f, 0.0f, // bottom right-1f, 1f, 0.0f, // top left1f, 1f, 0.0f, // top right};//正常纹理坐标 对应顶点坐标 与之映射
// static float textureData[] = { // in counterclockwise order:
// 0f, 1f, 0.0f, // bottom left
// 1f, 1f, 0.0f, // bottom right
// 0f, 0f, 0.0f, // top left
// 1f, 0f, 0.0f, // top right
// };//fbo 纹理坐标static float textureData[] = { // in counterclockwise order:0f, 0f, 0.0f, // bottom left1f, 0f, 0.0f, // bottom right0f, 1f, 0.0f, // top left1f, 1f, 0.0f, // top right};//每一次取点的时候取几个点static final int COORDS_PER_VERTEX = 3;private final int vertexCount = vertexData.length / COORDS_PER_VERTEX;//每一次取的总的点 大小private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertexprivate Context context;//位置private FloatBuffer vertexBuffer;//纹理private FloatBuffer textureBuffer;private int program;private int avPosition;//纹理位置private int afPosition;//需要渲染的纹理idprivate int imageTextureId;//fbo纹理idprivate int fboTextureId;//fbo Idprivate int fboId;private Bitmap bitmap;public void setBitmap(Bitmap bitmap) {this.bitmap = bitmap;}public BitmapFboTexture(Context context) {this.context = context;vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertexData);vertexBuffer.position(0);textureBuffer = ByteBuffer.allocateDirect(textureData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(textureData);textureBuffer.position(0);}public void onSurfaceCreated() {String vertexSource = ShaderUtil.readRawTxt(context, R.raw.vertex_shader);String fragmentSource = ShaderUtil.readRawTxt(context, R.raw.fragment_shader);program = ShaderUtil.createProgram(vertexSource, fragmentSource);if (program > 0) {//获取顶点坐标字段avPosition = GLES20.glGetAttribLocation(program, "av_Position");//获取纹理坐标字段afPosition = GLES20.glGetAttribLocation(program, "af_Position");createFBO();imageTextureId = createImageTexture();}}public void draw() {//绑定fboGLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);//使用程序GLES20.glUseProgram(program);//绑定渲染纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, imageTextureId);GLES20.glEnableVertexAttribArray(avPosition);GLES20.glEnableVertexAttribArray(afPosition);//设置顶点位置值GLES20.glVertexAttribPointer(avPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);//设置纹理位置值GLES20.glVertexAttribPointer(afPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureBuffer);//绘制 GLES20.GL_TRIANGLE_STRIP:复用坐标GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);GLES20.glDisableVertexAttribArray(avPosition);GLES20.glDisableVertexAttribArray(afPosition);//解绑纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);//解绑fboGLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);}private void createFBO() {if (bitmap == null) {throw new IllegalArgumentException("bitmap is null");}//1. 创建FBOint[] fbos = new int[1];GLES20.glGenFramebuffers(1, fbos, 0);fboId = fbos[0];//2. 绑定FBOGLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);//3. 创建FBO纹理fboTextureId = createTexture();//4. 把纹理绑定到FBOGLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,GLES20.GL_TEXTURE_2D, fboTextureId, 0);//5. 设置FBO分配内存大小GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(), bitmap.getHeight(),0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);//6. 检测是否绑定从成功if (GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER)!= GLES20.GL_FRAMEBUFFER_COMPLETE) {Log.e("zzz", "glFramebufferTexture2D error");}//7. 解绑纹理和FBOGLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);}private int createImageTexture() {int[] textureIds = new int[1];//创建纹理GLES20.glGenTextures(1, textureIds, 0);if (textureIds[0] == 0) {return 0;}//绑定纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]);//环绕(超出纹理坐标范围) (s==x t==y GL_REPEAT 重复)GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);//过滤(纹理像素映射到坐标点) (缩小、放大:GL_LINEAR线性)GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);//测试图片GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);//解绑纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);return textureIds[0];}private int createTexture() {int[] textureIds = new int[1];//创建纹理GLES20.glGenTextures(1, textureIds, 0);if (textureIds[0] == 0) {return 0;}//绑定纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]);//环绕(超出纹理坐标范围) (s==x t==y GL_REPEAT 重复)GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);//过滤(纹理像素映射到坐标点) (缩小、放大:GL_LINEAR线性)GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);return textureIds[0];}public int getFboTextureId() {return fboTextureId;}public void onSurfaceChanged(int width, int height) {}
}
渲染类:BitmapRenderTexture.java
import android.content.Context;
import android.opengl.GLES20;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;//纹理 根据坐标系映射
public class BitmapRenderTexture {//顶点坐标static float vertexData[] = { // in counterclockwise order:-1f, -1f, 0.0f, // bottom left1f, -1f, 0.0f, // bottom right-1f, 1f, 0.0f, // top left1f, 1f, 0.0f, // top right};//纹理坐标 对应顶点坐标 与之映射static float textureData[] = { // in counterclockwise order:0f, 1f, 0.0f, // bottom left1f, 1f, 0.0f, // bottom right0f, 0f, 0.0f, // top left1f, 0f, 0.0f, // top right};//每一次取点的时候取几个点static final int COORDS_PER_VERTEX = 3;private final int vertexCount = vertexData.length / COORDS_PER_VERTEX;//每一次取的总的点 大小private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertexprivate Context context;//位置private FloatBuffer vertexBuffer;//纹理private FloatBuffer textureBuffer;private int program;private int avPosition;//纹理位置private int afPosition;public BitmapRenderTexture(Context context) {this.context = context;vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertexData);vertexBuffer.position(0);textureBuffer = ByteBuffer.allocateDirect(textureData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(textureData);textureBuffer.position(0);}public void onSurfaceCreated() {String vertexSource = ShaderUtil.readRawTxt(context, R.raw.vertex_shader);String fragmentSource = ShaderUtil.readRawTxt(context, R.raw.fragment_shader);program = ShaderUtil.createProgram(vertexSource, fragmentSource);if (program > 0) {//获取顶点坐标字段avPosition = GLES20.glGetAttribLocation(program, "av_Position");//获取纹理坐标字段afPosition = GLES20.glGetAttribLocation(program, "af_Position");}}public void draw(int textureId) {//使用程序GLES20.glUseProgram(program);//绑定渲染纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);GLES20.glEnableVertexAttribArray(avPosition);GLES20.glEnableVertexAttribArray(afPosition);//设置顶点位置值GLES20.glVertexAttribPointer(avPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);//设置纹理位置值GLES20.glVertexAttribPointer(afPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureBuffer);//绘制 GLES20.GL_TRIANGLE_STRIP:复用坐标GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);GLES20.glDisableVertexAttribArray(avPosition);GLES20.glDisableVertexAttribArray(afPosition);//解绑纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);}public void onSurfaceChanged(int width, int height) {GLES20.glViewport(0, 0, width, height);}
}
这篇关于OpenGLES帧缓冲的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!