经过大量的研究和挖掘,我找到了glReadPixels的解决方案,以及如何使用PBO来缓冲图像/帧以供以后处理。

因此,我们需要做的第一件事是在GLES2中公开一个额外的函数。在您的应用程序模块中添加一个名为cpp的新目录,然后创建一个名为GlesHelper的新c文件(或者您想要调用它的任何东西)

并粘贴以下代码:

代码语言:javascript运行复制#include

#include

JNIEXPORT void JNICALL

// Change

Java_com_your_full_package_name_helper_GlesHelper_glReadPixels(JNIEnv *env, jobject instance, jint x,

jint y, jint width, jint height,

jint format, jint type) {

// TODO

glReadPixels(x, y, width, height, format, type, 0);

}然后,我们需要向您的项目的根添加一个CMakeFile。右键单击,新文件,输入CMakeLists.txt

并粘贴以下代码

代码语言:javascript运行复制cmake_minimum_required(VERSION 3.4.1)

add_library( # Specifies the name of the library.

native-lib

# Sets the library as a shared library.

SHARED

# Provides a relative path to your source file(s).

src/main//cpp//GlesHelper.c )

target_link_libraries( # Specifies the target library.

native-lib

# Links the target library to the log library

# included in the NDK.

${log-lib}

GLESv2)现在打开您的应用程序/模块build.gradle文件

将其粘贴到Gradle文件的android.defaultConfig部分

代码语言:javascript运行复制externalNativeBuild {

// Encapsulates your CMake build configurations.

cmake {

// Provides a relative path to your CMake build script.

cppFlags "-std=c++11 -fexceptions"

arguments "-DANDROID_STL=c++_shared"

}

}然后将其粘贴到Gradle文件的android部分

代码语言:javascript运行复制externalNativeBuild {

// Encapsulates your CMake build configurations.

cmake {

// Provides a relative path to your CMake build script.

path "CMakeLists.txt"

}

}所以这就是所有的MakeFile和c的东西--所有的设置--让我们转到一些java上

在项目中创建一个与c文件(即com_your_full_package_name_helper = com.your.full.package.name.helper )中的包匹配的新文件

确保这些匹配正确,类名和函数名相同。

所以你的课应该是这样

代码语言:javascript运行复制package com.your.full.package.name.helper;

public class GlesHelper

{

public static native void glReadPixels(int x, int y, int width, int height, int format, int type);

}因为我们已经将本机代码添加到项目中,所以我们需要使用System.loadLibrary(“本机库”)来加载我们的新方法。

在启动下一位之前,将这些成员变量添加到您的渲染器中

代码语言:javascript运行复制/**

* The PBO Ids, increase the allocate amount for more PBO's

* The more PBO's the smoother the frame rate (to an extent)

* Side affect of having more PBO's the frames you get from the PBO's will lag behind by the amount of pbo's

*/

private IntBuffer mPboIds = IntBuffer.allocate(2);;

/**

* The current PBO Index

*/

private int mCurrentPboIndex = 0;

/**

* The next PBO Index

*/

private int mNextPboIndex = 1;所以现在我们需要初始化我们的PBO--这很简单

代码语言:javascript运行复制 // Generate the buffers for the pbo's

GLES30.glGenBuffers(mPboIds.capacity(), mPboIds);

// Loop for how many pbo's we have

for (int i = 0; i < mPboIds.capacity(); i++)

{

// Bind the Pixel_Pack_Buffer to the current pbo id

GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, mPboIds.get(i));

// Buffer empty data, capacity is the width * height * 4

GLES30.glBufferData(GLES30.GL_PIXEL_PACK_BUFFER, capacity, null, GLES30.GL_STATIC_READ);

}

// Reset the current buffer so we can draw properly

GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, 0);然后,在开始绘制调用此方法之前,这将将像素数据读入pbo,交换缓冲区,并允许您访问像素数据。

代码语言:javascript运行复制/**

* Reads the pixels from the PBO and swaps the buffers

*/

private void readPixelsFromPBO()

{

// Bind the current buffer

GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, mPboIds.get(mCurrentPboIndex));

// Read pixels into the bound buffer

GlesHelper.glReadPixels(0, 0, mViewWidth, mViewHeight, GLES20.GL_RGBA, GLES30.GL_UNSIGNED_BYTE);

// Bind the next buffer

GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, mPboIds.get(mNextPboIndex));

// Map to buffer to a byte buffer, this is our pixel data

ByteBuffer pixelsBuffer = (ByteBuffer) GLES30.glMapBufferRange(GLES30.GL_PIXEL_PACK_BUFFER, 0, mViewWidth * mViewHeight * 4, GLES30.GL_MAP_READ_BIT);

if(mSkipFirstFrame)

{

// Skip the first frame as the PBO's have nothing in them until the second render cycle

}

// Set skip first frame to true so we can begin frame processing

mSkipFirstFrame = true;

// Swap the buffer index

mCurrentPboIndex = (mCurrentPboIndex + 1) % mPboIds.capacity();

mNextPboIndex = (mNextPboIndex + 1) % mPboIds.capacity();

// Unmap the buffers

GLES30.glUnmapBuffer(GLES30.GL_PIXEL_PACK_BUFFER);

GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, GLES20.GL_NONE);

GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, GLES20.GL_NONE);

}回到我最初的问题,我们的Redner/onDrawMethod会是这样的。

代码语言:javascript运行复制 // Use the OpenGL Program for rendering

GLES20.glUseProgram(mProgram);

// If the Texture Matrix is not null

if (textureMatrix != null)

{

// Apply the Matrix

GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, textureMatrix, 0);

}

// Apply the Matrix

GLES20.glUniformMatrix4fv(mMVPMatrixLoc, 1, false, mMvpMatrix, 0);

// Bind the Texture

GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureID);

// Draw the texture

GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, GLConstants.VERTEX_NUM);

// Unbind the Texture

GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);

// Read from PBO

readPixelsFromPBO()我希望这能帮助那些在使用glReadPixels的性能上遇到类似问题的人,或者至少是努力实现PBO的人。