在很久很久以前私蕾,盤古開辟了天地,他的頭頂著天胡桃,腳踩著地踩叭,最后他掛了。他的毛發(fā)變成了森林翠胰,他的血液變成了河流容贝,他的肌肉變成了大地。之景。斤富。。锻狗。满力。
卡!
哦轻纪,不對油额,在很久很久以前,你屬于我刻帚,我擁有你潦嘶。
你還有沒有程序員的自我修養(yǎng)啦。
不好意思崇众,串戲了掂僵,下面進入。校摩。看峻。主題
本文適合對webgl、計算機圖形學衙吩、前端可視化感興趣的讀者互妓。
在很久很久以前,使用WebGL1的時候坤塞,只能在默認的繪制的緩沖區(qū)上面使用MSAA冯勉,而不能在幀緩沖區(qū)上面實現(xiàn),更加形象的說就是:MSAA不能用于離屏渲染摹芙。
如果需要在幀緩沖區(qū)(離屏渲染)上面實現(xiàn)去鋸齒效果灼狰,需要在貼圖內容上使用自己實現(xiàn)的post -process的AA,比如:
- FXAA: https://github.com/mattdesl/glsl-fxaa
- SMAA http://threejs.org/examples/#webgl_postprocessing_smaa
而且在WebGL1中浮禾,不能通過上下文來改變MSAA的采樣數(shù)量交胚,這對于WebGL1下的去鋸齒效果有很大影響份汗。
多采樣渲染緩沖對象
在WebGL2中,有了一個新的特性蝴簇,叫做Multisampled Renderbuffer杯活,恩,中文呢就叫做: 多采樣渲染緩沖對象吧熬词;通過多采樣渲染緩沖對象旁钧,可以在幀緩沖區(qū)的渲染緩沖對象上實現(xiàn)MSAA(multisampled antialiasing), 然后通過下面的流程實現(xiàn)最終實現(xiàn)渲染的去鋸齒:
pre-z pass –> rendering pass to FBO –> postprocessing pass –> render to window
renderbufferStorageMultisample
和多采樣渲染緩沖對象相關的一個重要的函數(shù)就是gl.renderbufferStorageMultisample,下面是函數(shù)的簽名:
gl.renderbufferStorageMultisample(target, samples, internalFormat, width, height);
該函數(shù)的第一個target是渲染緩沖對象的“目標”,samples表示采樣數(shù)互拾,internalFormat表示數(shù)據格式歪今,width、height表示渲染緩沖對象的寬高颜矿。
下面是使用該函數(shù)的簡單代碼片段:
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 中創(chuàng)建幀緩沖區(qū)的代碼類似寄猩,并沒有太大差別,不同的是如下一行:
gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, FRAMEBUFFER_SIZE.x, FRAMEBUFFER_SIZE.y);
通過gl.renderbufferStorageMultisample方法指定了渲染緩沖對象的多重采樣骑疆,采樣數(shù)是4焦影。
多采樣紋理附件
多采樣紋理附件又是什么東西呢,好吧封断,其實在WebGL2中斯辰,沒有這個多采樣紋理附件,在OPENGL才有坡疼,為什么提到這個多采樣紋理附件彬呻,大部分時間,我們的離屏渲染都需要渲染到一個紋理對象上面柄瑰,才能進一步使用闸氮。
在沒有多采樣紋理附件,只有多采樣渲染緩沖對象的情況下教沾,要實現(xiàn)MSAA蒲跨,只能渲染到渲染緩沖對象上,但是渲染緩沖對象的內容不能直接傳遞給紋理對象授翻。
那么應該怎么做呢或悲? 需要使用另外一個重要的函數(shù):
gl.blitFramebuffer函數(shù)
通過gl.blitFramebuffer函數(shù),可以把多采樣渲染緩沖對象的內容傳遞給紋理對象堪唐。下面是該函數(shù)的簽名:
gl.blitFramebuffer(srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,
mask, filter);
該函數(shù)的作用就是巡语,把一個幀緩沖區(qū)(read framebuffer)上的指定區(qū)域像素轉移給另外一個幀緩沖區(qū)(draw framebuffer)上的指定區(qū)域。
其中參數(shù)srcX0, srcY0, srcX1, srcY1指定read framebuffer上的區(qū)域淮菠;
dstX0, dstY0, dstX1, dstY1 指定draw framebuffer上的區(qū)域男公; mask指定那個buffer的內容會被copy,可選值:
- gl.COLOR_BUFFER_BIT
- gl.DEPTH_BUFFER_BIT
- gl.STENCIL_BUFFER_BIT
filter 表示當兩個區(qū)域大小不同的時候合陵,插值的方式枢赔,可以是以下值: - 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 renderbuffers
gl.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上面的顏色關聯(lián)對象寇荧,然后調用gl.blitFramebuffer方法把renderableFramebuffer的顏色關聯(lián)對象上的數(shù)據復制到colorFramebuffer的顏色管理對象,colorFramebuffer的顏色關聯(lián)對象是一個紋理對象执隧,這樣就把數(shù)據從渲染緩沖對象復制到紋理對象上面了。
READ_FRAMEBUFFER和DRAW_FRAMEBUFFER
在webgl1中户侥,幀緩沖區(qū)的對象的目標只能是gl.FRAMEBUFFER,而在WebGL2中镀琉,增加兩種目標:
- gl.READ_FRAMEBUFFER
- gl.DRAW_FRAMEBUFFER
以上兩種目標分別表示FBO可以分別進行讀操作和寫操作;這在FBO復制到FBO的時候很有用蕊唐,就像前文中所敘述的屋摔,可以把READ_FRAMEBUFFER上的數(shù)據復制到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多年開發(fā)經驗,現(xiàn)任公司系統(tǒng)架構師副瀑、技術總監(jiān)弓熏、技術培訓師、職業(yè)規(guī)劃師糠睡。熟悉Java挽鞠、JavaScript、Python語言狈孔,熟悉數(shù)據庫信认。熟悉java、nodejs應用系統(tǒng)架構均抽,大數(shù)據高并發(fā)嫁赏、高可用、分布式架構油挥。在計算機圖形學潦蝇、WebGL、前端可視化方面有深入研究深寥。對程序員思維能力訓練和培訓护蝶、程序員職業(yè)規(guī)劃有濃厚興趣。