首页 文章

Unity3d渲染openGL FBO到android中的纹理(java)

提问于
浏览
0

我正在尝试在Android(java)中为Unity3D创建一个插件,以使用OpenGL纹理进行渲染,获取原生指针并在Unity中编写Quad . 到目前为止我的Unity代码很简单:

// Use this for initialization
void Start () {
    AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); 
    context = jc.GetStatic<AndroidJavaObject>("currentActivity");
    surface2Unity = new AndroidJavaObject("com.everywoah.surface2unity.Surface2Unity"); 

    int i = surface2Unity.Call<int> ("getTextureID");
    t =Texture2D.CreateExternalTexture (1280, 720, TextureFormat.ARGB32, false,false, new IntPtr(i));
    t.filterMode = FilterMode.Bilinear;
    t.wrapMode = TextureWrapMode.Repeat;
    debug.text = "" + i;
    GetComponent<MeshRenderer> ().material.mainTexture = t;
}

// Update is called once per frame
void Update () {
    //transform.Rotate(1f,1f,1f);
    surface2Unity.Call ("draw");
}

在Java中我有:

public MyRenderer(){
    initGL();
    initFBO();
}

private void initGL(){
    GLstatics.checkGlError("initGL_S");

    String vertexShader = "attribute vec4 aPosition;\n" +
            "attribute vec4 aTex;\n" +
            "varying vec2 tex;\n" +
            "void main() {\n" +
            "    gl_Position = aPosition;\n" +
            "tex=aTex.xy;\n" +
            "}";

    String fragmentShader = "precision mediump float;\n" +
            "\n" +
            "void main(){\n" +
            "        gl_FragColor = vec4(1.0,1.0,0.0,1.0);\n" +
            "\n" +
            "}";

    mProgram         = GLstatics.createProgram(vertexShader, fragmentShader);
    maPositionHandle = GLES30.glGetAttribLocation(mProgram, "aPosition");
    maTexHandle = GLES30.glGetAttribLocation(mProgram, "aTex");

    GLstatics.checkGlError("initGL_E");

}


private void initFBO(){
    GLstatics.checkGlError("initFBO_S");


    GLES30.glGenFramebuffers(1, mFboId, 0);
    GLES30.glGenRenderbuffers(1, mRboId, 0);
    GLES30.glGenTextures(1, mTexId, 0);

    GLES30.glGenBuffers(1,buffer, 0);

    GLES30.glBindRenderbuffer(GLES30.GL_RENDERBUFFER, mRboId[0]);
    GLES30.glRenderbufferStorage(GLES30.GL_RENDERBUFFER, GLES30.GL_DEPTH_COMPONENT16, 1280,
            720);

    GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFboId[0]);
    GLES30.glFramebufferRenderbuffer(GLES30.GL_FRAMEBUFFER, GLES30.GL_DEPTH_ATTACHMENT,
            GLES30.GL_RENDERBUFFER, mRboId[0]);

    GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
    GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTexId[0]);
    GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
    GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
    GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
    GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);

    GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, 1280, 720, 0,
            GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null);

    GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0,
            GLES30.GL_TEXTURE_2D, mTexId[0], 0);
    GLstatics.checkGlError("initFBO_E ");
}

public void draw() {
    GLstatics.checkGlError("draw_S");

    GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFboId[0]);
    GLES30.glClearColor(0.0f,0.0f,1.0f,1.0f);

    GLES30.glViewport(0, 0, 1280, 720);

    GLES30.glClear(GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT);

    GLES30.glUseProgram(mProgram);

    mVtxBuf.position(0);
    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, buffer[0]);

    GLES30.glVertexAttribPointer(maPositionHandle,
            3, GLES30.GL_FLOAT, false, 4*(3+2), mVtxBuf);
    GLES30.glEnableVertexAttribArray(maPositionHandle);

    mVtxBuf.position(3);
    GLES30.glVertexAttribPointer(maTexHandle, 2, GLES30.GL_FLOAT, false, 4 * (3 + 2), mVtxBuf);
    GLES30.glEnableVertexAttribArray(maTexHandle);

    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);

    GLstatics.checkGlError("draw_E ");
}

它应该是一个非常简单的代码,只是在蓝色背景中绘制一个黄色矩形,我可以使它在一个Activity中工作 . 这里的问题是我的应用程序看起来像这样:
enter image description here

从我认为我已经搞乱了已经绑定的openGL缓冲区,导致我的矩形的顶点被绘制但内部有一个奇怪的东西 . 我已经尝试保存它们并在绘制函数后绑定它们但我得到了相同的结果 . 我有什么想法我做错了吗?如果可能,我真的想用Java解决这个问题,我有使用NDK的经验 .

2 回答

  • 0

    java side:public int loadImageReturnTexturePtr(String imagePath,int width,int heigh){Log.d(“unity”,“loading image1:”imagePath);

    Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
        Log.d("unity", "Bitmap is: " + bitmap);
    
        int textures[] = new int[1];
        GLES20.glGenTextures(1, textures, 0);
        int textureId = textures[0];
    
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, heigh, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
        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);
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap,0);
    
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        Log.d("unity", "texture id returned: " + textureId);
    
        return textureId;
    }
    

    unity c#side://用于初始化void Start(){AndroidJavaObject mImageLoader = new AndroidJavaObject(“com.dvision.load.LoadTexture”); Texture2D texture2D = new Texture2D(2048,2048,TextureFormat.ARGB32,false);

    int texPtr = mImageLoader.Call <int> ("loadImageReturnTexturePtr", "/sdcard/Lfront.jpg", 2048, 2048);
        Debug.Log ("texture pointer? " + texPtr);
        Texture2D nativeTexture = Texture2D.CreateExternalTexture (2048, 2048, TextureFormat.ARGB32, false, true, new System.IntPtr (texPtr));
        texture2D.UpdateExternalTexture (nativeTexture.GetNativeTexturePtr ());
        gameObject.GetComponent<Renderer> ().material.mainTexture = texture2D;
    }
    

    你可以使用这个函数:Texture2D.CreateExternalTexture它很简单 .

  • 1

    好吧,问题是我必须自己控制EGLContex,我不能在与Unity相同的上下文中进行渲染,所以我需要这个类:

    public class SurfaceManager {
    
    public final static String TAG = "TextureManager";
    
    private static final int EGL_RECORDABLE_ANDROID = 0x3142;
    
    // Contexto donde dibujar
    private EGLContext mEGLContext = null;
    // Contexto compartido entre hilos. Para poder pasar el FBO de un hilo a otro
    private EGLContext mEGLSharedContext = null;
    private EGLSurface mEGLSurface = null;
    private EGLDisplay mEGLDisplay = null;
    
    // La surface donde se va a dibujar
    private Surface mSurface;
    
    /**
     * Creates an EGL context and an EGL surface.
     */
    public SurfaceManager(Surface surface) {
        EGLContext shared = EGL14.eglGetCurrentContext();
        if (surface == null) {
            throw new NullPointerException();
        }
        mSurface = surface;
        mEGLSharedContext = shared;
        Log.d("Surface2UnityDebug", "vamos al setup");
        eglSetup();
    }
    
    // Hace que la surface actual sea esta
    public void makeCurrent() {
        if (!EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext))
            throw new RuntimeException("eglMakeCurrent failed");
    }
    
    // Cambia el buffer donde se está pintando por el de la surface. es decir, guarda lo que se haya pintado.
    public void swapBuffers() {
        EGL14.eglSwapBuffers(mEGLDisplay, mEGLSurface);
    }
    
    /**
     * Sends the presentation time stamp to EGL.  Time is expressed in nanoseconds.
     */
    public void setPresentationTime(long nsecs) {
        EGLExt.eglPresentationTimeANDROID(mEGLDisplay, mEGLSurface, nsecs);
        checkEglError("eglPresentationTimeANDROID");
    }
    
    /**
     * Prepares EGL.  We want a GLES 2.0 context and a surface that supports recording.
     */
    private void eglSetup() {
        mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
        if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
            Log.d("Surface2UnityDebug", "unable to get EGL14 display");
            throw new RuntimeException("unable to get EGL14 display");
        }
        int[] version = new int[2];
        if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) {
            Log.d("Surface2UnityDebug", "unable to initialize EGL14");
            throw new RuntimeException("unable to initialize EGL14");
        }
    
        // Configure EGL for recording and OpenGL ES 2.0.
        int[] attribList;
        attribList = new int[]{
                EGL14.EGL_RED_SIZE, 8,
                EGL14.EGL_GREEN_SIZE, 8,
                EGL14.EGL_BLUE_SIZE, 8,
                EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
                EGL_RECORDABLE_ANDROID, 1,
                EGL14.EGL_NONE
        };
        EGLConfig[] configs = new EGLConfig[1];
        int[] numConfigs = new int[1];
    
        EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length,
                numConfigs, 0);
        checkEglError("eglCreateContext RGB888+recordable ES2");
    
        // Configure context for OpenGL ES 2.0.
        int[] attrib_list = {
                EGL14.EGL_CONTEXT_CLIENT_VERSION, 3,
                EGL14.EGL_NONE
        };
    
        mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], mEGLSharedContext, attrib_list, 0);
        checkEglError("eglCreateContext");
    
        // Create a window surface, and attach it to the Surface we received.
        int[] surfaceAttribs = {
                EGL14.EGL_NONE
        };
        mEGLSurface = EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW);
        checkEglError("eglCreateWindowSurface");
    
    
    }
    
    /**
     * Discards all resources held by this class, notably the EGL context.  Also releases the
     * Surface that was passed to our constructor.
     */
    public void release() {
        if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
            EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE,
                    EGL14.EGL_NO_CONTEXT);
            EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
            EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
            EGL14.eglReleaseThread();
            EGL14.eglTerminate(mEGLDisplay);
        }
        mEGLDisplay = EGL14.EGL_NO_DISPLAY;
        mEGLContext = EGL14.EGL_NO_CONTEXT;
        mEGLSurface = EGL14.EGL_NO_SURFACE;
        mSurface.release();
    }
    
    /**
     * Checks for EGL errors. Throws an exception if one is found.
     */
    private void checkEglError(String msg) {
        int error;
        if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {
            Log.d("Surface2UnityDebug", msg + ": EGL error: 0x" + Integer.toHexString(error));
            throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error));
        }
    }}
    

    和方法:

    // Guarda el estado actual
    public void saveRenderState() {
        mSavedEglDisplay     = EGL14.eglGetCurrentDisplay();
        mSavedEglDrawSurface = EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW);
        mSavedEglReadSurface = EGL14.eglGetCurrentSurface(EGL14.EGL_READ);
        mSavedEglContext     = EGL14.eglGetCurrentContext();
    }
    
    // Carga el estado guardado
    public void restoreRenderState() {
        if (!EGL14.eglMakeCurrent(
                mSavedEglDisplay,
                mSavedEglDrawSurface,
                mSavedEglReadSurface,
                mSavedEglContext)) {
            throw new RuntimeException("eglMakeCurrent failed");
        }
    }
    

    这样我可以调用saveRenderState(),makeCurrent(),draw()和restoreRenderState(),现在一切正常 .

相关问题