OpenGLES ,为什么 glReadPixels() 不能从 FBO 的 Renderbuffer 的颜色缓冲区读取数据?



这是完整的代码:


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只得到黑色视图。

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

我不知道为什么这不起作用——这可能只是你使用的设备上的驱动程序错误。

解决方案只是使用纹理。出于所有实际目的,它们与Renderbuffer相同。

最新更新