安卓opengles教程_Android opengl

安卓opengles教程_Android opengl当需要对纹理进行多次渲染时,而这些渲染采样是不需要展示给用户看的,就可以用一个单独的缓冲对象(离屏渲染)来存储多次渲染采样的结果,等处理完后再显示到窗口上

当需要对纹理进行多次渲染时,而这些渲染采样是不需要展示给用户看的,就可以用一个单独的缓冲对象(离屏渲染)
来存储多次渲染采样的结果,等处理完后再显示到窗口上。

FBO的创建有以下步骤:

  1. 创建FBO
  2. 绑定FBO
  3. 设置FBO分配内存大小
  4. 把纹理绑定到FBO
  5. 检查FBO绑定是否成功
  6. 解绑FBO

FBO的使用有以下步骤:

  1. 绑定FBO
  2. 获取需要绘制的图片纹理,然后绘制渲染
  3. 解绑FBO
  4. 把绑定到FBO的纹理绘制渲染出来

1. FBO的创建

在onSurfaceCreated时创建:

  		//创建 fbo
        int[] fbo_s = new int[1];
        GLES20.glGenBuffers(1, fbo_s, 0);
        fbo = fbo_s[0];
        //使 fbo 成为 fbo对象 GL_FRAMEBUFFER
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo);

        //创建 1个 fbo 纹理 fboTextureID
        int[] textureIds = new int[1];
        GLES20.glGenTextures(1, textureIds, 0);//第三个参数是指从哪儿开始取
        fboTextureID = textureIds[0];
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fboTextureID);// 在没设置点的情况下默认是绑定 0号纹理

        //设置纹理的环绕方式
        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);
        //设置纹理的过滤方式
        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);

2.使用FBO

在onDrawFrame时使用:

 		//绑定 fbo 开始使用 FBO
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo);

        //绑定 imgTextureId 开始使用纹理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, imgTextureId);
        //绘制
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        //解绑 FBO纹理
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

        yFboRender.onDraw(fboTextureID);

3. 完整代码

package com.york.media.opengl.demo.fbo;

import android.content.Context;
import android.opengl.GLES20;
import com.york.media.opengl.R;
import com.york.media.opengl.egl.TextureUtils;
import com.york.media.opengl.egl.YGLSurfaceView;
import com.york.media.opengl.egl.YShaderUtil;
import com.york.media.opengl.utils.LogUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

/** * author : York * date : 2020/12/20 19:42 * desc : FBO 帧缓冲对象 * <p> * 当需要对纹理进行多次渲染时,而这些渲染采样是不需要展示给用户看的,就可以用一个单独的缓冲对象(离屏渲染) * 来存储多次渲染采样的结果,等处理完后再显示到窗口上。 */
public class YUsedFboRender implements YGLSurfaceView.YGLRender { 
   

    private final Context mContext;
    private final FloatBuffer vertexBuffer;
    private final FloatBuffer fragmentBuffer;
    private int program;
    private int vPosition;
    private int fPosition;

    private int fboTextureID;
    private int vbo;
    private int fbo;

    private int imgTextureId;
    private int fboWidth;
    private int fboHeight;

    private final YFboRender yFboRender;
    //顶点坐标
    float[] vertexData = { 
   
            -1f, -1f,
            1f, -1f,
            -1f, 1f,
            1f, 1f
    };

    //纹理坐标
    float[] fragmentData = { 
   
            0f, 1f,
            1f, 1f,
            0f, 0f,
            1f, 0f
    };


    public YUsedFboRender(Context context, int width, int height) { 
   
        this.mContext = context;
        fboWidth = width;
        fboHeight = height;
        yFboRender = new YFboRender(context);
        //读取顶点坐标
        vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertexData);
        vertexBuffer.position(0);

        //读取纹理坐标
        fragmentBuffer = ByteBuffer.allocateDirect(fragmentData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(fragmentData);
        fragmentBuffer.position(0);

    }

    @Override
    public void onSurfaceCreated() { 
   
        yFboRender.onCreate();

        //加载顶点着色器 shader
        String vertexSource = YShaderUtil.getRawResource(mContext, R.raw.screen_vert);
        //加载片元着色器 shader
        String fragmentSource = YShaderUtil.getRawResource(mContext, R.raw.screen_frag);
        //获取源程序
        program = YShaderUtil.createProgram(vertexSource, fragmentSource);
        //从渲染程序中得到着顶点色器中的属性
        vPosition = GLES20.glGetAttribLocation(program, "vPosition");
        //从渲染程序中得到片元着色器中的属性
        fPosition = GLES20.glGetAttribLocation(program, "fPosition");
        //创建 VBO
        int[] vbo_s = new int[1];
        GLES20.glGenBuffers(1, vbo_s, 0);
        vbo = vbo_s[0];
        //绑定 VBO
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo);

        //分配 VBO需要的缓存大小
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4 + fragmentData.length * 4, null, GLES20.GL_STATIC_DRAW);
        //设置顶点坐标数据的值到 VBO
        GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, vertexData.length * 4, vertexBuffer);
        //设置纹理坐标数据的值到 VBO
        GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4, fragmentData.length * 4, fragmentBuffer);
        //解绑 VBO,指的是离开对 VBO的配置,进入下一个状态
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

        //创建 fbo
        int[] fbo_s = new int[1];
        GLES20.glGenBuffers(1, fbo_s, 0);
        fbo = fbo_s[0];
        //使 fbo 成为 fbo对象 GL_FRAMEBUFFER
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo);

        //创建 1个 fbo 纹理 fboTextureID
        int[] textureIds = new int[1];
        GLES20.glGenTextures(1, textureIds, 0);//第三个参数是指从哪儿开始取
        fboTextureID = textureIds[0];
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fboTextureID);// 在没设置点的情况下默认是绑定 0号纹理

        //设置纹理的环绕方式
        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);
        //设置纹理的过滤方式
        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);

        LogUtil.d("fbo_Width=" + fboWidth + ",fboHeight=" + fboHeight);
        //分配FBO内存大小
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, fboWidth, fboHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
        //把 2D纹理 fboTextureID 绑定到 FBO 对象
        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, fboTextureID, 0);
        //检查FBO绑定是否成功
        if (GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER) != GLES20.GL_FRAMEBUFFER_COMPLETE) { 
   
            LogUtil.e("fbo bind error !");
        }

        //绑定纹理到 fbo成功后 退出纹理绑定,进入下一环节
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

        imgTextureId = TextureUtils.createImageTexture(mContext, R.drawable.nobb);

    }

    @Override
    public void onSurfaceChanged(int width, int height) { 
   
        //设置窗口大小
        GLES20.glViewport(0, 0, width, height);
        fboWidth = width;
        fboHeight = height;
        yFboRender.onChange(fboWidth, fboHeight);
    }

    @Override
    public void onDrawFrame() { 
   
        //清除屏幕,此处用的是红色
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glClearColor(1f, 0f, 0f, 1f);
        //使用着色器源程序
        GLES20.glUseProgram(program);

        //开始使用 VBO
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo);
        //使能顶点属性数组,使之有效
        GLES20.glEnableVertexAttribArray(vPosition);
        //使能之后,为顶点属性赋值,从VBO里获取 绑定顶点坐标; 注意:最后一个参数如果是 vertexBuffer,那么就没有用到 VBO,那就还是从CPU里取顶点
        GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8, 0);
        //使能片元属性数组,使之有效
        GLES20.glEnableVertexAttribArray(fPosition);
        //使能之后,为片元属性赋值,从VBO里获取 绑定纹理坐标; 注意:最后一个参数为 VBO里的偏移量
        GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 8, vertexData.length * 4);
        //退出 VBO的使用
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

        //绑定 fbo 开始使用 FBO
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo);

        //绑定 imgTextureId 开始使用纹理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, imgTextureId);
        //绘制
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        //解绑 FBO纹理
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

        yFboRender.onDraw(fboTextureID);

    }
}

package com.york.media.opengl.demo.fbo;

import android.content.Context;
import android.opengl.GLES20;

import com.york.media.opengl.R;
import com.york.media.opengl.egl.YShaderUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

/** * author : York * date : 2020/12/20 20:29 * desc : */
public class YFboRender { 
   

    private final Context context;
    private final FloatBuffer vertexBuffer;
    private final FloatBuffer fragmentBuffer;
    private int vPosition;
    private int fPosition;
    private int program;
    private int vbo;


    private final float[] vertexData = { 
   
            -1f, -1f,
            1f, -1f,
            -1f, 1f,
            1f, 1f
    };
    //因为 fbo的片元坐标系与安卓的不一样,所以看上去是倒的
    private final float[] fragmentData = { 
   
            0f, 0f,
            1f, 0f,
            0f, 1f,
            1f, 1f
    };

    public YFboRender(Context context) { 
   
        this.context = context;

        vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(vertexData);
        vertexBuffer.position(0);

        fragmentBuffer = ByteBuffer.allocateDirect(fragmentData.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(fragmentData);
        fragmentBuffer.position(0);

    }

    public void onCreate() { 
   

        String vertexSource = YShaderUtil.getRawResource(context, R.raw.screen_vert);
        String fragmentSource = YShaderUtil.getRawResource(context, R.raw.screen_frag);

        program = YShaderUtil.createProgram(vertexSource, fragmentSource);

        vPosition = GLES20.glGetAttribLocation(program, "vPosition");
        fPosition = GLES20.glGetAttribLocation(program, "fPosition");

        int[] vbo_s = new int[1];
        GLES20.glGenBuffers(1, vbo_s, 0);
        vbo = vbo_s[0];

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo);
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4 + fragmentData.length * 4, null, GLES20.GL_STATIC_DRAW);
        GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, vertexData.length * 4, vertexBuffer);
        GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4, fragmentData.length * 4, fragmentBuffer);
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
    }

    public void onChange(int width, int height) { 
   
        GLES20.glViewport(0, 0, width, height);
    }

    public void onDraw(int textureId) { 
   

        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glClearColor(0f, 1f, 0f, 1f);
        GLES20.glUseProgram(program);
        //使用 vbo
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo);
        GLES20.glEnableVertexAttribArray(vPosition);
        GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8, 0);
        GLES20.glEnableVertexAttribArray(fPosition);
        GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 8, vertexData.length * 4);
        //解绑vbo,退出使用vbo 进入下一环节,绘制纹理
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

        //绑定纹理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        //绘制纹理
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        //解绑纹理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

    }
}

效果依旧杠杠滴:

安卓opengles教程_Android opengl

今天的文章安卓opengles教程_Android opengl分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/81507.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注