Get bitmap to Unity through Android plugin using GLES20

对着背影说爱祢 提交于 2020-01-04 09:22:22

问题


I'm trying to use the UpdateExternalTexture and CreateExternalTexture to pass a simple bitmap image from an android plugin into unity. On the documentation it says the latter is meant to be used with low level plugins. I'm a layer above that with java code.

I'm getting a context error when I do any GLES20 call:

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

According to this excellent question this is because the context isn't right (or has none). I followed the instructions on that page and I managed to create a context. However, now they seem to be referring to different resource "areas". The pointer I'm getting is "1" which unity understands as the "current frame on the screen" instead of my bitmap. So looks like this:

Here's a snippet of my code. First the Unity piece. This is attached to a game object in the scene.

// 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);
}

Now for the Java side. This code is being used by unity through an AAR file.

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);
}

So, if I'm correct in understanding the problem what I need is to refer to the same context that unity is using to draw it's scene. Is there a way to get/use this?


SOLUTION:

As noted per the accepted answer, the main issue was that I'm using multi-threaded rendering. For my use case this makes no difference.

This didn't work straight away from the code above. A few things to note:

  • If you do this don't create your own context. It messes up with unity and prevents any updating of the surface (freezes any drawing)
  • The code is slightly different, not completely sure why the one above didn't work but the following does.

[ line intentionally added since StackOverflow can't render code after bullet points]

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];
}

回答1:


Based on this 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.

You probably have multithreaded rendering turned on, so it might be the case. You could try to turn it off and see if it makes a difference.



来源:https://stackoverflow.com/questions/47779970/get-bitmap-to-unity-through-android-plugin-using-gles20

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!