glReadPixels + FBO无效

时间:2014-07-10 16:34:24

标签: android opengl-es-2.0

在Android上 - ES 2.通过调用glReadPixels + FBO从帧缓冲区读取。但是,字节数组是0.有趣的是,当我删除绑定代码(保留glReadPixels)时,它可以工作。

让我想知道我是否没有正确绑定缓冲区,但是当我检查帧缓冲区状态(glCheckFramebufferStatus)时,我得到了GLES20.GL_FRAMEBUFFER_COMPLETE。 知道我做错了吗?

    int frameIdIndex=0,renderIdIndex=1,textureIdIndex=2;
    int[] bufferId=new int[3];

    Bitmap takeOne(Context cntxt) {

            DisplayMetrics dm = cntxt.getResources().getDisplayMetrics();
            int width = dm.widthPixels;
            int height = dm.heightPixels;

            //id  index  0 frameId, 1 renderId 2 textureId;

            GLES20.glGenFramebuffers(1,bufferId,frameIdIndex);
            GLES20.glGenRenderbuffers(1, bufferId, renderIdIndex);
            GLES20.glGenTextures(1, bufferId, textureIdIndex);

            // bind texture and load the texture mip-level 0
            // texels are RGB565
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,bufferId[textureIdIndex]);
            GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,0,GLES20.GL_RGBA,width,height,0,GLES20.GL_RGBA,GLES20.GL_UNSIGNED_SHORT_5_6_5,null);

            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_MAG_FILTER, GLES20.GL_LINEAR);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);


            // bind renderbuffer and create a 16-bit depth buffer
            // width and height of renderbuffer = width and height of
            // the texture
            GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, bufferId[renderIdIndex]);
            GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER,GLES20.GL_DEPTH_COMPONENT16,width,height);

            //bind the frameBuffer;
            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,bufferId[frameIdIndex]);

            //specify texture as color attachment
            GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,GLES20.GL_COLOR_ATTACHMENT0,GLES20.GL_TEXTURE_2D,bufferId[textureIdIndex],0);


            //specify renderbuffer as depth_attachment
            GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER,GLES20.GL_DEPTH_ATTACHMENT,GLES20.GL_RENDERBUFFER,bufferId[renderIdIndex]);


            //check for framebuffer complete
            int status= GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
            if(status !=GLES20.GL_FRAMEBUFFER_COMPLETE) {
                throw new RuntimeException("status:"+status+", hex:"+Integer.toHexString(status));
            }


            int screenshotSize = width * height;
            ByteBuffer bb = ByteBuffer.allocateDirect(screenshotSize * 4);
            bb.order(ByteOrder.nativeOrder());
            GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA,
                    GL10.GL_UNSIGNED_BYTE, bb);

            int pixelsBuffer[] = new int[screenshotSize];
            bb.asIntBuffer().get(pixelsBuffer);
            final Bitmap bitmap = Bitmap.createBitmap(width, height,
                    Bitmap.Config.RGB_565);
            bitmap.setPixels(pixelsBuffer, screenshotSize - width, -width,
                    0, 0, width, height);
            pixelsBuffer = null;

            short sBuffer[] = new short[screenshotSize];
            ShortBuffer sb = ShortBuffer.wrap(sBuffer);
            bitmap.copyPixelsToBuffer(sb);

            // Making created bitmap (from OpenGL points) compatible with
            // Android
            // bitmap
            for (int i = 0; i < screenshotSize; ++i) {
                short v = sBuffer[i];
                sBuffer[i] = (short) (((v & 0x1f) << 11) | (v & 0x7e0) | ((v & 0xf800) >> 11));
            }
            sb.rewind();
            bitmap.copyPixelsFromBuffer(sb);

            // cleanup
            GLES20.glDeleteRenderbuffers(1, bufferId,renderIdIndex);
            GLES20.glDeleteFramebuffers(1, bufferId ,frameIdIndex);
            GLES20.glDeleteTextures(1, bufferId,textureIdIndex);

            return bitmap;
    }

1 个答案:

答案 0 :(得分:0)

您的格式和类型有些混乱。如果您使用glTexImage2D()进行检查,此GL_INVALID_OPERATION应该会给您glGetError()来电:

GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0,
    GLES20.GL_RGBA, width, height, 0,
    GLES20.GL_RGBA, GLES20.GL_UNSIGNED_SHORT_5_6_5, null);

GL_UNSIGNED_SHORT_5_6_5只能使用GL_RGB格式。来自documentation

  

如果type为GL_UNSIGNED_SHORT_5_6_5且格式不是GL_RGB,则会生成GL_INVALID_OPERATION。

要避免此错误情况,请致电:

GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0,
    GLES20.GL_RGB, width, height, 0,
    GLES20.GL_RGB, GLES20.GL_UNSIGNED_SHORT_5_6_5, null);

glReadPixels()调用本身对我来说很好,所以我相信一旦你有一个有效的纹理要渲染它就应该有效。

bitmap.setPixels()电话可能有问题。文档说它期望ARGB颜色,你将在这里使用RGBA。但这超出了你问题的主要范围。