WebGL中图片多级处理(FrameBuffer) - 纸异兽- 博客园

文章推薦指數: 80 %
投票人數:10人

FBO(Frame Buffer Object)是被推荐用于将数据渲染到纹理对象的扩展。

FrameBuffer就像是一个webgl显示容器一样,平时我们使用gl.drawArrays或者gl. 首页 新闻 博问 专区 闪存 班级 我的博客 我的园子 账号设置 简洁模式... 退出登录 注册 登录 纸异兽 https://zhiyishou.com WebGL中图片多级处理(FrameBuffer) 在webgl中对图片进行多级处理,也就是framebuffer的使用和操作 在webgl的使用过程中,我们通常会想对texture进行多级处理并对其贴在表面显示 如对较精准的边缘检测,要先后使用灰度shader、模糊shader、边缘shader来进行处理,而每次的处理对象则是上一次处理后的texture,这就要对处理后的结果进行覆盖保存。

这是我在做Polyer使用到的:http://zhiyishou.github.io/Polyer 在众多webgl库中,直接有选项rederToTarget来实现将shader处理后的texture渲染并覆盖原texture,其是怎么完成这个步骤的呢? 这就要引出本文的主角——FrameBuffer   FrameBuffer是什么   FBO(FrameBufferObject)是被推荐用于将数据渲染到纹理对象的扩展。

FrameBuffer就像是一个webgl显示容器一样,平时我们使用gl.drawArrays或者gl.drawElements都是将对象绘制在了默认的窗口中,而当我们指定一个FrameBuffer为当前窗口时,则用这两个方法去绘制,则会将对象绘制于指定的FrameBuffer中。

  FrameBuffer的使用   internalformat,intx,inty,sizeiwidth,sizeiheight,intborder);target:TEXTURE_2D,TEXTURE_ FBO的创建: //创建一个Framebuffer varfb=gl.createFramebuffer(); //将fb绑定为目前的窗口 gl.bindFramebuffer(gl.FRAMEBUFFER,fb);   这样,我们则创建了一个新的可以绘制的buffer了,且其并不会被显示出来 但是,这样就可以了吗?我们想到的是将经过shader渲染后的texture渲染出来并交给下一个shader,这时则引入方法framebufferTexture2D Referencefrom《OpenGLESReferencePagesaboutFramebufferTexture2D》:   Torenderdirectlyintoatextureimage,aspecifiedimagefromatextureobjectcanbeattachedasoneofthelogicalbuffersofthecurrentlyboundframebufferobjectbycallingthecommand 为了直接渲染至纹理图片中,一个纹理对象中指定的图片可用下面的方法绑定在当前使用的FBO上一个逻辑缓存中 voidFramebufferTexture2D(enumtarget,enumattachment,enumtextarget,uinttexture,intlevel);   target: • FRAMEBUFFER attachment: •IfattachmentisCOLOR_ATTACHMENT0,thenimagemusthaveacolorrenderableinternalformat.(色彩) •IfattachmentisDEPTH_ATTACHMENT,thenimagemusthaveadepthrenderableinternalformat.(深度) •IfattachmentisSTENCIL_ATTACHMENT,thenimagemusthaveastencilrenderableinternalformat.(模板) textarget: • TEXTURE_2D  (two-dimensionaltexture) • TEXTURE_CUBE_MAP_POSITIVE_X (three-dimensional+xtexture) • TEXTURE_CUBE_MAP_POSITIVE_Y  (three-dimensional+ytexture) • TEXTURE_CUBE_MAP_POSITIVE_Z  (three-dimensional+ztexture) • TEXTURE_CUBE_MAP_NEGATIVE_X  (three-dimensional-xtexture) • TEXTURE_CUBE_MAP_NEGATIVE_Y  (three-dimensional-ytexture) • TEXTURE_CUBE_MAP_NEGATIVE_Z  (three-dimensional-ztexture) texture:   textureobject level:   specifiesthemipmaplevelofthetextureimagetobeattachedtotheframebufferandmustbe0.   我们使用这个方法来进行绑定(本文只介绍色彩的绑定,尝试和模板类似,但是有不同之处,不在此讨论) //创建一个纹理对象 vartexture=gl.createTexture(); //使用如下的设置来创建texture,这样对texture的设置可以使我们对任何尺寸的图片进行处理 gl.bindTexture(gl.TEXTURE_2D,texture); gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST); varfb=gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER,fb); //使用该方法将texture的颜色值与FBO进行绑定 gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,texture,0);   绑定后,当我们执行gl.drawArrays或gl.drawElements方法时,则会将直接渲染至目前绑定的FBO上,而FBO又与texture的色彩进行了绑定,所以绘制时则也将色彩渲染至了texture中 这样,我们则可用两个FBO来进行队列加工: OriginalImage-->texture1 texture1-->gray-->texture2 texture2-->blur-->texture1 texture1-->edge-->texture2   下面是具体实现过程 varFBOs=[], textures=[]; for(vari=0;i<2;i++){ vartexture=gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D,texture); gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST); varfb=gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER,fb); gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,texture,0); //storecorrespondingtextureandfb textures.push(texture); FBOs.push(fb); } gl.bindTexture(gl.TEXTURE_2D,originalImageTexture); for(vari=0;i<3;i++){ switch(i){case0: //setgrayshadertocurrentshaderprogram //handleargumentstovsshaderandfsshader break; case1: //setblurshadertocurrentshaderprogram //handleargumentstovsshaderandfsshader break; case2: //setedgeshadertocurrentshaderprogram //handleargumentstovsshaderandfsshader break; } gl.bindFramebuffer(gl.FRAMEBUFFER,FBOs[i%2]); //settheviewportfitstheimagessize gl.viewport(0,0,imgWidth,imgHeight); gl.drawArrays(....);//orgl.drawElements(....); //settherenderedtexturetocurrenttexturefornextframbufferusing gl.bindTexture(gl.TEXTURE_2D,texture[i%2]); }   完整的过程为: originalTexture-->grayprogram-->setFBO1-->draw-->FBO1-->settexture1 texture1-->blurprogram-->setFBO2-->draw-->FBO2-->settexture2 texture2-->edgeprogram-->setFBO1-->draw-->FBO1-->settexture1   该过程中,FBO1与texture1是进行色彩渲染绑定的,所以setFBO1后进行渲染则会直接渲染至texture1 当我们完成了整个绘制的时候,要正常显示处理后的图片,则要从FBO中跳出来: //setFBOtonulltousedefaultframebuffer gl.bindFramebuffer(gl.FRAMEBUFFER,null);   FrameBuffer的其它用处   gl.readPixels 从FrameBuffer中读取像素颜色数据 Referencefrom《webgl_2.0_reference_card》/《OpenGLESReferencePagesaboutreadPixels》:   Pixelsinthecurrentframebuffercanbereadbackintoan ArrayBufferViewobject. voidreadPixels(intx,inty,longwidth,longheight,enumformat,enumtype,Objectpixels)   x,y • Specifythewindowcoordinatesofthefirstpixelthatisreadfromtheframebuffer.Thislocationisthelowerleftcornerofarectangularblockofpixels. width,height   • Specifythedimensionsofthepixelrectangle. width and height ofonecorrespondtoasinglepixel. format • Specifiestheformatofthepixeldata.Thefollowingsymbolicvaluesareaccepted RGBA inWebGL type • Specifiesthedatatypeofthepixeldata.MustbeUNSIGNED_BYTEinWebGL pixels   • Returnsthepixeldata.     在使用过程中,我们要先创建pixels对象来储存数据 //usingArrayBufferViewtostorepixelsdataonly,Unit8Arrayisthebestbecauseeachcolordataisabyte varpixels=newUint8Array(ImageWidth*ImageHeight*4); gl.readPixels(0,0,ImageWidth,ImageHeight,gl.RGBA,gl.UNSIGNED_BYTE,pixels);   这样,我们则可以得到整个FBO中的色彩数据   gl.CopyTexImage2D gl.CopyTexSubImage2D 这两个函数都是用来从FBO中将数据复制至当前绑定的texture中的 CopyTexImage2D方法: Referencefrom 《OpenGLESReferencePagesaboutCopyTexImage2D》:   copypixelsintoa2Dtextureimage voidCopyTexImage2D(enumtarget,intlevel,enuminternalformat,intx,inty,sizeiwidth,sizeiheight,intborder);   target: • TEXTURE_2D • TEXTURE_CUBE_MAP_POSITIVE_{X,Y,Z}, • TEXTURE_CUBE_MAP_NEGATIVE_{X,Y,Z} internalformat: • ALPHA • LUMINANCE • LUMINANCE_ALPHA • RGB • RGBA x,y Specifythewindowcoordinatesofthelowerleftcorneroftherectangularregionofpixelstobecopied. width Specifiesthewidthofthetextureimage.Mustbe0or 2 n + 2 ⁡ border forsomeinteger n. height Specifiestheheightofthetextureimage.Mustbe0or 2 m + 2 ⁡ border forsomeinteger m. border Specifiesthewidthoftheborder.Mustbeeither0or1.  CopyTexSubImage2D方法: Referencefrom 《OpenGLESReferencePagesaboutCopyTexSubImage2D》:   copyatwo-dimensionaltexturesubimage voidCopyTexSubImage2D(enumtarget,intlevel,intxoffset,intyoffset,intx,inty,sizeiwidth,sizeiheight);   target: • TEXTURE_2D • TEXTURE_CUBE_MAP_POSITIVE_{X,Y,Z}, • TEXTURE_CUBE_MAP_NEGATIVE_{X,Y,Z} level: Specifiesthelevel-of-detailnumber.Level0isthebaseimagelevel.Level n isthe nthmipmapreductionimage. xoffset: Specifiesatexeloffsetinthexdirectionwithinthetexturearray. yoffset: Specifiesatexeloffsetintheydirectionwithinthetexturearray. x,y: Specifythewindowcoordinatesofthelowerleftcorneroftherectangularregionofpixelstobecopied. width: Specifiesthewidthofthetexturesubimage. height: Specifiestheheightofthetexturesubimage. 这两个方法的不同之处相信大家已经看得出来了   CopyTexSubImage2D相对CopyTexImage2D增加了offset来改变复制区域 其最终复制区域为:[x,xoffset+width-1]与[y,yoffset+height-1]。

  而CopyTexImage2D则是比CopyTexSubImage2D多了internelformat参数来控制对像素数据复制的种类。

  结语: 有了对texture灵活的操作,则我们才能做出更有趣的东西出来,而framebuffer在里面也是相当重要的一个角色。

  附: WebGL-1.0参考卡片:https://files.cnblogs.com/files/zhiyishou/webgl-reference-card-1_0.pdf OpenGL-ES-2.0参考卡片:https://files.cnblogs.com/files/zhiyishou/OpenGL-ES-2_0-Reference-card.pdf OpenGL-ES-2.0参考手册:https://www.khronos.org/opengles/sdk/docs/man/   Theend. posted@ 2015-06-2702:05  纸异兽  阅读(7619)  评论(1)  编辑  收藏  举报 刷新评论刷新页面返回顶部 Copyright©2022纸异兽 Poweredby.NET6onKubernetes



請為這篇文章評分?