OpenGL 高级特性

回顾一下渲染管线流程图:


OpenGL 高级特性_第1张图片
OpenGL ES 2.x渲染管线.png

我们学习了顶点、片元着色器,还有纹理,其实可以渲染比较真实的物体了。后面的模板测试、深度测试、颜色混合、帧缓冲就是属于高级特征了。

模板测试

当片元着色器处理完片元之后,模板测试(Stencil Test) 就开始执行了,它能丢弃一些片元。模板测试基于模板缓冲(Stencil Buffer),允许在渲染时更新它来获取有意思的效果。

模板缓冲中的模板值(Stencil Value)通常是8位的,因此每个片元/像素共有256种不同的模板值。

OpenGL 高级特性_第2张图片
屏幕快照 2019-09-04 14.43.07.png

上图很明确的说了模板测试的意图。通过测试的片元会被画出来,不通过就是丢弃。其实就是一个不规则的罩板。通过不通过可以自定义,一般情况下,我们设置0、1两个值表示通不过和通过。

模板测试最经典的例子水塘的倒影。

OpenGL 高级特性_第3张图片
image

上图可以看到树比较大,水面较小,水面倒影只有一部分。只需要画出水面区域的倒影纹理。使用模板很容易做到。

使用模板测试的核心代码如下:

GLES20.glClear(GLES20.GL_STENCIL_BUFFER_BIT);
GLES20.glEnable(GLES20.GL_STENCIL_TEST);
GLES20.glStencilFunc(GLES20.GL_ALWAYS,1,1);
GLES20.glStencilOp(GLES20.GL_KEEP,GLES20.GL_KEEP,GLES20.GL_REPLACE);
GLES20.glDisable(GLES20.GL_STENCIL_TEST);

深度测试

深度测试主要是以防止被遮挡的面渲染,可以提升效率。当深度测试启用的时候, OpenGL 测试深度缓冲区内的深度值。OpenGL 执行深度测试的时候,如果此测试通过,则渲染片元。如果深度测试失败,则丢弃该片元。操作和模板类似。

帧缓冲对象

用于写入颜色值的颜色缓冲,用于写入深度信息的深度缓冲,以及允许我们基于一些条件丢弃指定片段的模板缓冲。把这几种缓冲结合起来叫做帧缓冲(Framebuffer),它被储存于内存中。OpenGL给了我们自己定义帧缓冲的自由,我们可以选择性的定义自己的颜色缓冲、深度和模板缓冲。

我们目前所做的渲染操作都是在默认的帧缓冲之上进行的。当你创建了你的窗口的时候默认帧缓冲就被创建和配置好了。默认的framebuffer连接在屏幕上,表现就是会填充窗口提供的Surface.

当然我也可以通过创建我们自己的帧缓冲获得一种额外的渲染方式。这种渲染是offscreen渲染。

帧缓冲对象结构图

OpenGL 高级特性_第4张图片
屏幕快照 2019-09-04 17.20.19.png

从结构图也可以看出来,framebuffer不是我们理解的buffer,是一个二维数据形式的一块内存。它是一个对象,其实是没有任何存储空间的。可以把它理解为一个插线板,他上面可以附加一些外设(包含两种:texture和render buffer),而这两种外设是需要分配内存的,同时一个framebuffer可以附加的外设的数量也是有限的,这个最大数量GL_MAX_COLOR_ATTACHMENTS与硬件相关,可以通过glget函数查询。

帧缓冲在相机中应用

我们相机的三方图像算法就是使用FBO把图像画到一张Texture上,然后让我们把这张Texture渲染到屏上的。还有一个应用就是获取预览数据做高斯模糊时,也用到了FBO,把预览数据渲染到一个Texture2D的纹理中,然后读出来。这样读取的速度比较快,实测快3-5倍,不同机器表现不一样。

实现代码如下:

 public Bitmap getPreviewBitmapByFBO(SurfaceTexture texture, int textureId,
                                        int width, int height, IPreviewCallbacker callbacker) {
        Bitmap bitmap = null;
        if (texture == null || textureId <= 0) {
            return bitmap;
        }
        texture.getTransformMatrix(mTransformMatrix);
        IntBuffer framebuffer = IntBuffer.allocate(1);
//        IntBuffer maxRenderbufferSize = IntBuffer.allocate(1);
//        IntBuffer depthRenderbuffer = IntBuffer.allocate(1);
        IntBuffer texture2d = IntBuffer.allocate(1);
//        GLES20.glGetIntegerv(GLES20.GL_MAX_RENDERBUFFER_SIZE, maxRenderbufferSize);
        GLES20.glGenFramebuffers(1, framebuffer);
//        GLES20.glGenRenderbuffers(1, depthRenderbuffer);
        GLES20.glGenTextures(1, texture2d);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture2d.get(0));
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height,
                0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
        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.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
//        GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRenderbuffer.get(0));
//        GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16,
//                width, height);

        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebuffer.get(0));
        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
                GLES20.GL_TEXTURE_2D, texture2d.get(0), 0);
        int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
        if (status == GLES20.GL_FRAMEBUFFER_COMPLETE) {
//            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
            boolean handled = callbacker != null ? callbacker.drawOffScreen(texture, textureId, width, height, framebuffer.get(0)) : false;
            if (handled) {
                bitmap = createBitmapFromFBO(0, 0, width, height);
            }
            Log.i(TAG, "getPreviewBitmapByFBO bitmap = " + bitmap);
            if (bitmap == null) {
                drawTexture(textureId);
                bitmap = createBitmapFromFBO(0, 0, width, height);
            }
        }
//        GLES20.glDeleteRenderbuffers(1, depthRenderbuffer);
        GLES20.glDeleteFramebuffers(1, framebuffer);
        GLES20.glDeleteTextures(1, texture2d);
        return bitmap;
    }

 private Bitmap createBitmapFromFBO(int x, int y, int w, int h) {
        int bitmapBuffer[] = new int[w * h];
        int bitmapSource[] = new int[w * h];
        IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer);
        intBuffer.position(0);
        if (x < 0) {
            x = 0;
        }
        if (y < 0) {
            y = 0;
        }
        try {
            GLES20.glReadPixels(x, y, w, h, GL10.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, intBuffer);
            int offset1, offset2;
            for (int i = 0; i < h; i++) {
                offset1 = i * w;
                offset2 = (h - i - 1) * w;
                for (int j = 0; j < w; j++) {
                    int texturePixel = bitmapBuffer[offset1 + j];
                    int blue = (texturePixel >> 16) & 0xff;
                    int red = (texturePixel << 16) & 0x00ff0000;
                    int pixel = (texturePixel & 0xff00ff00) | red | blue;
                    bitmapSource[offset2 + j] = pixel;
                }
            }
        } catch (GLException e) {
            Log.e(TAG, "createBitmapFromGLSurface: " + e.getMessage(), e);
            return null;
        }
        Bitmap bmp = Bitmap.createBitmap(bitmapSource, w, h, Bitmap.Config.ARGB_8888);
        if (IS_SAVE_FOR_TEST) {
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream("/sdcard/screen.png");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }

            bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
            try {
                fos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bmp;
    }

你可能感兴趣的:(OpenGL 高级特性)