java - 使用 GLES20 通过 Android 插件获取位图到 Unity

标签 java android unity3d opengl-es egl

我正在尝试使用 UpdateExternalTextureCreateExternalTexture 将一个简单的位图图像从 android 插件传递到 unity。在文档中它说后者是为了与低级插件一起使用。我使用 Java 代码在其之上。

当我进行任何 GLES20 调用时,我遇到上下文错误:

call to OpenGL ES API with no current context (logged once per thread)

根据这个excellent question这是因为上下文不正确(或没有)。我按照该页面上的说明进行操作,并设法创建了一个上下文。但是,现在他们似乎指的是不同的资源“区域”。我得到的指针是“1”,统一理解为“屏幕上的当前帧”而不是我的位图。所以看起来像这样:

enter image description here

这是我的代码 fragment 。首先是 Unity 部分。这是附加到场景中的游戏对象。

// This function is called shortly after Start
private void TestingTransfer() {
    // get the current activity from unity
    AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    androidActivity = jc.GetStatic<AndroidJavaObject>("currentActivity");
    // create a link to the android plugin
    AndroidJavaObject obj = new AndroidJavaObject("com.test.pc.sample.SampleClass", androidActivity);
    // Make the call to put the bitmap in the graphic memory and get it's PTR
    Int32 texPtr = obj.Call<Int32>("PutBitmapInGraphicsCard");
    Debug.Log("texture pointer == " + texPtr); 
    // Stage the texture in unity
    Texture2D nativeTexture = Texture2D.CreateExternalTexture(100, 100, TextureFormat.ARGB32, false, false, (IntPtr)texPtr);
    // Update it with the new PTR
    nativeTexture.UpdateExternalTexture(nativeTexture.GetNativeTexturePtr());
    // Notify other things in unity that this updated (delegate)
    // I'm using this from another game object to pickup the new texture
    if (OnNewImageReported != null) OnNewImageReported(nativeTexture);
}

现在是 Java 方面。 Unity 通过 AAR 文件使用此代码。

private int PutBitmapInGraphicsCard() {
    final int[] textureHandle = new int[1];
    final Bitmap bitmap = GenerateTestImage(); // this creates a simple bitmap, blank with a blue circle in the center, works fine in android.
    CreateContext(); // look below, it's defined there
    GLES20.glGenTextures(1, textureHandle, 0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
    bitmap.recycle();
    return textureHandle[0];
}

// This function is a (almost) direct copy from the question linked above
public void CreateContext(){
    // gets hold of the display
    EGLDisplay dpy = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
    int[] vers = new int[2];
    EGL14.eglInitialize(dpy, vers, 0, vers, 1);
    // get some basic configs going
    int[] configAttr = {
            EGL14.EGL_COLOR_BUFFER_TYPE, EGL14.EGL_RGB_BUFFER,
            EGL14.EGL_LEVEL, 0,
            EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
            EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT,
            EGL14.EGL_NONE
    };
    EGLConfig[] configs = new EGLConfig[1];
    int[] numConfig = new int[1];
    EGL14.eglChooseConfig(dpy, configAttr, 0,
            configs, 0, 1, numConfig, 0);
    if (numConfig[0] == 0) {
        Log.e("GLEDB-Error", "Could not find/create config!!");
    }
    EGLConfig config = configs[0];
    // creating an offscreen (PBuffer) surface to render stuff
    int[] surfAttr = {
            EGL14.EGL_WIDTH, 100,
            EGL14.EGL_HEIGHT, 100,
            EGL14.EGL_NONE
    };
    EGLSurface surf = EGL14.eglCreatePbufferSurface(dpy, config, surfAttr, 0);
    // create the context
    int[] ctxAttrib = {
            EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
            EGL14.EGL_NONE
    };
    EGLContext ctx = EGL14.eglCreateContext(dpy, config, EGL14.EGL_NO_CONTEXT, ctxAttrib, 0);
    // connect all these things together
    EGL14.eglMakeCurrent(dpy, surf, surf, ctx);
}

因此,如果我对问题的理解是正确的,那么我需要的是引用 unity 用来绘制场景的相同上下文。有没有办法获取/使用它?


解决方案:

根据已接受的答案,主要问题是我使用的是多线程渲染。对于我的用例,这没有区别。

上面的代码并不能立即生效。需要注意的几点:

  • 如果您这样做,请不要创建您自己的上下文。它搞砸了统一并阻止了表面的任何更新(卡住任何绘图)
  • 代码略有不同,不完全确定为什么上面的代码不起作用,但下面的代码可以。

[ 由于 StackOverflow 无法在项目符号点后呈现代码而有意添加的行]

public int PutBitmapInGraphicsCard() {
    final int[] textureHandle = new int[1];
    GLES20.glGenTextures(1, textureHandle, 0);
    final Bitmap bitmap = GenerateTestImage();
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D,0, bitmap, 0);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(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.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
    return textureHandle[0];
}

最佳答案

基于此Manual :

Rendering in Unity can be multithreaded if the platform and number of available CPUs will allow for it. When multithreaded rendering is used, the rendering API commands happen on a thread which is completely separate from the one that runs MonoBehaviour scripts.

您可能打开了多线程渲染,所以可能是这种情况。 您可以尝试将其关闭,看看是否有所不同。

关于java - 使用 GLES20 通过 Android 插件获取位图到 Unity,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47779970/

相关文章:

c# - 为什么不能同时使用 2 个 NetworkManager?

java - 如何在 Linux、Mac 和 Windows 上制作安装程序?

java - Jackson - 使用动态 key 反序列化 json

java - 接收或重新发送android收到的广播

android - 内部错误 : retry receiver class not set yet

c# - 如何使用触摸板 gearVR

java - onClickListener 使用 Butterknife

android - 尝试在Flutter中使用Animator时发生编译错误

android - 尝试更改颜色时资源 $NotFoundException

android - Facebook Analytics for Apps 中未跟踪 Android 上的 Unity 游戏 Activity 安装