我在Android上开发视频应用程序并使用OpenGL通过着色器从相机渲染和过滤视频。我的一个着色器使用两个纹理 - 一个是来自相机的实时帧,另一个是前一个渲染过程结果。所以我需要渲染图片两次 - 屏幕预览和分离纹理下一个渲染通道。为了实现它,我使用Frame Buffer对象。这是我的代码:
对于init帧缓冲区:
private void initPredrawBuffer() {
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
prevBuffer = new int[1];
GLES20.glGenFramebuffers(1, prevBuffer, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, prevBuffer[0]);
prevTexture = new int[1];
GLES20.glGenTextures(1, prevTexture, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, prevTexture[0]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, mFrameWidth, mFrameHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, prevTexture[0], 0);
int[] depthRenderbuffers = new int[1];
GLES20.glGenRenderbuffers(1, depthRenderbuffers, 0);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRenderbuffers[0]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, mFrameWidth, mFrameHeight);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, depthRenderbuffers[0]);
int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
throw new RuntimeException("Incomplete buffer");
}
}
和渲染:
private void draw(boolean offScreen, float[] mvpMatrix, FloatBuffer vertexBuffer, int firstVertex,
int vertexCount, int coordsPerVertex, int vertexStride,
float[] texMatrix, FloatBuffer texBuffer, int textureId, int texStride) {
GlUtil.checkGlError("draw start");
if (offScreen)
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, prevBuffer[0]);
else
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
// Select the program.
GLES20.glUseProgram(firstFrame && firstFrameProgram > 0 ? firstFrameProgram : mProgramHandle);
GlUtil.checkGlError("glUseProgram");
// Set the texture.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);
// Copy the model / view / projection matrix over.
GLES20.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mvpMatrix, 0);
GlUtil.checkGlError("glUniformMatrix4fv");
// Copy the texture transformation matrix over.
GLES20.glUniformMatrix4fv(muTexMatrixLoc, 1, false, texMatrix, 0);
GlUtil.checkGlError("glUniformMatrix4fv");
// Enable the "aPosition" vertex attribute.
GLES20.glEnableVertexAttribArray(maPositionLoc);
GlUtil.checkGlError("glEnableVertexAttribArray");
// Connect vertexBuffer to "aPosition".
GLES20.glVertexAttribPointer(maPositionLoc, coordsPerVertex,
GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
GlUtil.checkGlError("glVertexAttribPointer");
// Enable the "aTextureCoord" vertex attribute.
GLES20.glEnableVertexAttribArray(maTextureCoordLoc);
GlUtil.checkGlError("glEnableVertexAttribArray");
// Connect texBuffer to "aTextureCoord".
GLES20.glVertexAttribPointer(maTextureCoordLoc, 2,
GLES20.GL_FLOAT, false, texStride, texBuffer);
GlUtil.checkGlError("glVertexAttribPointer");
// Setting Light Trails filter params
if (mProgramType == ProgramType.TEXTURE_LIGHT_TRAILS && !firstFrame) {
GLES20.glUniform1i(muTextureNew, 0);
GlUtil.checkGlError("glUniform1i muTextureNew");
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GlUtil.checkGlError("temp glActiveTexture");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, prevTexture[0]);
GlUtil.checkGlError("temp glBindTexture");
GLES20.glUniform1i(muTexturePrev, 1);
GlUtil.checkGlError("glUniform1i muTexturePrev");
GLES20.glUniform1f(muLightTrailsExposure, lightTrailsKernel[0]);
GlUtil.checkGlError("glUniform1f muLightTrailsExposure");
GLES20.glUniform1f(muLightTrailsEcho, lightTrailsKernel[1]);
GlUtil.checkGlError("glUniform1f muLightTrailsEcho");
GLES20.glUniform1f(muLightTrailsLimit, lightTrailsKernel[2]);
GlUtil.checkGlError("glUniform1f muLightTrailsLimit");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GlUtil.checkGlError("temp glActiveTexture");
}
// Draw the rect.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, firstVertex, vertexCount);
GlUtil.checkGlError("glDrawArrays");
GLES20.glFinish();
}
问题是渲染到帧缓冲区不起作用,glReadPixels
总是返回一个空数组。渲染到屏幕工作正常。