能否将Android View渲染到OpenGL FBO或纹理中?

13

是否可能将一个视图(比如WebView)渲染到FBO中,以便在OpenGL组合中用作纹理?


持续更新?还是只需一次性快照? - kabuko
据我所知,不行。AFAIK,你最好的选择是将View渲染为Bitmap,并使用GLUtils将其分配给纹理。 - harism
@harism 我无法想象这样做的帧率会很高。一定有比那更好的方法。 - bobpoekert
3个回答

19

我整合了一个完整的演示项目,在此repo中可找到,它以高效的方式实时将视图渲染成GL纹理,作为示例展示了如何将WebView实时渲染为GL纹理。

此外,这个项目的简短代码可以看起来像下面这样(取自上述repo的演示项目):

public class GLWebView extends WebView {

    private ViewToGLRenderer mViewToGLRenderer;
    ...
    // drawing magic
    @Override
    public void draw( Canvas canvas ) {
        //returns canvas attached to gl texture to draw on
        Canvas glAttachedCanvas = mViewToGLRenderer.onDrawViewBegin();
        if(glAttachedCanvas != null) {
            //translate canvas to reflect view scrolling
            float xScale = glAttachedCanvas.getWidth() / (float)canvas.getWidth();
            glAttachedCanvas.scale(xScale, xScale);
            glAttachedCanvas.translate(-getScrollX(), -getScrollY());
            //draw the view to provided canvas
            super.draw(glAttachedCanvas);
        }
        // notify the canvas is updated
        mViewToGLRenderer.onDrawViewEnd();
    }

    ...
}


public class ViewToGLRenderer implements GLSurfaceView.Renderer{

    private SurfaceTexture mSurfaceTexture;
    private Surface mSurface;

    private int mGlSurfaceTexture;
    private Canvas mSurfaceCanvas;

    ...

    @Override
    public void onDrawFrame(GL10 gl){
        synchronized (this){
            // update texture
            mSurfaceTexture.updateTexImage();
        }
   }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height){
        releaseSurface();
        mGlSurfaceTexture = createTexture();
        if (mGlSurfaceTexture > 0){
            //attach the texture to a surface.
            //It's a clue class for rendering an android view to gl level
            mSurfaceTexture = new SurfaceTexture(mGlSurfaceTexture);
            mSurfaceTexture.setDefaultBufferSize(mTextureWidth, mTextureHeight);
            mSurface = new Surface(mSurfaceTexture);
        }

    }

    public Canvas onDrawViewBegin(){
        mSurfaceCanvas = null;
        if (mSurface != null) {
            try {
                mSurfaceCanvas = mSurface.lockCanvas(null);
            }catch (Exception e){
                Log.e(TAG, "error while rendering view to gl: " + e);
            }
        }
        return mSurfaceCanvas;
    }

    public void onDrawViewEnd(){
        if(mSurfaceCanvas != null) {
            mSurface.unlockCanvasAndPost(mSurfaceCanvas);
        }
        mSurfaceCanvas = null;
    }
}

演示输出截图:


是的,它可以工作。但视图仍需要添加到 Activity 中。我们能否在不将它们添加到可见布局中的情况下呈现它们? - neoexpert
这种方法存在问题,因为WebView现在接受屏幕上的所有触摸事件。没有一个层用于将实际触摸事件的位置转换为虚拟触摸事件,并将其映射到webview的GL表示形式。 - Jherico
@virus 有没有一种方法可以呈现整个应用程序,而不仅仅是一个WebView? - Timotej Leginus
@TimotejLeginus,我不这么认为,但这取决于你所说的“整个应用程序”的含义。您可以将任何视图呈现到GL中,并根据您的情况进行适当处理。此外,根据您的用例,使用Unity、AndEngine等引擎可能会有所帮助。 - vir us
实际上,我正在尝试将纹理传递给Unity。我想知道是否有一种简单的方法可以将整个应用程序渲染到纹理中。 - Timotej Leginus

13

我发现并非所有的视图都可以绘制。TextureView 无法像这样绘制。你能解决吗? - dragonfly
如果我使用TextureView,我发现TextureView.OnFrameAvailableListener的onSurfaceTextureAvailable回调没有被调用。为什么TextureView不能像这样绘制? - dragonfly

0

至少有人成功地以这种方式呈现了文本:

在Android上使用OpenGL渲染文本

它描述了我使用OpenGL ES 1.0和TrueType/OpenType字体文件高效呈现高质量动态文本的方法。

[...]

整个过程实际上非常简单。我们生成位图(作为纹理),计算并存储每个字符的大小以及其在纹理上的位置(UV坐标)。还有一些其他细节,但我们会讲到那些内容。
OpenGL ES 2.0版本:https://github.com/d3kod/Texample2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接