这是完整的代码:


public class FBORenderer2 implements GLSurfaceView.Renderer {

    private static final String TAG = "FBORenderer2";
    
    protected FloatBuffer mVerBuffer = ShaderUtils.floatBuffer(-1.0f,  1.0f,
            -1.0f, -1.0f,
            1.0f, 1.0f,
            1.0f,  -1.0f);
    protected FloatBuffer mTexBuffer = ShaderUtils.floatBuffer(0.0f, 0.0f,
            0.0f,  1.0f,
            1.0f,  0.0f,
            1.0f, 1.0f);

    private Bitmap mBitmap;
    private ByteBuffer mBuffer;

    private final int[] fFrame = new int[1];
    private final int[] fRender = new int[1];
    private final int[] fTexture = new int[3];

    protected int mHPosition;
    protected int mHCoord;
    protected int mHTexture;
    protected int mHMatrix;

    protected int program;

    private Context context;

    private float[] mMatrix = {
            1,0,0,0,
            0,1,0,0,
            0,0,1,0,
            0,0,0,1
    };

    private Callback mCallback;

    public FBORenderer2(Context context){
        this.context = context;
        mMatrix = flip(mMatrix,false,true);
    }

    public static float[] flip(float[] m,boolean x,boolean y){
        if(x||y){
            Matrix.scaleM(m,0,x?-1:1,y?-1:1,1);
        }
        return m;
    }

    public void setBitmap(Bitmap bitmap){
        this.mBitmap = bitmap;
    }

    public void setmCallback(Callback callback){
        this.mCallback = callback;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {

        program = ShaderUtils.createProgram(ShaderUtils.loadFromAssets("base_vertex.vert",context.getResources()),
                ShaderUtils.loadFromAssets("gray_fragment.frag",context.getResources()));
        GLES30.glEnable(GL_DEPTH_TEST);
        mHPosition= GLES30.glGetAttribLocation(program, "vPosition");
        mHCoord=GLES30.glGetAttribLocation(program,"vCoord");
        mHMatrix=GLES30.glGetUniformLocation(program,"vMatrix");
        mHTexture=GLES30.glGetUniformLocation(program,"vTexture");

        // Texture  source Texture
        GLES30.glGenTextures(1, fTexture, 0);
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fTexture[0]);
        GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, mBitmap, 0);

        // RenderBuffer
        GLES30.glGenRenderbuffers(1, fRender, 0);
        GLES30.glBindRenderbuffer(GLES30.GL_RENDERBUFFER, fRender[0]);
        GLES30.glRenderbufferStorage(GLES30.GL_RENDERBUFFER, GLES30.GL_RGBA8, mBitmap.getWidth(), mBitmap.getHeight());
        LogUtils.checkError(TAG,"glRenderbufferStorage");

        // FrameBuffer
        GLES30.glGenFramebuffers(1, fFrame, 0);
        GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fFrame[0]);
        GLES30.glFramebufferRenderbuffer(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_RENDERBUFFER, fRender[0]);
        LogUtils.checkFrameBuffer(TAG,GLES30.glCheckFramebufferStatus(GL_FRAMEBUFFER));

        mBuffer = ByteBuffer.allocate(mBitmap.getWidth() * mBitmap.getHeight() * 4);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES30.glViewport(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        if(mBitmap != null && !mBitmap.isRecycled()){

            clear();
            GLES30.glBindFramebuffer(GL_FRAMEBUFFER,fFrame[0]);
            GLES30.glUseProgram(program);

            // set GLSL's variable value
            GLES30.glUniformMatrix4fv(mHMatrix,1,false, mMatrix,0);
            GLES30.glUniform1i(mHTexture,0);
            GLES30.glEnableVertexAttribArray(mHPosition);
            GLES30.glVertexAttribPointer(mHPosition,2, GLES30.GL_FLOAT, false, 0,mVerBuffer);
            GLES30.glEnableVertexAttribArray(mHCoord);
            GLES30.glVertexAttribPointer(mHCoord, 2, GLES30.GL_FLOAT, false, 0, mTexBuffer);

            // bind source Texture
            GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
            GLES30.glBindTexture(GLES30.GL_TEXTURE_2D,fTexture[0]); 

            GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP,0,4); 
            GLES30.glDisableVertexAttribArray(mHPosition);
            GLES30.glDisableVertexAttribArray(mHCoord);

            GLES30.glReadPixels(0, 0, mBitmap.getWidth(), mBitmap.getHeight(), GLES30.GL_RGBA,
                    GLES30.GL_UNSIGNED_BYTE, mBuffer);
            LogUtils.checkError(TAG,"glReadPixels");

            GLES30.glDeleteTextures(1, fTexture, 0);
            GLES30.glDeleteRenderbuffers(1, fRender, 0);
            GLES30.glDeleteFramebuffers(1, fFrame, 0);

            if(mCallback!=null){
                mCallback.onCall(mBuffer);
            }
            mBitmap.recycle();
            mBuffer.clear();
        }
    }

    private void clear(){
        GLES30.glClearColor(1.0f,1.0f,1.0f,1.0f);
        GLES30.glClear(GL_COLOR_BUFFER_BIT|GLES30.GL_DEPTH_BUFFER_BIT);
    }

    interface Callback{
        void onCall(ByteBuffer data);
    }

}

我调试并获取的mBuffer数据是:

[0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, 
-1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0,
 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0,
 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, +586,656 more]

如果使用纹理附着到FBO替换Renderbuffer,在glReadPixels()之后,我可以得到如下数据:

[-10, -10, -10, -1, -10, -10, -10, -1, -10, -10, -10, -1, -10, -10, -10, -1, -10, -10, 
-10, -1, -10, -10, -10, -1, -10, -10, -10, -1, -11, -11, -11, -1, -11, -11, -11, -1, -11,
 -11, -11, -1, -11, -11, -11, -1, -11, -11, -11, -1, -11, -11, -11, -1, -11, -11, -11, 
-1, -11, -11, -11, -1, -11, -11, -11, -1, -11, -11, -11, -1, -12, -12, -12, -1, -11, -11, 
-11, -1, -11, -11, -11, -1, -11, -11, -11, -1, -11, -11, -11, -1, -11, -11, -11, -1, -11,
 -11, -11, -1, -11, -11, -11, -1, +586,656 more]

这可以在ImageView上显示完整的渲染结果.使用RenderBuffer只能获得黑色视图.

我想这可能是因为glReadPixels()不接受GLES30.glRenderbufferStorage(GLES30.GL_RENDERBUFFER, GLES30.GL_RGBA8, mBitmap.getWidth(), mBitmap.getHeight())的GL_RGBA8,但我不知道如何解决这个问题.

推荐答案

我不确定这为什么不起作用——这可能只是你正在使用的设备上的一个驱动程序错误.

解决方法就是使用纹理.出于所有实际目的,它们与渲染缓冲区相同.

Android相关问答推荐

AdMob:MobileAds. initialize()—java. lang. xml对于某些设备不能强制转换为java. lang. String""

如何将结果从viewModelScope传递到活动

关闭导致Kotlin中的内存泄漏?

是否可以附加事件处理程序,如onClick,拖动到Canvas Composable中绘制的内容,或使用drawBehind修饰符?

学习Kotlin问题.无法理解Modifier参数

为什么 Android Compose 将片段作为参数传递给 Composables 函数?

我的自定义小吃店不适合我的全宽屏幕尺寸

如何知道我的应用程序的新版本是否显示广告?

如何在 React Native 下载文件之前打开文件管理器并 Select 一个目录

Jetpack Compose UI - 在 AlertDialog 中单击时按钮宽度会发生变化

在移动设备上看到时如何增加 PasswordField 文本?

如何使用 Jetpack Compose 制作两个圆圈

单击过go 的文章时 NewsApp 崩溃

我的观点在jetpack compose中相互重叠

Gradle 构建错误:找不到 semver4j-0.16.4-nodeps.jar

Jetpack Compose:mutableStateOf 不随流量更新

在 Compose 中使用 DeepLink 会导致无法向后导航

未使用的内容填充参数

无法再查看 Jetpack Compose 预览.无法实例化一个或多个类 (ComposeViewAdapter)

单击后退按钮时,应用程序会在一秒钟后崩溃