More particles
Blitz3D Forums/Blitz3D Programming/More particles
| ||
Here's another system. It's pretty straightforward, single-surface, very fast: Const EMITTER_BUFFERSIZE=68 Const EMITTER_ENTITY=0 Const EMITTER_VELOCITYX=4 Const EMITTER_VELOCITYY=8 Const EMITTER_VELOCITYZ=12 Const EMITTER_DVELOCITY=16 Const EMITTER_SIZE=20 Const EMITTER_DSIZE=24 Const EMITTER_INTENSITY=28 Const EMITTER_LIFE=32 Const EMITTER_PARTICLEBUFFER=36 Const EMITTER_SPREADX=40 Const EMITTER_SPREADY=44 Const EMITTER_SPREADZ=48 Const EMITTER_COLOR=52 Const EMITTER_ACCELERATIONX=56 Const EMITTER_ACCELERATIONY=60 Const EMITTER_ACCELERATIONZ=64 Global EMITTER_BUFFER=CreateBank() Function CountEmitters() Return BankSize(emitter_BUFFER)/4 End Function Function GetEmitter(n) Return PeekInt(emitter_BUFFER,(n-1)*4) End Function Function UpdateEmitters(speed#=1) For n=1 To countemitters() updateemitter getemitter(n),speed# Next End Function Function FindEmitter(entity) For n=1 To countemitters() buffer=getemitter(n) If entity=PeekInt(buffer,EMITTER_ENTITY) Return buffer Next End Function Function EmitterSize(entity,size#,dsize#=-1) buffer=FindEmitter(entity) PokeFloat buffer,EMITTER_SIZE,size If dsize<>-1 PokeFloat buffer,EMITTER_DSIZE,dsize End Function Function EmitterVelocity(entity,vx#,vy#,vz#,ax#=43.63,ay#=43.63,az#=43.63,dv#=-1) buffer=FindEmitter(entity) PokeFloat buffer,EMITTER_VELOCITYX,vx PokeFloat buffer,EMITTER_VELOCITYY,vy PokeFloat buffer,EMITTER_VELOCITYZ,vz If ax<>43.63 PokeFloat buffer,EMITTER_ACCELERATIONX,ax If ay<>43.63 PokeFloat buffer,EMITTER_ACCELERATIONY,ay If az<>43.63 PokeFloat buffer,EMITTER_ACCELERATIONZ,az If dv<>-1.0 PokeFloat buffer,EMITTER_DVELOCITY,dv End Function Function EmitterSpread(entity,x#,y#,z#) buffer=FindEmitter(entity) PokeFloat buffer,EMITTER_SPREADX,x PokeFloat buffer,EMITTER_SPREADY,y PokeFloat buffer,EMITTER_SPREADZ,z End Function Function CreateEmitter(intensity=10,life=100) buffer=CreateBank(EMITTER_BUFFERSIZE) bsize=BankSize(EMITTER_BUFFER) ResizeBank EMITTER_BUFFER,bsize+4 PokeInt EMITTER_BUFFER,bsize,buffer entity=CreateMesh() EntityBlend entity,3 EntityFX entity,1+2+8+32 PokeInt buffer,EMITTER_ENTITY,entity PokeFloat buffer,EMITTER_VELOCITYX,0 PokeFloat buffer,EMITTER_VELOCITYY,1 PokeFloat buffer,EMITTER_VELOCITYZ,0 PokeFloat buffer,EMITTER_ACCELERATIONX,0 PokeFloat buffer,EMITTER_ACCELERATIONY,0 PokeFloat buffer,EMITTER_ACCELERATIONZ,0 PokeFloat buffer,EMITTER_DVELOCITY,0.01 PokeFloat buffer,EMITTER_SIZE,10 PokeFloat buffer,EMITTER_DSIZE,0.1 PokeFloat buffer,EMITTER_LIFE,life PokeFloat buffer,EMITTER_SPREADX,5 PokeFloat buffer,EMITTER_SPREADY,5 PokeFloat buffer,EMITTER_SPREADZ,5 PokeInt buffer,EMITTER_COLOR,RGB(255,255,255) PokeInt buffer,EMITTER_INTENSITY,intensity surf=CreateSurface(entity) For n=0 To intensity-1 angle#=Rnd(360) p=CreatePivot() RotateEntity p,0,0,angle TFormVector 1,1,0,p,0 AddVertex surf,0,0,0,(TFormedX()+1.0)/2.0,(TFormedY()+1.0)/2.0 TFormVector 1,-1,0,p,0 AddVertex surf,0,0,0,(TFormedX()+1.0)/2.0,(TFormedY()+1.0)/2.0 TFormVector -1,-1,0,p,0 AddVertex surf,0,0,0,(TFormedX()+1.0)/2.0,(TFormedY()+1.0)/2.0 TFormVector -1,1,0,p,0 AddVertex surf,0,0,0,(TFormedX()+1.0)/2.0,(TFormedY()+1.0)/2.0 FreeEntity p AddTriangle surf,n*4,n*4+2,n*4+1 AddTriangle surf,n*4+2,n*4+0,n*4+3 Next pbuffer=CreateBank(4*intensity) PokeInt buffer,EMITTER_PARTICLEBUFFER,pbuffer offset#=Rnd(0,1) For n=0 To intensity-1 bank=CreateBank(36) PokeInt pbuffer,n*4,bank PokeFloat bank,28,(offset+Float(n))/Float(intensity)+offset PokeFloat bank,32,Rnd(360) Next Return entity End Function Function UpdateEmitter(buffer,speed#=1) entity=PeekInt(buffer,EMITTER_ENTITY) pbuffer=PeekInt(buffer,EMITTER_PARTICLEBUFFER) life#=PeekFloat(buffer,EMITTER_LIFE) size#=PeekFloat(buffer,EMITTER_SIZE) dsize#=PeekFloat(buffer,EMITTER_DSIZE) velx#=PeekFloat(buffer,EMITTER_VELOCITYX) vely#=PeekFloat(buffer,EMITTER_VELOCITYY) velz#=PeekFloat(buffer,EMITTER_VELOCITYZ) ax#=PeekFloat(buffer,EMITTER_ACCELERATIONX) ay#=PeekFloat(buffer,EMITTER_ACCELERATIONY) az#=PeekFloat(buffer,EMITTER_ACCELERATIONZ) dv#=PeekFloat(buffer,EMITTER_DVELOCITY) surf=GetSurface(entity,1) spreadx#=PeekFloat(buffer,EMITTER_SPREADX) spready#=PeekFloat(buffer,EMITTER_SPREADY) spreadz#=PeekFloat(buffer,EMITTER_SPREADZ) hue=PeekInt(buffer,EMITTER_COLOR) r=Red(hue) g=Green(hue) b=Blue(hue) ;Calculate particle orientation TFormVector 1,1,0,cam,entity x0#=TFormedX() y0#=TFormedY() z0#=TFormedZ() TFormVector -1,1,0,cam,entity x1#=TFormedX() y1#=TFormedY() z1#=TFormedZ() TFormVector -1,-1,0,cam,entity x2#=TFormedX() y2#=TFormedY() z2#=TFormedZ() TFormVector 1,-1,0,cam,entity x3#=TFormedX() y3#=TFormedY() z3#=TFormedZ() surf=GetSurface(entity,1) ;Update particles For n=0 To BankSize(pbuffer)/4-1 ;Get info bank=PeekInt(pbuffer,n*4) x#=PeekFloat(bank,0) y#=PeekFloat(bank,4) z#=PeekFloat(bank,8) vx#=PeekFloat(bank,12) vy#=PeekFloat(bank,16) vz#=PeekFloat(bank,20) scale#=PeekFloat(bank,24) alpha#=PeekFloat(bank,28) angle#=PeekFloat(bank,32) ;Process info alpha=alpha-1.0/life*speed scale=scale+dsize*speed vx=vx+Rnd(-dv,dv)*speed+ax vy=vy+Rnd(-dv,dv)*speed+ay vz=vz+Rnd(-dv,dv)*speed+az x=x+vx y=y+vy z=z+vz If alpha<0 alpha=1 x=Rnd(-spreadx,spreadx) y=Rnd(-spready,spready) z=Rnd(-spreadz,spreadz) vx=velx vy=vely vz=velz scale=size EndIf ;Store info PokeFloat bank,0,x PokeFloat bank,4,y PokeFloat bank,8,z PokeFloat bank,12,vx PokeFloat bank,16,vy PokeFloat bank,20,vz PokeFloat bank,24,scale PokeFloat bank,28,alpha ;Update mesh VertexCoords surf,n*4,x+x0*scale,y+y0*scale,z+z0*scale VertexCoords surf,n*4+1,x+x1*scale,y+y1*scale,z+z1*scale VertexCoords surf,n*4+2,x+x2*scale,y+y2*scale,z+z2*scale VertexCoords surf,n*4+3,x+x3*scale,y+y3*scale,z+z3*scale VertexColor surf,n*4,r,g,b,alpha VertexColor surf,n*4+1,r,g,b,alpha VertexColor surf,n*4+2,r,g,b,alpha VertexColor surf,n*4+3,r,g,b,alpha Next End Function |
| ||
Halo, do you think that using banks and additional 2 peek/poke commands for each value ( in main loop ) is faster than using types for particles ? |
| ||
It doesn't matter what you use tbh, so don't worry. The speed difference is tiny. |
| ||
It's a different option though - I like options. |
| ||
Err... I'm a perfectionist :) Even "1 FPS more" is "big deal" for me :) |
| ||
Halo, do you think that using banks and additional 2 peek/poke commands for each value ( in main loop ) is faster than using types for particles ? I'm gonna bet it is - blitz should convert it directly to an add, possibly a comparisen(at least in debug mode), and finally a direct memory write. With the type system it probably has to parse through the blitz variable system, which might be a bit slower. You should do some tests. |
| ||
various particle systems I've done use banks. |
| ||
Types are crap. Banks are the only dynamic data system that can be stored in a single four-byte integer, and accessed by other applications. I don't know, I just got tired of "For particle.particle=each particle". |
| ||
I agree, banks are great, but in this case using types to iterate through particles will be much faster. Blitz's peek/poke commands are not too fast, as one could expected. |
| ||
What I would be concerned with is the amount of memory being allocated and deallocated each frame, not the speed at which the types are being accessed. The speed at which they're accessed is surely insignificant considering how few particles one can have in the world. But as I found with my shadow system, allocating and deallocating hundreds of polygons in a type each frame was a no-no. So you should do some speed tests and calculate how much time you think is going to be spent in that part of the code for an average number of particles being created and deleted each frame. But it seems to me that the number of particles created and deleted each frame, even with an effect using hundreds of particles, is generally going to be fairly low. Let's say you had 200 snow particles falling gently down the screen. Only a few each frame would be deleted, and only a few would be created. Fire and smoke on the other hand has faster moving particles, but still only a few should be created and deleted each frame. Still, it's something to consider. With a type based system one could clearly not simulate every single particle of snow in a level at once if one is creatign and deleting types. However, if one were to create a pool of types, and re-use the allocated memory when possible... That would significantly cut down on the wasted reallocation. Of course, one should not try to do snow in that way. That was just an example. |
| ||
Thanks for the particle system Halo! I will try it out soon... |
| ||
I agree, banks are great, but in this case using types to iterate through particles will be much faster. Blitz's peek/poke commands are not too fast, as one could expected. Type Typ Field Flot# End Type Const n=100000*4 For a=1 To 100000 t.typ=New typ Next bank=CreateBank(n) For qwert=1 To 100 m=MilliSecs() For a=0 To n-4 Step 4 PokeFloat bank,a,Float(a/100.0) Next m2=m2+(MilliSecs()-m) Next Print Float(m2/100.0)+" millisecs for bank write" a=Rand(1,100) For qwert=1 To 100 m=MilliSecs() For t.typ = Each typ t\flot#=Float(a/100.0) Next m2=m2+(MilliSecs()-m) Next Print Float(m2/100.0)+" millisecs for type write" For qwert=1 To 100 m=MilliSecs() For a=0 To n-4 Step 4 moo#=PeekFloat#(bank,a) Next m2=m2+(MilliSecs()-m) Next Print "" Print Float(m2/100.0)+" millisecs for bank read" a=Rand(1,100) For qwert=1 To 100 m=MilliSecs() For t.typ = Each typ moo#=t\flot# Next m2=m2+(MilliSecs()-m) Next Print Float(m2/100.0)+" millisecs for type read" According to this comparisent that is incorrect. |
| ||
What I would be concerned with is the amount of memory being allocated and deallocated each frame. This doesn't allocate any new memory. The particles are kept in a cycle, and their number is constant. |
| ||
SSwift, your idea that creation/deletion of types is slow is based on your impropper use of them, those polygons in your culling system contain tons of blitzarrays, adding blitzarrays to a type makes them mortaly slow to delete, (approx 1000-5000 times slower then a regular type, I'm NOT kidding about this) try deleting a 1000 of your polygon types and a 1000 types without blitz arrays, without debug on and time them both. You'll be shocked! Just gave away one of the reasons why Storms Shadows are prolly a bit faster then yours, but whatever I'm in a generous mood today. ;) |
| ||
Or maybe perhaps storm's is based on OpenGL and has access to lovely things like stencil buffers and nvidia specific shadow extensions etc ;) I think the best is defined by what you're doing. My gl engine for example, for each mesh, there's a linked/tri version for the benefits of object based coding(I can quickly and easily construct new meshes) there's then an optimization layer, that compiles the mesh into a vertex array compatible format.. now that is a bank. A bank is better suited for this. as for this lib, my god halo, learn how to format your code ffs. ;) |
| ||
Hehe, no otacon, I'm still talking about the non GL storm engine. The one based off blitz3d. Oh yes and I agree on halo's code... :P (halo, is your tab button broken? ;) |
| ||
"Just gave away one of the reasons why Storms Shadows are prolly a bit faster then yours, but whatever I'm in a generous mood today. ;)" 1. I optimized all those type creations/deletions out of my system weeks ago before the new version which used them ever made it's way into any of the hands of those who use it. They were only ever in when I first added the clipping code, and it was too slow that way so I had top optimize it before release. 2. What's this Storm's Shadows you're talking about? 3. While my own tests did in fact show that deleting a type with an array in it was slower than deleting a regular type, I seem to recall my test showing that both were anything but lightning fast. But I won't deny that the difference may be great enough that you need not worry about it much if you avoid the use of arrays. |
| ||
1. I optimized all those type creations/deletions out of my system weeks ago before the new version which used them ever made it's way into any of the hands of those who use it. They were only ever in when I first added the clipping code, and it was too slow that way so I had top optimize it before release. Good good, tho I wouldn't have used arrays in the polygon type in the first place, take a test, you'll see putting banks into types or even adding a manualy linked list to it is infact faster when being deleted then a type with blitzArrays, it's rediculous how slow they are... (the creation time is not slow however, just the removal) 2. What's this Storm's Shadows you're talking about? Storm Engine, the shadows are just a tiny bit of it, it's a full development solution for blitz that myself and shattered are currently working on. It offers more functionality then all the seperate blitz products for sale currently offer together and in a much more flexible package. 3. While my own tests did in fact show that deleting a type with an array in it was slower than deleting a regular type, I seem to recall my test showing that both were anything but lightning fast. But I won't deny that the difference may be great enough that you need not worry about it much if you avoid the use of arrays. Run this, it should demonstrate my point, overhere it takes 1 millisec to free the 10000 normal types and 2480 milliseconds to free the ones with blitzArrays give it a go on your comp! :) Type tenVariables Field a,b,c,d,e,f,g,h,i,j End Type Type blitzArray Field dummy[9] End Type Const testAmmount = 10000 Delay 500 time = MilliSecs() For i = 1 To testAmmount V.tenVariables = New tenVariables Next Print "Creation of tenVariables took: " + (MilliSecs() - time) Delay 500 time = MilliSecs() For j = 1 To testAmmount B.blitzArray = New blitzArray Next Print "Creation of blitzArray took: " + (MilliSecs() - time) Delay 500 time = MilliSecs() For V.tenVariables = Each tenVariables Delete V Next Print "Deleting of tenVariables took: " + (MilliSecs() - time) Delay 500 time = MilliSecs() For B.blitzArray = Each blitzArray Delete B Next Print "Deleting of blitzArray took: " + (MilliSecs() - time) WaitKey() |
| ||
Yeah blitz arrays are horribly slow. Did a test on a fmc level in our engine back when I used types for everything all the time, and it took around 30 seconds to free around 30,000 types. |
| ||
Hm, interesting... It takes 2 milliseconds to allocate the tenvars and 7 to allocate the blitz arrays, but just 2 ms again to deallocate the tenvars, but a whopping 5883 milliseconds to deallocate the blitzarrays. Why in the world is is so slow to DEALLOCATE memory? I could understand if it took longer to allocate it... Doing so might mean that 0's have to be written to all addresses. But deallocating it? And why would an array be slower than a variable? Memory is memory. Technically, with either one, one would assume Blitz calculates the total size of the type, taking into account the size of each field, and then does a single memory alloction or deallocation for all. So even if Blitz is doing some kind of memory management to defragment memory when freeing the type, because both operations should be IDENTICAL when allocating the memory, they should both taker exactly the same amount of time. I don't get it. I mean even if Blitz is doing some funny set up internally for the array... still... Why would it affect deallocation? And why would it increase the time so much? This doesn't make any sense. I'm gonna have to assume Mark messed up on this one. Hopefully he'll explain it to us. Inquiring minds want to know! Well at least I know now that allocating the types isn't gonna slow stuff down. Just deallocating them. |
| ||
Oh, and I want to know how you've supposedly made this shadow system faster than mine. Prove it! Compile that FPS demo I released with your shadow system. :-) Even if you do though, there's one litlte problem. You can;t directly compare the systems. Your lights might have a different falloff. Or if your system were slower, it might be caused by corretly rendering the shadows rather than using the trick I did which prevents them from getting larger in the distance. (and thus covering a lot more polygons and looking all blocky) Then again, perhaps you precalculate visibility information for a level. But does that come at the cost that the user can't then modify the level? And of course there's the question of price. What are you gonna charge? |
| ||
There seems to be a problem with PokeInt buffer,EMITTER_COLOR,RGB(255,255,255) The function RGB is not found. |
| ||
Function RGB(r,g,b) Return (r Shr 16)+(g Shr 8)+b End Function I just punched this into the browser. Migt be wrong though. I don't use shr much. |
| ||
Isn't it Shl ? |
| ||
According to this comparisent that is incorrect BotBuilder, I said "in this case" - and your example is far from halo's code ! Here is more accurate example, try it ! bank=CreateBank(4100) Type p ; particle Field x# Field y# Field z# Field vx# Field vy# Field vz# Field scale# Field alpha# Field angle# End Type k1#=MilliSecs() For i=1 To 1000 For n=1 To 1000 mybank=PeekInt(bank,n*4) x#=PeekFloat(bank,0) y#=PeekFloat(bank,4) z#=PeekFloat(bank,8) vx#=PeekFloat(bank,12) vy#=PeekFloat(bank,16) vz#=PeekFloat(bank,20) scale#=PeekFloat(bank,24) alpha#=PeekFloat(bank,28) angle#=PeekFloat(bank,32) x=x+1 y=y+1 z=z+1 vx=vx+1 vy=vy+1 vz=vz+1 scale=scale+1 alpha=alpha+1 angle=angle+1 PokeFloat bank,0,x PokeFloat bank,4,y PokeFloat bank,8,z PokeFloat bank,12,vx PokeFloat bank,16,vy PokeFloat bank,20,vz PokeFloat bank,24,scale PokeFloat bank,28,alpha Next Next k#=MilliSecs()-k1 Text 100,100,"using bank + peek +poke commands ="+k# k1#=MilliSecs() For a=1 To 1000 p.p=New P Next For i=1 To 1000 For p.p=Each p p\x=p\x+1 p\y=p\y+1 p\z=p\z+1 p\vx=p\vx+1 p\vy=p\vy+1 p\vz=p\vz+1 p\scale=p\scale+1 p\alpha=p\alpha+1 p\angle=p\angle+1 Next Next k#=MilliSecs()-k1 Text 100,120,"using types="+k# WaitKey() End |
| ||
Function RGB(r,g,b) Return (r Shr 16)+(g Shr 8)+b End Function I just punched this into the browser. Migt be wrong though. I don't use shr much. Don't think that will work. Try, function rgb(r,g,b) return b or (g shl 8) or (r shl 16) end function |
| ||
Oh, and I want to know how you've supposedly made this shadow system faster than mine. Prove it! Compile that FPS demo I released with your shadow system. :-) Even if you do though, there's one litlte problem. You can;t directly compare the systems. Your lights might have a different falloff. Or if your system were slower, it might be caused by corretly rendering the shadows rather than using the trick I did which prevents them from getting larger in the distance. (and thus covering a lot more polygons and looking all blocky) From what I've seen in your shadow system demo and read overhere I'm thinking our shadow systems aren't very different from eachother in the way they work, logic dictates that if we both coded it properly, their speeeds won't differ much... Ofcourse we don't need to compete with your shadow system directly, the shadows are just icing on the cake. :) Then again, perhaps you precalculate visibility information for a level. But does that come at the cost that the user can't then modify the level? Flexibility is our main objective, so all of our culling/visibility systems are either dynamic or optional. And of course there's the question of price. What are you gonna charge? That's a question we're leaving unanswered for the moment, we'll see how people respond to the techdemos, it's likely to be more expensive then your average blitz product. (which will be fairly obvious when you see it's feature set) |
| ||
That's a question we're leaving unanswered for the moment, we'll see how people respond to the techdemos, it's likely to be more expensive then your average blitz product. (which will be fairly obvious when you see it's feature set) *whispers* we'd better pretend to hate it. |
| ||
I have doubts about that. |
| ||
I plan to sell my lib for 5 quid cheaper than yours. Fully expect a full on price war to commence, eventually resulting in us selling our libs for 50p each. Everyone's a winner! ;) |
| ||
Not likely otacon, our lib is in a completely different league, yours is more of an extended rendering pipeline with some extra features like collision support, while ours is a complete and generic game engine, which just happens to use the blitz functionality as it's rendering base, you see, we could just as easily make the Storm Engine run on your OpenGL renderer or any other renderer we make ourselves, which might just be what happens when blitzMax is released. We'll simply port our remaining code to a C++ dll and plug in our own renderer... :) Essentialy creating a game engine accessible and usable from any language, not just blitz! :) |
| ||
You want a war? I'll give you a war. ;) (Sorry, just any excuse to quote scarface...) Your right though, sounds like we're going to two very differant markets, mine is just a 2d/3d engine with lots of fx. |
| ||
Hello halo, Quote: "Banks are the only dynamic data system that can be stored in a single four-byte integer, and accessed by other applications." The "accessed by other applications" .. can you explain that for me. As in 'how to do?' Have not run across a port on the matter. Thank you, |
| ||
Make that "post" .. |