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.
Usecodegoeshere
forcodeblocks
commentspoweredbyDisqus