Nodragem Posted November 23, 2018 Share Posted November 23, 2018 Hello, I am playing around with the Solid Particle System (SPS) and the performance looks great! However I would like to show a different letter on the front face of each of my cubes, such as illustrated here: However, it seems that the property uvs (SPS.particles[p].uvs) does not allow me to do that. It is expecting a Vector4, while I was expecting to give an array such as the one given for Mesh.setVerticesData(BABYLON.VertexBuffer.UVKind, array). Is it in theory possible to change the VerticesData of each particle as if they were meshes? Quote Link to comment Share on other sites More sharing options...
Sebavan Posted November 23, 2018 Share Posted November 23, 2018 Adding @jerome our SPS mastermind Quote Link to comment Share on other sites More sharing options...
Nodragem Posted November 23, 2018 Author Share Posted November 23, 2018 If that can help, this is how I tried to deal with the UVs right now: https://playground.babylonjs.com/ts.html#9GFDZN#2 I must be doing something wrong, cause that does not even show a letter anywhere on my cubes ? Quote Link to comment Share on other sites More sharing options...
jerome Posted November 23, 2018 Share Posted November 23, 2018 https://playground.babylonjs.com/ts.html#9GFDZN#3 I just set some faceUVs on the model box before so only one face has UVs(0, 0, 1, 1) then each particle can be given a part of the texture in the same way. You may have some error in your row, col computations. In my example, I just give (0, 0, 1, 1) to each particle here's another example with some fixed, but computed, values with your initial texture so you can understand how to set the particle UVs : https://playground.babylonjs.com/ts.html#9GFDZN#4 Sebavan and JohnK 2 Quote Link to comment Share on other sites More sharing options...
JohnK Posted November 23, 2018 Share Posted November 23, 2018 Here is a version that gets close. Its in Javascript rather than typescript but might help you spot any issue with your PG. Doesn't deal with non-letters and letters are applied to all sides. Also I made the cuboids immovable but this can be removed. https://www.babylonjs-playground.com/#UIIK1W And here is one using an second SPS of labels in front of the cuboid https://www.babylonjs-playground.com/#UIIK1W#1 Sebavan, ssaket and jerome 3 Quote Link to comment Share on other sites More sharing options...
JohnK Posted November 23, 2018 Share Posted November 23, 2018 Having read how Jerome did it I updated to this one https://www.babylonjs-playground.com/#UIIK1W#2 which also does random letters only. Note face 1 faces forward. jerome 1 Quote Link to comment Share on other sites More sharing options...
Nodragem Posted November 23, 2018 Author Share Posted November 23, 2018 hey hey, this is working! Thank you very much to both of you! I needed the trick that Jerome gave to project only on 1 face; then I also realised that my function getEventAtIndex(i) was not returning a number ? Here I modified Jerome's PG: https://playground.babylonjs.com/ts.html#9GFDZN#6 Ha! I see that you also did it meantime @JohnK I was too slow to answer! So now, I have an other question. Would it be possible (and efficient) to add an update function to each particles, like this one: Class RuneLetter{ player:Player; particule:BABYLON.SolidParticle; update(){ if(this.player && BABYLON.Vector3.Distance(this.player.position, this.particle.position) < 1 && this.particle.isVisible && !this.wasPickedUp){ this.onPickedUp(this.data); } if(this.isRotating){ this.mesh.rotate(BABYLON.Vector3.Up(), Math.PI/2000 * this.scene.getEngine().getDeltaTime()) } } } I need to check if there is an optimised way to detect collision with a particle and send a signal to the class RuneLetter. Quote Link to comment Share on other sites More sharing options...
jerome Posted November 23, 2018 Share Posted November 23, 2018 great, you found the easiest way by inversing the texture in the model just what I was about to suggest to you The SPS can handle particle intersection directly : https://doc.babylonjs.com/how_to/solid_particle_system#particle-intersections unless you just want pickability : https://doc.babylonjs.com/how_to/solid_particle_system#pickable-particles not sure to understand what you want to achieve Quote Link to comment Share on other sites More sharing options...
Nodragem Posted November 23, 2018 Author Share Posted November 23, 2018 Yeah ? so I will try to clarify: Imagine that you have the player character (for instance Mario) and you have collectables (like the coins in Mario). I want to use SPS to manage the animation of my coins (i.e. they just rotate constantly), while detecting if Mario collided with a coin. Hence, I think for now I want to use something like that: var SPS = new SolidParticleSystem("CoinManager", scene, {particleIntersection: true, boundingSphereOnly: true}); SPS.particle[p].intersectsMesh(Mario); I could also use this for the rotation animation: // animation var updateParticle = function(particle) { particle.rotation.y += 0.015; }; SPS.updateParticle = updateParticle; scene.registerBeforeRender(function() { SPS.setParticles(); }); And if I did not want to use the intersectMesh() function, I could check for the distance between mario and the collectables in updateParticle: // animation var updateParticle = function(particle) { particle.rotation.y += 0.015; if(BABYLON.Vector3.distance(Mario.position, particle.position) < 1){ doSomething() } }; SPS.updateParticle = updateParticle; scene.registerBeforeRender(function() { SPS.setParticles(); }); I am going to try that last one... Quote Link to comment Share on other sites More sharing options...
jerome Posted November 23, 2018 Share Posted November 23, 2018 yep, that's the right way to go The BoundingSphere intersection test actually also does a distance computation (just a little more accurate than the position/position one), it should be quite fast then too. If your particle are quite immobile in the space, you could create some space partitioning and store where the particle are located, so you could check the intersection only against the particles in the same space section than the player character. Or use a quadtree (don't know you to use the BJS provided one) Imagine something like this : partX is an array, some equal sections of the X world axis, say, from 0 to 99 units per element. So partX[0] depicts all the x coordinates between 0 and 99. And so on, partX[1] is from 100 to 199, etc. partX[0] = [idP1, idp25, idP56, idP67]; // means that particle id1 has its position x in the range 0..99, idem for id25, etc then do the same with partX[n] and the same with partY[], then partZ[] now, each frame, you know mario.position.x, y and z. If you divide x, y and z by 100 and get the Floor() of this, you know the particles in the same world section than Mario, right ? indexX = Math.floor(mario.position.x / 100); indexY = Math.floor(mario.position.y / 100); indexZ = Math.floor(mario.position.z / 100); => particles near Mario : those thtat are in partX[indexX] and partY[indexY] and partZ[indexZ] , this is really a very fast search. You can mark them directly when found : sps.particles[id].toCheck = true; You can then just test the distance between Mario and the particle only for the ones (if any) fullfilling the former condition, not for all the particles. just reset finaly each particle .toCheck to false in updateParticle() Of course, this space partitioning is worth it if you have a big number of particles and if they don't move in the space. Quote Link to comment Share on other sites More sharing options...
Nodragem Posted November 24, 2018 Author Share Posted November 24, 2018 Sounds like a very good optimisation! If I still have performance issue after using the SPS, this is definitely my next step to go, thank you! Quote Link to comment Share on other sites More sharing options...
jerome Posted November 25, 2018 Share Posted November 25, 2018 from JohnK's PG, 750 animated letters in one draw call and one texture : https://www.babylonjs-playground.com/#UIIK1W#3 Quote Link to comment Share on other sites More sharing options...
Nodragem Posted November 25, 2018 Author Share Posted November 25, 2018 I tried to add some optimization by freezing some properties: https://www.babylonjs-playground.com/#UIIK1W#6 Here what I added: SPS.computeParticleRotation = true; // prevents from computing particle.rotation SPS.computeParticleTexture = false; // prevents from computing particle.uvs SPS.computeParticleColor = false; // prevents from computing particle.color SPS.computeParticleVertex = false; // prevents from calling the custom updateParticleVertex() function //SPS.mesh.freezeNormals(); The freezeNormals() makes the back side of the letter runes black. Any other suggestions of optimisation? Quote Link to comment Share on other sites More sharing options...
jerome Posted November 25, 2018 Share Posted November 25, 2018 Yep, when the particles rotate (even just once), the normals are internally rotated, so they can't be frozen in this case. You set the right optimizers in your case. Are you encountering some performance issues with less than 1000 boxes ? weird ... If yes, what can be done then would be to act on your logic part : - for instance, set only the particles needing to be updated in the current frame with setParticles(start, end) - if you manage more particles than the ones that are actually visible in the screen, then reduce the particle pool and recycle them. If recycling is too complex to implement, then set the not visible ones to invisible (invisible particles aren't processed to make the system faster, only their function updateParticles() is called ... just in case it would reset them to visible) - if not necessary, don't call at all setParticle() each frame etc this chaotic example runs at 60 fps on my laptop : https://www.babylonjs-playground.com/#UIIK1W#7 Quote Link to comment Share on other sites More sharing options...
Nodragem Posted November 25, 2018 Author Share Posted November 25, 2018 no I have no issues; I am just making more optimisation than necessary cause I target mobiles and tablets by the way, when my player collects a coin, the coin should be killed. I did not find a way to dispose of a particle, so for now I do: p.isVisible = false; However, I think that the invisible particles should not be updated by setParticles(), so I tried: p.isVisible = false; p.alive = false; However, it seems that p.alive = false is cancelling the effect of p.isVisible. Is that normal? Quote Link to comment Share on other sites More sharing options...
jerome Posted November 25, 2018 Share Posted November 25, 2018 alive false means that the particle is frozen in its current state (visible or not) and no longer computed until reset to true. It can used to define particles within a pool that won't evolve for a while and that don't need to be computed then. isVisible false means the particle is set in a first pass (first call to setParticles() when just set to invisible) in the same location than the camera, is scaled to zero (so no more in the frustum, not mathematically intersectable within anything else although its logical settings can be set and are saved (position, rotation, scaling, uvs, etc), then is no longer computed in the next passes (meaning next calls to setParticles() ) to improve the perfs. Therefore isVisible = false has more effect than alive = false. isVisible = false is the right way to go to fake a particle disposing : no garbage collector activity, no un-necessary computation, etc. If you want to get a bit more speed, just exit updateParticles(), that is called anyway, immediatly for invisible particles : SPS.updateParticle = function(p) { if (!p.isVisible && someCondition ) { return; } // your active particle logic then here ... }; I added "someCondition" more because you need to keep a way to reset the particle to visible at some moment [EDIT] you could of course reset the particle to visible also outside the function updateParticle() : // somewhere in the code, nothing to do with SPS management var p = sps.particles[thatOne]; if (SomeOtherCondition) { p.isVisible = true; } Quote Link to comment Share on other sites More sharing options...
Nodragem Posted November 25, 2018 Author Share Posted November 25, 2018 Thank you very much for your explanation, that is indeed very useful to know! I am using isVisible = false now. Is it possible to prevent particles to be updated/visible based on whether they are behind a wall? My players are in a maze, so in fact I don't need to update what's behind walls. Note that, it could still be useful to be able to definitely destroy a particle as they could have no need to be visible again. Also, it could be useful to have a data property on each particle, or to have observables to make it easier to link the particles to other objects in the game. For instance, here my particles represent letter runes that the player can collect. Hence, I need to know which letter my player have collected. For now, I organised my code so that I can use the particle's idx property to retrieve the letter that the particle represents. But alternatively, I could have store the letter in a data property. Or alternatively, I could have observed the collision of each particle with an observer storing the letter. I mean, I am just giving ideas I think SPS is definitely a great tool to manage collectables in game level! I gonna use it all the time now. Quote Link to comment Share on other sites More sharing options...
jerome Posted November 26, 2018 Share Posted November 26, 2018 The SPS is designed to be agnostic about everything else : it doesn't know how the user wants to emit or not the particles, how they must move (physics or not), what they must depict or act for. This is a design choice in order to make it as versatile as possible. This choice, although it forces the user to make his own behavior implementation, has shown it was a good option until now to achieve this versatility. So, if you want to make particles behind walls invisible, you will have to implement this as the SPS doesn't know anything about its environment. "Behind walls" implies a point a view, it is to say a camera position. If the camera is fixed, the walls are fixed, maybe it's easy to know if a particle is visible or not only by knowing its position in the space and without having to compute anything. In this case, it's probably worth it to set them as invisible when behind walls. Else, if you have to check if a particle is in the camera frustum and if it's occulted or not by a wall, it will be probably far too much computation to do compared to the SPS computation dedicated to the hidden particles that wouldn't be set invisible. It's just a matter a choice depending on your very special case. The need for storing extra properties for particles is obvious (what letter it represents in your case). As you discovered it, it can be achieved by two different approaches : - as you did, you store this extra property values in some structure besides the SPS, say an array storing objects (logicalParticles ?) of your own and indexed, by example, by the particleIdx. Yo can then easily access from a particle to a collection of data related to your own logic and vice versa. - you could also extend the class SolidParticle (well, it's javascript) before creating your SPS and it will be compiled with the same performance then : SolidParticle.prototype.letter = ""; SolidParticle.prototype.myOwnFunction = function() { this.letter = doSomething(); }; then create your SPS as usual and your added particle properties will be available ? Sebavan 1 Quote Link to comment Share on other sites More sharing options...
Nodragem Posted November 29, 2018 Author Share Posted November 29, 2018 Thank you for your detailed explanation! Yep, so I guess it is not worth making my particles invisibles when behind walls. Concerning the data storage; I am using Typescript, I think it is a bit more complicated to add a custom property on a object. Would it impede the default performance if you added a property 'data:any' on your side, ready-to-use for the users? Quote Link to comment Share on other sites More sharing options...
jerome Posted November 29, 2018 Share Posted November 29, 2018 I don't think so because it's just some JS that is generated finally. This will rather impact the RAM consumption. But ... as people can manage dozen thousands particles in their SPS, I wouldn't add a default property that could never be used because people don't need it. I'm not a TypeScript expert, but I think there must be a way to re-open a class in order to add a property as JS allows it with prototypes (never forget that the final code is simply JS. Maybe some TS experts here could answer better than me. Anyway, the notation with SolidParticle.prototype.property should still work, because TS is still JS. If you can't modify the SolidParticle class and you don't want to manage a side array, maybe you could create your own objects (LogicalSolidParticles ?) either by extending the SolidParticle class, either by embedding the reference to the SolidParticle instance (the SPS will treat only SolidParticles, not other objects) in your own object type holding its dedicated properties. Then you could process your logic on the LogicalSolidParticles and just set the linked SolidParticles according to what they are supposed to do. It's a bit the same approach than the side array one, but you manage a pool of logical objects, each refering its related SolidParticle instead. There are plenty ways of doing. It would nice anyway to have an elegant way to reopen a class directly in TS. Quote Link to comment Share on other sites More sharing options...
Sebavan Posted November 29, 2018 Share Posted November 29, 2018 The three common ways would be : - inheritance so that you can modify the base call functions - creating a proxy which encapsulates the sps and drives the rest of your code or in Typescript, you can extend any classes with class Augmentation: Look at Module augmentation: https://www.typescriptlang.org/docs/handbook/declaration-merging.html brianzinn 1 Quote Link to comment Share on other sites More sharing options...
Nodragem Posted November 29, 2018 Author Share Posted November 29, 2018 Cool! I did not know we could do that with TS I will totally use this next time. Thanks for the ideas; for now I am happy with my array of data. 5 hours ago, jerome said: This will rather impact the RAM consumption. But ... as people can manage dozen thousands particles in their SPS, I wouldn't add a default property that could never be used because people don't need it. Ha ? yeah, that is indeed not a good idea if that impedes the performance Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.