GPGPU is "General Purpose" GPU and means using the GPU for something other than drawing pixels. The basic realization to understanding GPGPU in WebGL is ...
English
Français
日本語
한국어
Polski
Portuguese
Русский
简体中文
TableofContents
WebGLFundamentals.org
Fix,Fork,Contribute
WebGLGPGPU
GPGPUis"GeneralPurpose"GPUandmeansusingtheGPUforsomething
otherthandrawingpixels.
ThebasicrealizationtounderstandingGPGPUinWebGListhatatexture
isnotanimage,it'sa2Darrayofvalues.Inthearticleontextures
wecoveredreadingfromatexture.Inthearticleonrenderingtoatexture
wecoveredwritingtoatexture.So,ifrealizingatextureisa2Darrayofvalues
wecansaythatwehavereallydescribedawaytoreadfromandwriteto2Darrays.
ThatistheessenceofGPGPUinWebGL.
InJavaScriptthereistheArray.prototype.mapfunctionwhichgivenanarraycallsafunctiononeachelement
functionmultBy2(v){
returnv*2;
}
constsrc=[1,2,3,4,5,6];
constdst=src.map(multBy2);
//dstisnow[2,4,6,8,10,12];
YoucanconsidermultBy2ashaderandmapsimilartocallinggl.drawArraysorgl.drawElements.
Somedifferences.
Shadersdon'tgenerateanewarray,youhavetoprovideone
Wecansimulatethatbymakingourownmapfunction
functionmultBy2(v){
returnv*2;
}
+functionmapSrcToDst(src,fn,dst){
+for(leti=0;i{
if(max===undefined){
max=min;
min=0;
}
returnMath.random()*(max-min)+min;
};
constpositions=newFloat32Array(
ids.map(_=>[rand(canvas.width),rand(canvas.height),0,0]).flat());
constvelocities=newFloat32Array(
ids.map(_=>[rand(-300,300),rand(-300,300),0,0]).flat());
functioncreateTexture(gl,data,width,height){
consttex=gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D,tex);
gl.texImage2D(
gl.TEXTURE_2D,
0,//miplevel
gl.RGBA,//internalformat
width,
height,
0,//border
gl.RGBA,//format
gl.FLOAT,//type
data,
);
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);
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);
returntex;
}
//createatextureforthevelocityand2texturesforthepositions.
constvelocityTex=createTexture(gl,velocities,particleTexWidth,particleTexHeight);
constpositionTex1=createTexture(gl,positions,particleTexWidth,particleTexHeight);
constpositionTex2=createTexture(gl,null,particleTexWidth,particleTexHeight);
Wealsoneedframebufferslikewecoveredinthearticleonrenderingtoatexture.We'llmake2.Onethatallowsustowriteto
onepositiontextureandanotherfortheotherpositiontexture.
functioncreateFramebuffer(gl,tex){
constfb=gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER,fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,tex,0);
returnfb;
}
//create2framebuffers.OnethatrenderstopositionTex1one
//andanotherthatrenderstopositionTex2
constpositionsFB1=createFramebuffer(gl,positionTex1);
constpositionsFB2=createFramebuffer(gl,positionTex2);
letoldPositionsInfo={
fb:positionsFB1,
tex:positionTex1,
};
letnewPositionsInfo={
fb:positionsFB2,
tex:positionTex2,
};
wealsoneedtosetupabufferofvertexidsforourvertexpullingparticle
drawingshader.
//setupanidbuffer
constparticleTexWidth=20;
constparticleTexHeight=10;
constnumParticles=particleTexWidth*particleTexHeight;
constids=newArray(numParticles).fill(0).map((_,i)=>i);
constidBuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,idBuffer);
gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array(ids),gl.STATIC_DRAW);
Andweneedtocompilebothsetsofshadersandlookupallthelocations
constupdatePositionProgram=webglUtils.createProgramFromSources(
gl,[updatePositionVS,updatePositionFS]);
constdrawParticlesProgram=webglUtils.createProgramFromSources(
gl,[drawParticlesVS,drawParticlesFS]);
constupdatePositionPrgLocs={
position:gl.getAttribLocation(updatePositionProgram,'position'),
positionTex:gl.getUniformLocation(updatePositionProgram,'positionTex'),
velocityTex:gl.getUniformLocation(updatePositionProgram,'velocityTex'),
texDimensions:gl.getUniformLocation(updatePositionProgram,'texDimensions'),
canvasDimensions:gl.getUniformLocation(updatePositionProgram,'canvasDimensions'),
deltaTime:gl.getUniformLocation(updatePositionProgram,'deltaTime'),
};
constdrawParticlesProgLocs={
id:gl.getAttribLocation(drawParticlesProgram,'id'),
positionTex:gl.getUniformLocation(drawParticlesProgram,'positionTex'),
texDimensions:gl.getUniformLocation(drawParticlesProgram,'texDimensions'),
matrix:gl.getUniformLocation(drawParticlesProgram,'matrix'),
};
Andthenatrendertime,firstwerunthepositionupdatingshadertogenerate
newpositions.
letthen=0;
functionrender(time){
//converttoseconds
time*=0.001;
//Subtracttheprevioustimefromthecurrenttime
constdeltaTime=time-then;
//Rememberthecurrenttimeforthenextframe.
then=time;
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
//rendertothenewpositions
gl.bindFramebuffer(gl.FRAMEBUFFER,newPositionsInfo.fb);
gl.viewport(0,0,particleTexWidth,particleTexHeight);
//setupourattributestotellWebGLhowtopull
//thedatafromthebufferabovetothepositionattribute
//thisbufferjustcontainsa-1to+1quadforrendering
//toeverypixel
gl.bindBuffer(gl.ARRAY_BUFFER,updatePositionBuffer);
gl.enableVertexAttribArray(updatePositionPrgLocs.position);
gl.vertexAttribPointer(
updatePositionPrgLocs.position,
2,//size(numcomponents)
gl.FLOAT,//typeofdatainbuffer
false,//normalize
0,//stride(0=auto)
0,//offset
);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D,oldPositionsInfo.tex);
gl.activeTexture(gl.TEXTURE0+1);
gl.bindTexture(gl.TEXTURE_2D,velocityTex);
gl.useProgram(updatePositionProgram);
gl.uniform1i(updatePositionPrgLocs.positionTex,0);//telltheshaderthepositiontextureisontextureunit0
gl.uniform1i(updatePositionPrgLocs.velocityTex,1);//telltheshaderthepositiontextureisontextureunit1
gl.uniform2f(updatePositionPrgLocs.texDimensions,particleTexWidth,particleTexHeight);
gl.uniform2f(updatePositionPrgLocs.canvasDimensions,gl.canvas.width,gl.canvas.height);
gl.uniform1f(updatePositionPrgLocs.deltaTime,deltaTime);
gl.drawArrays(gl.TRIANGLES,0,6);//draw2triangles(6vertices)
Thenweusethosenewpositionstodrawpointsfortheparticles
gl.bindFramebuffer(gl.FRAMEBUFFER,null);
gl.viewport(0,0,gl.canvas.width,gl.canvas.height);
//setupourattributestotellWebGLhowtopull
//thedatafromthebufferabovetotheidattribute
gl.bindBuffer(gl.ARRAY_BUFFER,idBuffer);
gl.enableVertexAttribArray(drawParticlesProgLocs.id);
gl.vertexAttribPointer(
drawParticlesProgLocs.id,
1,//size(numcomponents)
gl.FLOAT,//typeofdatainbuffer
false,//normalize
0,//stride(0=auto)
0,//offset
);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D,newPositionsInfo.tex);
gl.useProgram(drawParticlesProgram);
gl.uniform2f(drawParticlesProgLocs.texDimensions,particleTexWidth,particleTexWidth);
gl.uniform1i(drawParticlesProgLocs.positionTex,0);//telltheshaderthepositiontextureisontextureunit0
gl.uniformMatrix4fv(
drawParticlesProgLocs.matrix,
false,
m4.orthographic(0,gl.canvas.width,0,gl.canvas.height,-1,1));
gl.drawArrays(gl.POINTS,0,numParticles);
Finallyweswapthevariablestrackingtheoldandnewpositions
soournewpositionsthisframewillbetheoldpositionsnextframe.
//swapwhichtexturewewillreadfrom
//andwhichonewewillwriteto
{
consttemp=oldPositionsInfo;
oldPositionsInfo=newPositionsInfo;
newPositionsInfo=temp;
}
AndwiththewegetGPGPUbasedparticles.JavaScriptisdoingalmostno
workexceptcallinggl.drawArraystwice.Oncetoupdatethepositions,
andoncetodrawtheparticles
clickheretoopeninaseparatewindow
We'redrawing200particlesbyhavingpositionandvelocitytextures20x10pixelsbig.Whatifwewantedtodraw199particles?SinceWebGLonlyworkswithtextures
andtexturesare2Darrayswecan'tmakea2Darraythatis199pixels.Instead
thoughwecouldcompute200butonlydraw199.You'llneedtofindsimilar
solutionsforproblemsthatdon'tneatlyfitintoa2Darray.
NextExample:Findingtheclosestlinesegmenttoapoint
I'mnotsurethisisagoodexamplebutit'stheoneIwrote.Isayitmight
notbegoodbecauseIsuspecttherearebetteralgorithmsforfinding
theclosestlinetoapointthanbruteforce,checkingeverylinewiththepoint.Forexamplevariousspacepartitioningalgorithmsmightletyoueasilydiscard95%
ofthepointsandsobefaster.Still,thisexampleprobablydoesshow
sometechniquesofGPGPUatleast.
Theproblem:Wehave500pointsand1000linesegments.Foreachpoint
findwhichlinesegmentitisclosestto.Thebruteforcemethodis
foreachpoint
minDistanceSoFar=MAX_VALUE
foreachlinesegment
computedistancefrompointtolinesegment
ifdistanceisi);
constidBufferInfo=webglUtils.createBufferInfoFromArrays(gl,{
id:{
numComponents:1,
data:ids,
},
});
So,atrendertimewecomputetheresultslikewedidbeforebut
wedon'tlookuptheresultswithreadPixels.Insteadwejust
passthemasatexturetotheappropriateshaders.
Firstwedrawallthelinesingray
//drawallthelinesingray
gl.bindFramebuffer(gl.FRAMEBUFFER,null);
gl.viewport(0,0,gl.canvas.width,gl.canvas.height);
constmatrix=m4.orthographic(0,gl.canvas.width,0,gl.canvas.height,-1,1);
webglUtils.setBuffersAndAttributes(gl,drawLinesPrgInfo,idBufferInfo);
gl.useProgram(drawLinesPrgInfo.program);
webglUtils.setUniforms(drawLinesPrgInfo,{
linesTex,
linesTexDimensions,
matrix,
});
gl.drawArrays(gl.LINES,0,numLineSegments*2);
Thenwedrawalltheclosestlines
webglUtils.setBuffersAndAttributes(gl,drawClosestLinesPrgInfo,idBufferInfo);
gl.useProgram(drawClosestLinesPrgInfo.program);
webglUtils.setUniforms(drawClosestLinesPrgInfo,{
numPoints,
closestLinesTex,
closestLinesTexDimensions,
linesTex,
linesTexDimensions,
matrix,
});
//thereisoneclosestlineforeachpoint,2verticesperline
gl.drawArrays(gl.LINES,0,numPoints*2);
andfinallywedraweachpoint
//drawthepoints
webglUtils.setBuffersAndAttributes(gl,drawPointsPrgInfo,idBufferInfo);
gl.useProgram(drawPointsPrgInfo.program);
webglUtils.setUniforms(drawPointsPrgInfo,{
numPoints,
pointsTex,
pointsTexDimensions,
matrix,
});
gl.drawArrays(gl.POINTS,0,numPoints);
Beforewerunitletsdoonemorething.Let'saddmorepointsandlines
-constpoints=[
-100,100,0,0,
-200,100,0,0,
-];
-constlines=[
-25,50,0,0,
-25,150,0,0,
-90,50,0,0,
-90,150,0,0,
-125,50,0,0,
-125,150,0,0,
-185,50,0,0,
-185,150,0,0,
-225,50,0,0,
-225,150,0,0,
-];
+functioncreatePoints(numPoints){
+constpoints=[];
+for(leti=0;iMath.random()*max;
+
+constpoints=createPoints(8);
+constlines=createPoints(125*2);
constnumPoints=points.length/4;
constnumLineSegments=lines.length/4/2;
andifwerunthat
clickheretoopeninaseparatewindow
Youcanbumpupthenumberofpointsandlines
butatsomepointyouwon'tbeabletotellwhich
pointsgowithwhichlinesbutwithasmallernumber
youcanatleastvisuallyverifyit'sworking.
Justforfun,letscombinetheparticleexampleandthis
example.We'llusethetechniquesweusedtoupdate
thepositionsofparticlestoupdatethepointsand
linesegmentpositions.
TodothatwecopyintheupdatePositionFSfragmentshader
fromtheparticleexampleandcompileit.Forthevertexshader
wecanusethesameoneclosestLineVSisusingasit'sjust
copyinga_positiontogl_Position
constclosestLinePrgInfo=webglUtils.createProgramInfo(
gl,[closestLineVS,closestLineFS(numLineSegments)]);
constdrawLinesPrgInfo=webglUtils.createProgramInfo(
gl,[drawLinesVS,drawLinesFS]);
constdrawPointsPrgInfo=webglUtils.createProgramInfo(
gl,[drawPointsVS,drawClosestPointsLinesFS]);
constdrawClosestLinesPrgInfo=webglUtils.createProgramInfo(
gl,[drawClosestLinesVS,drawClosestPointsLinesFS]);
+constupdatePositionPrgInfo=webglUtils.createProgramInfo(
+gl,[closestLineVS,updatePositionFS]);
Weneedtogeneratevelocitiesforboththepointsandlines
-functioncreatePoints(numPoints){
+functioncreatePoints(numPoints,ranges){
constpoints=[];
for(leti=0;ir(...range)),0,0);//RGBA
}
returnpoints;
}
-constr=max=>Math.random()*max;
+constr=(min,max)=>min+Math.random()*(max-min);
-constpoints=createPoints(8);
-constlines=createPoints(125*2);
+constpoints=createPoints(8,[[0,gl.canvas.width],[0,gl.canvas.height]]);
+constlines=createPoints(125*2,[[0,gl.canvas.width],[0,gl.canvas.height]]);
constnumPoints=points.length/4;
constnumLineSegments=lines.length/4/2;
+constpointVelocities=createPoints(numPoints,[[-20,20],[-20,20]]);
+constlineVelocities=createPoints(numLineSegments*2,[[-20,20],[-20,20]]);
Weneedtomakecopiesofthepointsandlinestextures
sowehaveoldandnewversionsofeachsowecanreadfromtheold
andrendertothenew.
-const{tex:pointsTex,dimensions:pointsTexDimensions}=
-createDataTexture(gl,points,gl.FLOAT);
-const{tex:linesTex,dimensions:linesTexDimensions}=
-createDataTexture(gl,lines,gl.FLOAT);
+const{tex:pointsTex1,dimensions:pointsTexDimensions1}=
+createDataTexture(gl,points,gl.FLOAT);
+const{tex:linesTex1,dimensions:linesTexDimensions1}=
+createDataTexture(gl,lines,gl.FLOAT);
+const{tex:pointsTex2,dimensions:pointsTexDimensions2}=
+createDataTexture(gl,points,gl.FLOAT);
+const{tex:linesTex2,dimensions:linesTexDimensions2}=
+createDataTexture(gl,lines,gl.FLOAT);
andweneedtexturesforthevelocities
const{tex:pointVelocityTex,dimensions:pointVelocityTexDimensions}=
createDataTexture(gl,pointVelocities,gl.FLOAT);
const{tex:lineVelocityTex,dimensions:lineVelocityTexDimensions}=
createDataTexture(gl,lineVelocities,gl.FLOAT);
Weneedtomakeframebuffersforbothsetsofpointsandlines
constpointsFB1=createFramebuffer(gl,pointsTex1);
constpointsFB2=createFramebuffer(gl,pointsTex2);
constlinesFB1=createFramebuffer(gl,linesTex1);
constlinesFB2=createFramebuffer(gl,linesTex2);
Andweneedtosetupsomeobjecttotrackoldandnew
letoldPointsLines={
pointsFB:pointsFB1,
linesFB:linesFB1,
pointsTex:pointsTex1,
linesTex:linesTex1,
};
letnewPointsLines={
pointsFB:pointsFB2,
linesFB:linesFB2,
pointsTex:pointsTex2,
linesTex:linesTex2,
};
Thenweneedarenderloop
constpointsTexDimensions=pointsTexDimensions1;
constlinesTexDimensions=linesTexDimensions1;
letthen=0;
functionrender(time){
//converttoseconds
time*=0.001;
//Subtracttheprevioustimefromthecurrenttime
constdeltaTime=time-then;
//Rememberthecurrenttimeforthenextframe.
then=time;
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
Thefirstthingwedointherenderloopisrender
thenewpositionsfromtheoldpositionsandvelocities
//updatethepointpositions
gl.bindFramebuffer(gl.FRAMEBUFFER,newPointsLines.pointsFB);
gl.viewport(0,0,...pointsTexDimensions);
webglUtils.setBuffersAndAttributes(gl,updatePositionPrgInfo,quadBufferInfo);
gl.useProgram(updatePositionPrgInfo.program);
webglUtils.setUniforms(updatePositionPrgInfo,{
positionTex:oldPointsLines.pointsTex,
texDimensions:pointsTexDimensions,
velocityTex:pointVelocityTex,
canvasDimensions:[gl.canvas.width,gl.canvas.height],
deltaTime,
});
gl.drawArrays(gl.TRIANGLES,0,6);//drawtheclipspacequadsowegetoneresultforeachpixel
anddothesameforthelinepositions
//updatethelinepositions
gl.bindFramebuffer(gl.FRAMEBUFFER,newPointsLines.linesFB);
gl.viewport(0,0,...linesTexDimensions);
webglUtils.setBuffersAndAttributes(gl,updatePositionPrgInfo,quadBufferInfo);
gl.useProgram(updatePositionPrgInfo.program);
webglUtils.setUniforms(updatePositionPrgInfo,{
positionTex:oldPointsLines.linesTex,
texDimensions:linesTexDimensions,
velocityTex:lineVelocityTex,
canvasDimensions:[gl.canvas.width,gl.canvas.height],
deltaTime,
});
gl.drawArrays(gl.TRIANGLES,0,6);//drawtheclipspacequadsowegetoneresultforeachpixel
Withthatdonewecanpulloutwhichtexturestousetocomputeclosestlines
andtherestoftherenderingcodestaysthesame
+const{linesTex,pointsTex}=newPointsLines;
...renderingcodefrompreviousexample...
andfinallylikeourparticleexampleweswapoldandnew
//swapoldandnewfornextframe
{
consttemp=oldPointsLines;
oldPointsLines=newPointsLines;
newPointsLines=temp;
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
Andwiththatwecanseeitworkingdynamicallyandallthecomputation
ishappeningontheGPU
clickheretoopeninaseparatewindow
SomeCaveatsaboutGPGPU
GPGPUinWebGL1ismostlylimitedtousing2Darrays
asoutputthoughyoucanoutputtomorethanone2Darray
atthesametimeusingtheWEBGL_draw_buffersextension
ifitexists.
WebGL2addstheabilitytojustprocessa1Darrayofarbitrarysize.
WebGPU(AFAIK)letsyouhaverandomaccesswriting,ie(computeshaders).
GPUsdon'thavethesameprecisionasCPUs.
Checkyourresultsandmakesuretheyareacceptable.
ThereisoverheadtoGPGPU.
Inthefirsttwoexamplesabovewecomputedsome
datausingWebGLandthenreadtheresults.Settingupbuffers,textures
settingattributesanduniformstakestime.Enoughtimethatforanything
underacertainsizeitwouldbebettertojustdoitinJavaScript.
Theactualexamplesmultiplying6numbersoradding3pairsofnumbers
aremuchtoosmallforGPGPUtobeuseful.Wherethattradeoffis
isundefined.Experimentbutjustaguessthatifyou'renotdoingatleast
1000ormorethingskeepitinJavaScript
readPixelsisslow
readingtheresultsfromWebGLisslowsoit'simportanttoavoidit
asmuchaspossible.Asanexamplenethertheparticlesystemabovenor
thedynamicclosestlinesexampleever
readtheresultsbacktoJavaScript.Whereyoucan,keeptheresults
ontheGPUforaslongaspossible.Inotherwords,youcoulddosomething
like
computestuffonGPU
readresult
prepresultfornextstep
uploadpreppedresulttogpu
computestuffonGPU
readresult
prepresultfornextstep
uploadpreppedresulttogpu
computestuffonGPU
readresult
whereasviacreativesolutionsitwouldbemuchfasterifyoucould
computestuffonGPU
prepresultfornextstepusingGPU
computestuffonGPU
prepresultfornextstepusingGPU
computestuffonGPU
readresult
Ourdynamicclosestlinesexampledidthis.Theresultsneverleave
theGPU.
AsanotherexampleIoncewroteahistogramcomputingshader.Ithenread
theresultsbackintoJavaScript,figuredouttheminandmaxvalues
Thendrewtheimagebacktothecanvasusingthoseminandmaxvalues
asuniformstoauto-leveltheimage.
But,itturnedinsteadofreadingthehistogrambackintoJavaScript
Icouldinsteadrunashaderonthehistogramitselfthatgenerated
a2pixeltexturewiththeminandmaxvaluesinthetexture.
Icouldthenpassthat2pixeltextureintothe3rdshaderwhichit
couldreadfortheminandmaxvalues.Noneedtoreadthemoutofthe
GPUforsettinguniforms.
SimilarlytodisplaythehistogramitselfIfirstreadthehistogram
datafromtheGPUbutlaterIinsteadwroteashaderthatcould
visualizethehistogramdatadirectlyremovingtheneedtoreadit
backtoJavaScript.
BydoingthattheentireprocessstayedontheGPUandwaslikelymuch
faster.
GPUscandomanythingsinparallelbutmostcan'tmulti-taskthesameway
aCPUcan.GPUsusuallycan'tdo"preemptivemultitasking".
Thatmeansifyougivethemaverycomplexshaderthatsaytakes5minutesto
runthey'llpotentiallyfreezeyourentiremachinefor5minutes.
MostwellmadeOSesdealwiththisbyhavingtheCPUcheckhowlongit'sbeen
sincethelastcommandtheygavetotheGPU.Ifit'sbeentolong(5-6second)
andtheGPUhasnotrespondedthentheironlyoptionistoresettheGPU.
ThisisonereasonwhyWebGLcanlosethecontextandyougetan"Aw,rats!"
orsimilarmessage.
It'seasytogivetheGPUtoomuchtodobutingraphicsit'snotthat
commontotakeittothe5-6secondlevel.It'susuallymorelikethe0.1
secondlevelwhichisstillbadbutusuallyyouwantgraphicstorunfast
andsotheprogrammerwillhopefullyoptimizeorfindadifferenttechnique
tokeepthetheirappresponsive.
GPGPUontheotherhandyoumighttrulywanttogivetheGPUaheavytask
torun.Thereisnoeasysolutionhere.Amobilephonehasamuchlesspowerful
GPUthanatopendPC.Otherthandoingyourowntimingthereisnowayto
knowforsurehowmuchworkyoucangiveaGPUbeforeits"tooslow"
Idon'thaveasolutiontooffer.Onlyawarningthatdependingonwhatyou're
tryingtodoyoumayrunintothatissue.
Mobiledevicesdon'tgenerallysupportrenderingtofloatingpointtextures
Therearenoeasysolutionshere.Onesolutionisyoucantryto
encodefloatingpointvaluesintoRGBA/UNSIGNED_BYTEvalues.Intheshader
whenyoureadavaluefromthetextureyouneedtoconvertbackto
floatingpointandwhenyououtputacoloryouneedtore-encodeit
backintoRGBA/UNSIGNED_BYTE.Seethis
But,forexample,ifweweretousethisintheparticleorclosestline
examplesabovetheywouldrequiresignificantchanges.Thecodeabove
isabletopulloutaposition(3values,x,y,z)withjustonelookup
butnowwe'dneedtodo3lookups.Thecodeaboveisalsoabletowrite
anew3valuepositiongl_FragColor=newPositionbutnowwe'donlybe
abletowrite1value.We'deitherhavetotrytouseWEBGL_draw_buffers
toletuswriteout3valuesto3differenttextures(yetmorework)
orwe'dhavetoadjusttheshadertorun3times,onceforeachofX,Y,andZ
Oneothersolutionissomemobiledevicessupportrenderingtohalffloats.
Theproblemwithhalffloatsaretheyhaveverylittleprecisionsowhile
theyareusefulforsomeproblemstheyaren'tnearlyasgenerallyuseful
asnormal32bitfloatingpointvalues.
IhopetheseexampleshelpedyouunderstandthekeyideaofGPGPUinWebGL
isjustthefactthatWebGLreadsfromandwritesto2Dtextureswhichare
really2DarraysofDATA,notjustpixelsforimages.
Theyworksimilartomapfunctionsinthatthefunctionbeingcalled
foreachvaluedoesn'tgettodecidewhereitsvaluewillbestored.
Ratherthatisdecidedfromtheoutsidethefunction.InWebGL'scase
that'sdecidedbyhowyousetupwhatyou'redrawing.Onceyoucallgl.drawXXX
theshaderwillbecalledforeachneededvaluebeingasked"whatvalueshould
Imakethis?"
Andthat'sreallyit.
Theexamplesabovemostlyused2Dtexturesas1Darraysbutofcourse
youcanusethemas2Darrays(forexamplemultiplying2largematrices
formachinelearning),orsimilarlytohowwedidmathtotreat2Darrays
as1Darrayswecouldalsowritemathtotreat2Darraysas3Darrays
andusethatforthingslikefluidsimulations.
SincewemadesomeparticlesviaGPGPUthereisthiswonderfulvideowhichinitssecondhalf
usescomputeshaderstodoa"slime"simulation.
UsingthetechniquesabovehereitistranslatedintoWebGL.
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