Particles / Instancing - OpenGL Tutorial
文章推薦指數: 80 %
Thanks to instancing, they will be shared by all particles. static const GLfloat ... Update the buffers that OpenGL uses for rendering.
Particles,lotsofthem!
Instancing
What’sthepoint?
Lifeanddeath
Creatingnewparticles
Deletingoldparticles
Themainsimulationloop
Sorting
Goingfurther
Animatedparticles
Handlingseveralparticlesystems
Smoothparticles
Improvingfillrate
Particlephysics
GPUSimulation
Particlesareverysimilarto3Dbillboards.Therearetwomajordifferences,though:
thereisusuallyaLOTofthem
theymove
theappearanddie.
theyaresemi-transparent
Bothofthesedifferencecomewithproblems.ThistutorialwillpresentONEwaytosolvethem;therearemanyotherpossibilities.
Particles,lotsofthem!
Thefirstideatodrawmanyparticleswouldbetousetheprevioustutorial’scode,andcallglDrawArraysonceforeachparticle.Thisisaverybadidea,becausethismeansthatallyourshinyGTX’512+multiprocessorswillallbededicatedtodrawONEquad(obviously,onlyonewillbeused,sothat’s99%efficiencyloss).Thenyouwilldrawthesecondbillboard,anditwillbethesame.
Clearly,weneedawaytodrawallparticlesatthesametime.
Therearemanywaystodothis;herearethreeofthem:
GenerateasingleVBOwithalltheparticlesinthem.Easy,effective,worksonallplatforms.
Usegeometryshaders.Notinthescopeofthistutorial,mostlybecause50%ofthecomputersdon’tsupportthis.
Useinstancing.NotavailableonALLcomputers,butavastmajorityofthem.
Inthistutorial,we’llusethe3rdoption,becauseitisanicebalancebetweenperformanceandavailability,andontopofthat,it’seasytoaddsupportforthefirstmethodoncethisoneworks.
Instancing
“Instancing”meansthatwehaveabasemesh(inourcase,asimplequadof2triangles),butmanyinstancesofthisquad.
Technically,it’sdoneviaseveralbuffers:
Someofthemdescribethebasemesh
Someofthemdescribetheparticularitiesofeachinstanceofthebasemesh.
Youhavemany,manyoptionsonwhattoputineachbuffer.Inoursimplecase,wehave:
Onebufferfortheverticesofthemesh.Noindexbuffer,soit’s6vec3,whichmake2triangles,whichmake1quad.
Onebufferfortheparticles’centers.
Onebufferfortheparticles’colors.
Theseareverystandardbuffers.Theyarecreatedthisway:
//TheVBOcontainingthe4verticesoftheparticles.
//Thankstoinstancing,theywillbesharedbyallparticles.
staticconstGLfloatg_vertex_buffer_data[]={
-0.5f,-0.5f,0.0f,
0.5f,-0.5f,0.0f,
-0.5f,0.5f,0.0f,
0.5f,0.5f,0.0f,
};
GLuintbillboard_vertex_buffer;
glGenBuffers(1,&billboard_vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER,billboard_vertex_buffer);
glBufferData(GL_ARRAY_BUFFER,sizeof(g_vertex_buffer_data),g_vertex_buffer_data,GL_STATIC_DRAW);
//TheVBOcontainingthepositionsandsizesoftheparticles
GLuintparticles_position_buffer;
glGenBuffers(1,&particles_position_buffer);
glBindBuffer(GL_ARRAY_BUFFER,particles_position_buffer);
//Initializewithempty(NULL)buffer:itwillbeupdatedlater,eachframe.
glBufferData(GL_ARRAY_BUFFER,MaxParticles*4*sizeof(GLfloat),NULL,GL_STREAM_DRAW);
//TheVBOcontainingthecolorsoftheparticles
GLuintparticles_color_buffer;
glGenBuffers(1,&particles_color_buffer);
glBindBuffer(GL_ARRAY_BUFFER,particles_color_buffer);
//Initializewithempty(NULL)buffer:itwillbeupdatedlater,eachframe.
glBufferData(GL_ARRAY_BUFFER,MaxParticles*4*sizeof(GLubyte),NULL,GL_STREAM_DRAW);
,whichisasusual.Theyareupdatedthisway:
//UpdatethebuffersthatOpenGLusesforrendering.
//TherearemuchmoresophisticatedmeanstostreamdatafromtheCPUtotheGPU,
//butthisisoutsidethescopeofthistutorial.
//http://www.opengl.org/wiki/Buffer_Object_Streaming
glBindBuffer(GL_ARRAY_BUFFER,particles_position_buffer);
glBufferData(GL_ARRAY_BUFFER,MaxParticles*4*sizeof(GLfloat),NULL,GL_STREAM_DRAW);//Bufferorphaning,acommonwaytoimprovestreamingperf.Seeabovelinkfordetails.
glBufferSubData(GL_ARRAY_BUFFER,0,ParticlesCount*sizeof(GLfloat)*4,g_particule_position_size_data);
glBindBuffer(GL_ARRAY_BUFFER,particles_color_buffer);
glBufferData(GL_ARRAY_BUFFER,MaxParticles*4*sizeof(GLubyte),NULL,GL_STREAM_DRAW);//Bufferorphaning,acommonwaytoimprovestreamingperf.Seeabovelinkfordetails.
glBufferSubData(GL_ARRAY_BUFFER,0,ParticlesCount*sizeof(GLubyte)*4,g_particule_color_data);
,whichisasusual.Beforerender,theyareboundthisway:
//1rstattributebuffer:vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,billboard_vertex_buffer);
glVertexAttribPointer(
0,//attribute.Noparticularreasonfor0,butmustmatchthelayoutintheshader.
3,//size
GL_FLOAT,//type
GL_FALSE,//normalized?
0,//stride
(void*)0//arraybufferoffset
);
//2ndattributebuffer:positionsofparticles'centers
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER,particles_position_buffer);
glVertexAttribPointer(
1,//attribute.Noparticularreasonfor1,butmustmatchthelayoutintheshader.
4,//size:x+y+z+size=>4
GL_FLOAT,//type
GL_FALSE,//normalized?
0,//stride
(void*)0//arraybufferoffset
);
//3rdattributebuffer:particles'colors
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER,particles_color_buffer);
glVertexAttribPointer(
2,//attribute.Noparticularreasonfor1,butmustmatchthelayoutintheshader.
4,//size:r+g+b+a=>4
GL_UNSIGNED_BYTE,//type
GL_TRUE,//normalized?***YES,thismeansthattheunsignedchar[4]willbeaccessiblewithavec4(floats)intheshader***
0,//stride
(void*)0//arraybufferoffset
);
,whichisasusual.Thedifferencecomeswhenrendering.InsteadofusingglDrawArrays(orglDrawElementsifyourbasemeshhasanindexbuffer),youuseglDrawArrraysInstanced/glDrawElementsInstanced,whichisequivalenttocallingglDrawArraysNtimes(Nisthelastparameter,inourcaseParticlesCount):
glDrawArraysInstanced(GL_TRIANGLE_STRIP,0,4,ParticlesCount);
Buesomethingismissinghere.Wedidn’ttellOpenGLwhichbufferwasforthebasemesh,andwhichwereforthedifferentinstances.ThisisdonewithglVertexAttribDivisor.Here’sthefullcommentedcode:
//ThesefunctionsarespecifictoglDrawArrays*Instanced*.
//Thefirstparameteristheattributebufferwe'retalkingabout.
//Thesecondparameteristhe"rateatwhichgenericvertexattributesadvancewhenrenderingmultipleinstances"
//http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribDivisor.xml
glVertexAttribDivisor(0,0);//particlesvertices:alwaysreusethesame4vertices->0
glVertexAttribDivisor(1,1);//positions:oneperquad(itscenter)->1
glVertexAttribDivisor(2,1);//color:oneperquad->1
//Drawtheparticules!
//Thisdrawsmanytimesasmalltriangle_strip(whichlookslikeaquad).
//Thisisequivalentto:
//for(iinParticlesCount):glDrawArrays(GL_TRIANGLE_STRIP,0,4),
//butfaster.
glDrawArraysInstanced(GL_TRIANGLE_STRIP,0,4,ParticlesCount);
Asyoucansee,instancingisveryversatile,becauseyoucanpassanyintegerastheAttribDivisor.Forinstance,withglVertexAttribDivisor(2,10),each10subsequentinstanceswillhavethesamecolor.
What’sthepoint?
Thepointisthatnow,weonlyhavetoupdateasmallbuffereachframe(thecenteroftheparticles)andnotahugemesh.Thisisax4bandwidthgain!
Lifeanddeath
Onthecontrarytomostotherobjectsinthescene,particlesdieandbornataveryhighrate.Weneedadecentlyfastwaytogetnewparticlesandtodiscardthem,somethingbetterthan“newParticle()”.
Creatingnewparticles
Forthis,wewillhaveabigparticlescontainer:
//CPUrepresentationofaparticle
structParticle{
glm::vec3pos,speed;
unsignedcharr,g,b,a;//Color
floatsize,angle,weight;
floatlife;//Remaininglifeoftheparticle.if<0:deadandunused.
};
constintMaxParticles=100000;
ParticleParticlesContainer[MaxParticles];
Now,weneedawaytocreatenewones.ThisfunctionsearcheslinearlyinParticlesContainer,whichshouldbeanhorribleidea,exceptthatitstartsatthelastknownplace,sothisfunctionusuallyreturnsimmediately:
intLastUsedParticle=0;
//FindsaParticleinParticlesContainerwhichisn'tusedyet.
//(i.e.life<0);
intFindUnusedParticle(){
for(inti=LastUsedParticle;i
延伸文章資訊
- 1Instancing - OpenGL ES SDK for Android - GitHub Pages
This sample presents the instanced drawing technique using OpenGL ES 3.0. Overview. Instancing_an...
- 2Instancing in OpenGL
Whenever you find yourself in a situation where you want to render many copies of a single object...
- 3实例化
如果我们能够将数据一次发送给GPU,就会更方便,然后告诉OpenGL使用一个绘制函数,将这些数据绘制为多个物体。这就是我们将要展开讨论的实例化(Instancing)。
- 4Instanced Rendering - OpenGL Wiki
Instanced Rendering. From OpenGL Wiki. Redirect page. Jump to navigation Jump to search. Redirect...
- 5How to do instancing the right way in OpenGL. - Stack Overflow
glDrawElementsInstanced use gl_InstanceID variable as if it were a static integer vertex attribut...