WebGL2系列之多采樣渲染緩衝對象

在好久好久之前,盤古開闢了天地,他的頭頂着天,腳踩着地,最後他掛了。他的毛髮變成了森林,他的血液變成了河流,他的肌肉變成了大地。。。。。。
卡!
哦,不對,在好久好久之前,你屬於我,我擁有你。
你還有沒有程序員的自我修養啦。
很差意思,串戲了,下面進入。。。主題
本文適合對webgl、計算機圖形學、前端可視化感興趣的讀者。前端

在好久好久之前,使用WebGL1的時候,只能在默認的繪製的緩衝區上面使用MSAA,而不能在幀緩衝區上面實現,更加形象的說就是:MSAA不能用於離屏渲染。
若是須要在幀緩衝區(離屏渲染)上面實現去鋸齒效果,須要在貼圖內容上使用本身實現的post -process的AA,好比:java

  • FXAA: https://github.com/mattdesl/glsl-fxaa
  • SMAA http://threejs.org/examples/#webgl_postprocessing_smaa
    並且在WebGL1中,不能經過上下文來改變MSAA的採樣數量,這對於WebGL1下的去鋸齒效果有很大影響。

多采樣渲染緩衝對象

在WebGL2中,有了一個新的特性,叫作Multisampled Renderbuffer,恩,中文呢就叫作: 多采樣渲染緩衝對象吧;經過多采樣渲染緩衝對象,能夠在幀緩衝區的渲染緩衝對象上實現MSAA(multisampled antialiasing), 而後經過下面的流程實現最終實現渲染的去鋸齒:node

pre-z pass –> rendering pass to FBO –> postprocessing pass –> render to window複製代碼

函數renderbufferStorageMultisample

和多采樣渲染緩衝對象相關的一個重要的函數就是gl.renderbufferStorageMultisample,下面是函數的簽名:git

gl.renderbufferStorageMultisample(target, samples, internalFormat, width, height);複製代碼

該函數的第一個target是渲染緩衝對象的「目標」,samples表示採樣數,internalFormat表示數據格式,width、height表示渲染緩衝對象的寬高。程序員

下面是使用該函數的簡單代碼片斷:github

var frameBuffer = gl.createFrameBuffer();var colorRenderbuffer = gl.createRenderbuffer();gl.bindRenderbuffer(gl.RENDERBUFFER, colorRenderbuffer);gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, FRAMEBUFFER_SIZE.x, FRAMEBUFFER_SIZE.y);gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorRenderbuffer);gl.bindFramebuffer(gl.FRAMEBUFFER, null);複製代碼

這和webgl1 中建立幀緩衝區的代碼相似,並無太大差異,不一樣的是以下一行:web

gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, FRAMEBUFFER_SIZE.x, FRAMEBUFFER_SIZE.y);複製代碼

經過gl.renderbufferStorageMultisample方法指定了渲染緩衝對象的多重採樣,採樣數是4。數據庫

多采樣紋理附件

多采樣紋理附件又是什麼東西呢,好吧,其實在WebGL2中,沒有這個多采樣紋理附件,在OPENGL纔有,爲何提到這個多采樣紋理附件,大部分時間,咱們的離屏渲染都須要渲染到一個紋理對象上面,才能進一步使用。
在沒有多采樣紋理附件,只有多采樣渲染緩衝對象的狀況下,要實現MSAA,只能渲染到渲染緩衝對象上,可是渲染緩衝對象的內容不能直接傳遞給紋理對象。
那麼應該怎麼作呢? 須要使用另一個重要的函數:bash

gl.blitFramebuffer函數

經過gl.blitFramebuffer函數,能夠把多采樣渲染緩衝對象的內容傳遞給紋理對象。下面是該函數的簽名:架構

gl.blitFramebuffer(srcX0, srcY0, srcX1, srcY1,                        dstX0, dstY0, dstX1, dstY1,                        mask, filter);複製代碼

該函數的做用就是,把一個幀緩衝區(read framebuffer)上的指定區域像素轉移給另一個幀緩衝區(draw framebuffer)上的指定區域。
其中參數srcX0, srcY0, srcX1, srcY1指定read framebuffer上的區域;
dstX0, dstY0, dstX1, dstY1 指定draw framebuffer上的區域; mask指定那個buffer的內容會被copy,可選值:

  • gl.COLOR_BUFFER_BIT
  • gl.DEPTH_BUFFER_BIT
  • gl.STENCIL_BUFFER_BIT
    filter 表示當兩個區域大小不一樣的時候,插值的方式,能夠是如下值:
  • gl.NEAREST
  • gl.LINEAR

下面是代碼片斷:

var renderableFramebuffer = gl.createFramebuffer();......var colorFramebuffer = gl.createFramebuffer();var texture = gl.createTexture();gl.bindTexture(gl.TEXTURE_2D, texture);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, FRAMEBUFFER_SIZE.x, FRAMEBUFFER_SIZE.y, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);gl.bindTexture(gl.TEXTURE_2D, null);gl.bindFramebuffer(gl.FRAMEBUFFER, colorFramebuffer);gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);gl.bindFramebuffer(gl.FRAMEBUFFER, null);// ...// After drawing to the multisampled renderbuffersgl.bindFramebuffer(gl.READ_FRAMEBUFFER, renderableFramebuffer);gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, colorFramebuffer);gl.clearBufferfv(gl.COLOR, 0, [0.0, 0.0, 0.0, 1.0]);gl.blitFramebuffer(    0, 0, FRAMEBUFFER_SIZE.x, FRAMEBUFFER_SIZE.y,    0, 0, FRAMEBUFFER_SIZE.x, FRAMEBUFFER_SIZE.y,    gl.COLOR_BUFFER_BIT, gl.NEAREST);複製代碼

代碼中,首先把場景渲染到renderableFramebuffer中,而後把renderableFramebuffer綁定到目標gl.READ_FRAMEBUFFER,把colorFramebuffer綁定到目標gl.DRAW_FRAMEBUFFER,以後清空DRAW_FRAMEBUFFER上面的顏色關聯對象,而後調用gl.blitFramebuffer方法把renderableFramebuffer的顏色關聯對象上的數據複製到colorFramebuffer的顏色管理對象,colorFramebuffer的顏色關聯對象是一個紋理對象,這樣就把數據從渲染緩衝對象複製到紋理對象上面了。

READ_FRAMEBUFFER和DRAW_FRAMEBUFFER

在webgl1中,幀緩衝區的對象的目標只能是gl.FRAMEBUFFER,而在WebGL2中,增長兩種目標:

  • gl.READ_FRAMEBUFFER
  • gl.DRAW_FRAMEBUFFER
    以上兩種目標分別表示FBO能夠分別進行讀操做和寫操做;這在FBO複製到FBO的時候頗有用,就像前文中所敘述的,能夠把READ_FRAMEBUFFER上的數據複製到DRAW_FRAMEBUFFER上。

參考

https://github.com/mrdoob/three.js/pull/8120
https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/blitFramebuffer
https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/blitFramebuffer
http://www.realtimerendering.com/blog/webgl-2-new-features/
https://www.khronos.org/registry/webgl/specs/latest/2.0/#2.2

歡迎關注公衆號「ITman彪叔」。彪叔,擁有10多年開發經驗,現任公司系統架構師、技術總監、技術培訓師、職業規劃師。熟悉Java、JavaScript、Python語言,熟悉數據庫。熟悉java、nodejs應用系統架構,大數據高併發、高可用、分佈式架構。在計算機圖形學、WebGL、前端可視化方面有深刻研究。對程序員思惟能力訓練和培訓、程序員職業規劃有濃厚興趣。

ITman彪叔公衆號
ITman彪叔公衆號
相關文章
相關標籤/搜索