Taking A Screenshot of the Canvas - WebGL Fundamentals

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

A common question is how to make a WebGL animation be the background of a webpage. There are 2 obvious ways. Set the canvas CSS position to fixed as in. #canvas ... English Français 日本語 한국어 Polski Portuguese Русский 简体中文 TableofContents WebGLFundamentals.org Fix,Fork,Contribute WebGLTips Thisarticleisacollectionofissuesyoumightruninto usingWebGLthatseemedtoosmalltohavetheirownarticle. TakingAScreenshotoftheCanvas Inthebrowserthereareeffectively2functionsthatwilltakeascreenshot. Theoldone canvas.toDataURL andthenewbetterone canvas.toBlob Soyou'dthinkitwouldbeeasytotakeascreenshotbyjustaddingsomecodelike +Save... constelem=document.querySelector('#screenshot'); elem.addEventListener('click',()=>{ canvas.toBlob((blob)=>{ saveBlob(blob,`screencapture-${canvas.width}x${canvas.height}.png`); }); }); constsaveBlob=(function(){ consta=document.createElement('a'); document.body.appendChild(a); a.style.display='none'; returnfunctionsaveData(blob,fileName){ consturl=window.URL.createObjectURL(blob); a.href=url; a.download=fileName; a.click(); }; }()); Here'stheexamplefromthearticleonanimation withthecodeaboveaddedandsomeCSStoplacethebutton clickheretoopeninaseparatewindow WhenItrieditIgotthisscreenshot Yes,it'sjustablankimage. It'spossibleitworkedforyoudependingonyourbrowser/OSbutingeneral it'snotlikelytowork. Theissueisthatforperformanceandcompatibilityreasons,bydefaultthebrowser willclearaWebGLcanvas'sdrawingbufferafteryou'vedrawntoit. Thereare3solutions. callyourrenderingcodejustbeforecapturing ThecodeweusedasadrawScenefunction.Itwouldbebesttomakethat codenotchangeanystateandthenwecouldcallittorenderforcapturing. elem.addEventListener('click',()=>{ +drawScene(); canvas.toBlob((blob)=>{ saveBlob(blob,`screencapture-${canvas.width}x${canvas.height}.png`); }); }); callthecapturingcodeinourrenderloop Inthiscasewe'djustsetaflagthatwewanttocaptureandthen intherenderingloopactuallydothecapture letneedCapture=false; elem.addEventListener('click',()=>{ needCapture=true; }); andtheninourrenderloop,whichiscurrentimplementedindrawScene, somewhereaftereverythinghasbeendrawn functiondrawScene(time){ ... +if(needCapture){ +needCapture=false; +canvas.toBlob((blob)=>{ +saveBlob(blob,`screencapture-${canvas.width}x${canvas.height}.png`); +}); +} ... } SetpreserveDrawingBuffer:truewhencreatingtheWebGLcontext constgl=someCanvas.getContext('webgl',{preserveDrawingBuffer:true}); Thismakeswebglnotclearthecanvasaftercompositingthecanvaswiththe restofthepagebutpreventscertainpossibleoptimizations. I'dpick#1above.ForthisparticularexamplefirstI'dseparatethepartsof thecodethatupdatestatefromthepartsthatdraw. varthen=0; -requestAnimationFrame(drawScene); +requestAnimationFrame(renderLoop); +functionrenderLoop(now){ +//Converttoseconds +now*=0.001; +//Subtracttheprevioustimefromthecurrenttime +vardeltaTime=now-then; +//Rememberthecurrenttimeforthenextframe. +then=now; + +//Everyframeincreasetherotationalittle. +rotation[1]+=rotationSpeed*deltaTime; + +drawScene(); + +//CallrenderLoopagainnextframe +requestAnimationFrame(renderLoop); +} //Drawthescene. +functiondrawScene(){ -functiondrawScene(now){ -//Converttoseconds -now*=0.001; -//Subtracttheprevioustimefromthecurrenttime -vardeltaTime=now-then; -//Rememberthecurrenttimeforthenextframe. -then=now; - -//Everyframeincreasetherotationalittle. -rotation[1]+=rotationSpeed*deltaTime; webglUtils.resizeCanvasToDisplaySize(gl.canvas); ... -//CalldrawSceneagainnextframe -requestAnimationFrame(drawScene); } andnowwecanjustcalldrawScenebeforecapturing elem.addEventListener('click',()=>{ +drawScene(); canvas.toBlob((blob)=>{ saveBlob(blob,`screencapture-${canvas.width}x${canvas.height}.png`); }); }); Andnowitshouldwork. clickheretoopeninaseparatewindow Ifyouactuallycheckthecapturedimageyou'llseethebackgroundistransparent. Seethisarticleforafewdetails. Preventingthecanvasbeingcleared Let'ssayyouwantedtolettheuserpaintwithananimated object.YouneedtopassinpreserveDrawingBuffer:truewhen youcreatethewebglcontext.Thispreventsthebrowserfrom clearingthecanvas. Takingthelastexamplefromthearticleonanimation varcanvas=document.querySelector("#canvas"); -vargl=canvas.getContext("webgl"); +vargl=canvas.getContext("webgl",{preserveDrawingBuffer:true}); andchangethecalltogl.clearsoitonlyclearsthedepthbuffer -//ClearthecanvasANDthedepthbuffer. -gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT); +//Clearthedepthbuffer. +gl.clear(gl.DEPTH_BUFFER_BIT); clickheretoopeninaseparatewindow Notethatifyouwereseriousaboutmakingadrawingprogramthiswouldnotbea solutionasthebrowserwillstillclearthecanvasanytimewechangeits resolution.We'rechangingisresolutionbasedonitsdisplaysize.Itsdisplay sizechangeswhenthewindowchangessize.Thatcanincludewhentheuserdownloads afile,eveninanothertab,andthebrowseraddsastatusbar.Italsoincludeswhen theuserturnstheirphoneandthebrowserswitchesfromportraittolandscape. Ifyoureallywantedtomakeadrawingprogramyou'd rendertoatexture. GettingKeyboardInput Ifyou'remakingafullpage/fullscreenwebglappthenyoucandowhatever youwantbutoftenyou'dlikesomecanvastojustbeapartofalargerpageand you'dlikeitsoiftheuserclicksonthecanvasthecanvasgetskeyboardinput. Acanvascan'tnormallygetkeyboardinputthough.Tofixthatsetthe tabindex ofthecanvasto0ormore.Eg. Thisendsupcausinganewissuethough.Anythingthathasatabindexset willgethighlightedwhenithasthefocus.TofixthatsetitsfocusCSSoutline tonone canvas:focus{ outline:none; } Todemonstratehereare3canvases andsomecssjustforthelastcanvas #c3:focus{ outline:none; } Let'sattachthesameeventlistenerstoallofthem document.querySelectorAll('canvas').forEach((canvas)=>{ constctx=canvas.getContext('2d'); functiondraw(str){ ctx.clearRect(0,0,canvas.width,canvas.height); ctx.textAlign='center'; ctx.textBaseline='middle'; ctx.fillText(str,canvas.width/2,canvas.height/2); } draw(canvas.id); canvas.addEventListener('focus',()=>{ draw('hasfocuspressakey'); }); canvas.addEventListener('blur',()=>{ draw('lostfocus'); }); canvas.addEventListener('keydown',(e)=>{ draw(`keyCode:${e.keyCode}`); }); }); Noticeyoucan'tgetthefirstcanvastoacceptkeyboardinput. Thesecondcanvasyoucanbutitgetshighlighted.The3rd canvashasbothsolutionsapplied. clickheretoopeninaseparatewindow MakingyourbackgroundaWebGLanimation AcommonquestionishowtomakeaWebGLanimationbethebackgroundof awebpage. Thereare2obviousways. SetthecanvasCSSpositiontofixedasin #canvas{ position:fixed; left:0; top:0; z-index:-1; ... } andsetz-indexto-1. AsmalldisadvantagetothissolutionisyourJavaScriptmustintegratewiththepage andifyouhaveacomplexpagethenyouneedtomakesurenoneoftheJavaScriptinyour webglcodeconflictswiththeJavaScriptdoingotherthingsinthepage. Useaniframe Thisisthesolutionusedonthefrontpageofthissite. Inyourwebpagejustinsertaniframe,forexample

Yourcontentgoeshere.
Thenstyletheiframetofillthewindowandbeinthebackground whichisbasicallythesamecodeasweusedaboveforthecanvas exceptwealsoneedtosetbordertononesinceiframeshave aborderbydefault. #background{ position:fixed; width:100vw; height:100vh; left:0; top:0; z-index:-1; border:none; pointer-events:none; } clickheretoopeninaseparatewindow English Français 日本語 한국어 Polski Portuguese Русский 简体中文 Fundamentals Fundamentals HowItWorks ShadersandGLSL WebGLStateDiagram ImageProcessing ImageProcessing ImageProcessingContinued 2Dtranslation,rotation,scale,matrixmath 2DTranslation 2DRotation 2DScale 2DMatrices 3D Orthographic3D 3DPerspective 3DCameras Lighting DirectionalLighting PointLighting SpotLighting StructureandOrganization LessCode,MoreFun DrawingMultipleThings SceneGraphs Geometry Geometry-Lathe Loading.objfiles Loading.objw.mtlfiles Textures Textures DataTextures Using2orMoreTextures CrossOriginImages PerspectiveCorrectTextureMapping PlanarandPerspectiveProjectionMapping RenderingToATexture RendertoTexture Shadows Shadows Techniques 2D 2D-DrawImage 2D-MatrixStack Sprites 3D Cubemaps Environmentmaps Skyboxes Skinning Fog Picking(clickingonstuff) Text Text-HTML Text-Canvas2D Text-UsingaTexture Text-UsingaGlyphTexture Textures RampTextures(ToonShading) GPGPU GPGPU Tips SmallestPrograms DrawingWithoutData Shadertoy PullingVertices Optimization IndexedVertices(gl.drawElements) InstancedDrawing Misc SetupAndInstallation Boilerplate ResizingtheCanvas Animation Points,Lines,andTriangles MultipleViews,MultipleCanvases VisualizingtheCamera WebGLandAlpha 2Dvs3Dlibraries Anti-Patterns WebGLMatricesvsMathMatrices PrecisionIssues Takingascreenshot PreventtheCanvasBeingCleared GetKeyboardInputFromaCanvas UseWebGLasBackgroundinHTML CrossPlatformIssues QuestionsandAnswers Reference Attributes TextureUnits Framebuffers readPixels References HelperAPIDocs TWGL,AtinyWebGLhelperlibrary github Questions?Askonstackoverflow. Issue/Bug?Createanissueongithub. Use
codegoeshere
forcodeblocks commentspoweredbyDisqus



請為這篇文章評分?