化繁为简 -webgl -framebuffer的使用

fbo在webgl中很常见,但在cesium的开发工作中基本用不到,而源码修改时,这又是必经的一条道,因此,转头回去学习了一下fbo的使用;由于原文的fbo使用了贴图,相对复杂,不利于理解,本人在理解的时候就移除了部分内容;

fbo一词尝与离屏渲染相关联,

webgl系统默认绑定的是窗口缓冲区,即绑定的shader program 会把对应的数据直接绘制到屏幕上,但是很多时候,绘制的直接结果不是我们想要的,因此可以使用fbo 即帧缓冲区。

渲染流程图,实际上渲染到fbo与渲染到屏幕上的流程没有任何差异,只有中间绑定帧缓冲区与解绑的操作。 渲染流程如下。

首先是shader准备两份,一份为取为屏幕缓冲区渲染创建的,需要片元由传入的纹理决定;另一份为离屏渲染使用的,简单的写为了 全是红色

 

    

 

        离屏渲染的shder                                                                                                                     屏幕渲染的shader

 

后续的逻辑基本就如流程图中的一致了,参照理解即可

简化fbo的渲染逻辑后的代码为

// HelloQuad.js (c) 2012 matsuda
// Vertex shader program
var VSHADER_SOURCE =
    'attribute vec4 a_Position;\n' +
    'void main() {\n' +
    '  gl_Position = a_Position;\n' +
    '}\n';

// Fragment shader program
var FSHADER_SOURCE =
    'void main() {\n' +
    '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
    '}\n';
// Size of off screen
var OFFSCREEN_WIDTH = 256;
var OFFSCREEN_HEIGHT = 256;


//顶点坐标,纹理坐标,模型视图矩阵,将顶点着色器中的纹理坐标传递给片元v_TexCoord纹理坐标
var m_VSHADER_SOURCE =
    'attribute vec4 a_Position;\n' +
    'void main() {\n' +
    '  gl_Position = a_Position;\n' +
    '}\n';

// 采样器,纹理坐标,纹理着色片元
var m_FSHADER_SOURCE =
    '#ifdef GL_ES\n' +
    'precision mediump float;\n' +
    '#endif\n' +
    'uniform sampler2D u_Sampler;\n' +
    'void main() {\n' +
    '  gl_FragColor = texture2D(u_Sampler, vec2(0.5,0.5));\n' +
    '}\n'


function main() {
    // Retrieve <canvas> element
    var canvas = document.getElementById('webgl');

    // Get the rendering context for WebGL
    var gl = getWebGLContext(canvas);

    // var ext = gl.getExtension('WEBGL_draw_buffers')
    if (!gl) {
        console.log('Failed to get the rendering context for WebGL');
        return;
    }

   let initProgram =  initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)

    var fbo = initFramebufferObject(gl);

    // Write the positions of vertices to a vertex shader
    var n = initVertexBuffers(gl);

       //绑定帧缓冲区
    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);              // Change the drawing         destination to FBO
    gl.viewport(0, 0, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT); // Set a viewport for FBO
    //设置背景色
    gl.clearColor(0.2, 0.2, 0.4, 1.0); // Set clear color (the color is slightly changed)
    //清空颜色和深度缓冲区
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);  // Clear FBO

    //一直前清空
    if (n < 0) {
        console.log('Failed to set the positions of the vertices');
        return;
    }

    // Specify the color for clearing <canvas>
    gl.clearColor(0, 0, 0, 1);

    // Clear <canvas>
    gl.clear(gl.COLOR_BUFFER_BIT);


    // Draw the rectangle
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);        // Change the drawing destination to color buffer
    //重新设置屏幕渲染的视点
    gl.viewport(0, 0, canvas.width, canvas.height);  // Set the size of viewport back to that of <canvas>


    let newProgram =  initShaders(gl, m_VSHADER_SOURCE, m_FSHADER_SOURCE);
    // Bind the texture object to the target
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, fbo.texture);
     initVertexBuffers(gl);
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);


}
function initFramebufferObject(gl) {
    var framebuffer, texture, depthBuffer;


    // 创建FBO 帧缓冲区
    framebuffer = gl.createFramebuffer();

    // Create a texture object and set its size and parameters
    texture = gl.createTexture(); // Create a texture object
    gl.bindTexture(gl.TEXTURE_2D, texture); // Bind the object to target
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    framebuffer.texture = texture; // Store the texture object


    // 将帧缓冲区绑定到程序上
    gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);



    // The WebGLRenderingContext.framebufferTexture2D() method of the WebGL API attaches a texture to a WebGLFramebuffer.
    //将framebufer渲染到一个纹理附件中

    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);


    // 创建渲染缓冲区
    depthBuffer = gl.createRenderbuffer(); // Create a renderbuffer object
    gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer); // Bind the object to target
    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT);
    //将帧缓冲区绑定到渲染缓冲区上
    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);


    // 解除帧缓冲区绑定
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    //解除纹理
    gl.bindTexture(gl.TEXTURE_2D, null);
    //解除 渲染缓冲区
    gl.bindRenderbuffer(gl.RENDERBUFFER, null);


    return framebuffer;
}

function initVertexBuffers(gl) {
    var vertices = new Float32Array([
        -0.5, 0.5,   -0.5, -0.5,      0.5, 0.5, 0.5, -0.5
    ]);
    var n = 4; // The number of vertices

    // Create a buffer object
    var vertexBuffer = gl.createBuffer();
    if (!vertexBuffer) {
        console.log('Failed to create the buffer object');
        return -1;
    }

    // Bind the buffer object to target
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    // Write date into the buffer object
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

    var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
    if (a_Position < 0) {
        console.log('Failed to get the storage location of a_Position');
        return -1;
    }
    // Assign the buffer object to a_Position variable
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

    // Enable the assignment to a_Position variable
    gl.enableVertexAttribArray(a_Position);

    return n;
}

 

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值