JavaScript-WebGL2学习笔记五-离屏渲染

Author: kagula

Date: 2018-03-30

Description:

          这是我《WebGL Lesson 16 – rendering to textures》的学习笔记。

源文地址:http://learningwebgl.com/blog/?p=1786

Content:

WebGL中离屏渲染有三个步骤组成:

[第一步]新建frame buffer同frame buffer关联的texture

[第二步]render到frame buffer, 这样同frame buffer关联的texture被绘制。

[最后一步]像使用普通texture一样,使用刚才绘制好的texture.

第一步:先要建frame buffer,并同texture对象和render buffer做关联,如下

    var rttFramebuffer;
    var rttTexture;

    function initTextureFramebuffer() {
        //create frame buffer
        rttFramebuffer = gl.createFramebuffer();
        gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer);
        rttFramebuffer.width = 512;
        rttFramebuffer.height = 512;

        //create texture
        rttTexture = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, rttTexture);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
        gl.generateMipmap(gl.TEXTURE_2D);

        //把texture的图片数据指针注销(交给frame buffer管理)
        gl.texImage2D(gl.TEXTURE_2D, //指定目标纹理,这个值必须是gl.TEXTURE_2D
        0, // 执行细节级别。0是最基本的图像级别,n表示第N级贴图细化级别
        gl.RGBA, //internalFormat, 指定纹理中的颜色组件。可选的值有GL_ALPHA,GL_RGB,GL_RGBA,GL_LUMINANCE, GL_LUMINANCE_ALPHA 等几种。
        rttFramebuffer.width, rttFramebuffer.height, //纹理图像的宽、高度,必须是2的n次方。纹理图片至少要支持64个材质元素的宽、高度
        0, //边框的宽度。必须为0。
        gl.RGBA, //源数据的颜色格式, 不需要和internalFormat取值必须相同。
        gl.UNSIGNED_BYTE, //源数据分量的数据类型。
        null);//内存中指向图像数据的指针

        //create render buffer
        var renderbuffer = gl.createRenderbuffer();
        gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
        //设置当前工作的渲染缓冲的存储大小
        gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, //这两个参数是固定的
        rttFramebuffer.width, rttFramebuffer.height);

        //texture绑定到frame buffer中
        //https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/framebufferTexture2D
        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 
        gl.TEXTURE_2D, //target
        rttTexture, //source, A WebGLTexture object whose image to attach.
        0);//A GLint specifying the mipmap level of the texture image to be attached. Must be 0.


        //把render buffer绑定到frame buffer上
        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, 
        gl.RENDERBUFFER, //renderBufferTarget, A GLenum specifying the binding point (target) for the render buffer.
        renderbuffer);//A WebGLRenderbuffer object to attach.

        //unbind
        gl.bindTexture(gl.TEXTURE_2D, null);
        gl.bindRenderbuffer(gl.RENDERBUFFER, null);
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    }

上面的代码新建了rttFrameBuffer对象。

第二步:render到纹理,并让这个纹理生成MipMap

我们drawElement的时候,可以render到这个对象中。

        gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer);
        drawSceneOnLaptopScreen();

注意上面的第一行代码,我们让当前render, render到rttFramebuffer中。

drawSceneOnLaptopScreen函数中的代码片段如下(就跟原来的普通render一样写代码,只不过这次是render到rttFrameBuffer中)

        gl.viewport(0, 0, rttFramebuffer.width, rttFramebuffer.height);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

        mat4.perspective(45, laptopScreenAspectRatio, 0.1, 100.0, pMatrix);

。。。

gl.drawElements(gl.TRIANGLES, moonVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);

。。。

gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);

由于rttFrameBuffer同rttTexture关联,上面的代码把scene render到了rttTexture上去。

再用下面的代码为rttTexture生成MipMap

        gl.bindTexture(gl.TEXTURE_2D, rttTexture);
        gl.generateMipmap(gl.TEXTURE_2D);
        gl.bindTexture(gl.TEXTURE_2D, null);

最后一步:

用下面的代码解除同frame buffer的绑定,这样我们才能render到用户可见的屏幕上。

        gl.bindFramebuffer(gl.FRAMEBUFFER, null);

最后可以像使用普通纹理对象一样使用rttTexture。

如下

        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, rttTexture);
        gl.uniform1i(shaderProgram.samplerUniform, 0);

        setMatrixUniforms();
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, laptopScreenVertexPositionBuffer.numItems);

Lesson16包含了太多不必要的代码,现在通过整理,可以看到实现离屏渲染不是件很难的事。


猜你喜欢

转载自blog.csdn.net/lee353086/article/details/79759414