WebGL中图片多级处理(FrameBuffer) - 纸异兽- 博客园
文章推薦指數: 80 %
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
延伸文章資訊
- 1How to work with framebuffers in webgl? - Stack Overflow
A fragment shader outputs to either the canvas or the attachments in a framebuffer. To be more te...
- 2JavaScript webgl framebuffer object | Develop Paper
By default, the final drawing result of webgl is stored in the color buffer, and the frame buffer...
- 3WebGL中图片多级处理(FrameBuffer) - 纸异兽- 博客园
FBO(Frame Buffer Object)是被推荐用于将数据渲染到纹理对象的扩展。 FrameBuffer就像是一个webgl显示容器一样,平时我们使用gl.drawArrays或者gl.
- 4WebGL基础学习篇(Lesson 8) - GitHub
这个方法更易于实现而且也更利于大家了解选取的工作原理。 最基础的思想就是将每个物体都渲染成不同的颜色,并且将场景渲染到offscreen framebuffer中。接着,当用户 ...
- 5WebGLRenderingContext.bindFramebuffer() - Web APIs | MDN
Binding a frame buffer. var canvas = document.getElementById('canvas'); var gl = canvas.getContex...