25-11-2021, 09:06 AM
(24-11-2021, 09:07 AM)josemendez Wrote: You're most welcome
Whenever a new particle is emitted, the emitter's OnEmitParticle event is called. You can subscribe to this event and get the index of the particle that was just emitted. Similarly, there's a OnKillParticle event that provides the index of the particle being killed. You can use this to keep your array in sync.
Yes. Fluid emitters and regular particle emitters (I mean Unity's built-in particles, that do not interact with each other) have some important differences. Even though fluid is made of particles, they represent a continuous volume. This means that creating two particles very close together or on top of each other will cause a pressure spike (since they'd represent a volume with very high density) and would "explode" or ricochet off each other. So fluid particles must be very precisely placed to avoid these unwanted pressure spikes and a smooth flow.
For this reason, the Emit() function does not allow you to place particles *anywhere* you want. That would create many more problems than it solves. When you Emit(), the emission point is picked from the EmitterShape you're using. Since the points in an EmitterShape are guaranteed to have the correct spacing between them, this guarantees the particle will be emitted at a "free" position.
Note you can write your own ObiEmitterShapes, and create your own point distributions by overriding its GenerateDistribution() method. Be careful though to ensure points are at roughly "particleSize" distance from each other, for the reasons given above. Check the existing emitter shapes for reference. Remember: with great power comes great responsibility.
You could move the emitter indeed, or you could create your own emitter shape(s) as described above. Which one is best (most comfortable) depends on what you use case is.
Yet another possibility! It all depends on your needs. You can hook to the emitter's OnEmitParticle event to do this as soon as the particle is emitted.
If you want to be in full control of the particle's lifetime, yes. You might as well derive your own custom emitter component from ObiEmitter at this point, though.
You can either set the lifetime to zero (in that case, the ObiEmitter will kill it at the start of the next step), or you can call KillParticle(index) passing the index of the particle in the emitter. That will kill it instantly. Note there's usually not much difference between both approaches.
Not *exactly* the queries exposed by the API, but close. During simulation, every particle needs to know about all neighbor particles within the smoothing radius (not just for diffusion, but for pressure, tension...pretty much everything). Making one query per particle would be wasteful, so all particles are inserted into a grid. Then for all particles inside each grid cell, particles in the neighboring cells are considered.
When you make a query using Obi's spatial query API, the same grid structure is reused. For instance if you query the contents inside a rectangle, only grid cells overlapping the rectangle are considered.
There's two ways to do this: use collision callbacks with trigger colliders, or use a spatial query.
Every frame Obi calculates which colliders are in close proximity of a particle, create a contact between the particle and each collider, and then -for non-triggers- solve the contact. When you subscribe to collision callbacks, Obi gives you the list of contacts generated in the current frame. You can then use this information as you wish.
Spatial queries reuse the grid structure I explained above to determine which particles are close to the query volume. So both approaches reuse a lot of the stuff Obi needs to calculate anyway, which is a good thing because very little extra work is done.
Which to use depends on how often you need to know which particles are inside the volume, and how many volumes you need to check. If you need that every frame and have a lot of volumes, using collision callbacks&triggers will be more efficient. If you only what to check this once, or a few times, and there's just one or few volumes, using a query would be more convenient.
Let me know if I can help!
kind regards,
Thanks again. I think I get close to it. So the solution is like using a big amount of obi colliders to fill in a mesh and move with it, right?