Integration of FLUIDS v.2 (SPH Fluids)

rtrius
Posts: 43
Joined: Sat May 26, 2012 1:09 am

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by rtrius »

My Bullet3 fork (https://github.com/rtrius/bullet3) runs entirely on the GPU, and has 2 way interaction
with rigid bodies implemented using a similar method as the Bullet-Fluids v.2 library. I'm having some
crashes with compound-compound(rigid against rigid) after updating to a more recent version of Bullet3,
though.

Here is an earlier video:
http://www.youtube.com/watch?v=1HHJJLKkGUQ

I've also looked into Fluids v.3, and implemented a similar solver (b3FluidSphSolverOpenCL2 in the Bullet3 fork).
From what I can tell, the main difference between Fluids v.3 and b3FluidSphSolverOpenCL2 is that it:
  • -Uses a variable sized explicit grid instead of a fixed size(64^3) grid
  • -Does not use modulo to expand the grid into an infinite domain
    • (not using modulo causes memory issues for very large scale simulations,
      but using modulo would make some optimizations more difficult)
  • -Uses counting sort instead of radix sort
    • (Fluids v.3 also sorts the particles in the counting sort kernel,
      as opposed to sorting [grid cell index, particle index] pairs,
      and then using that sorted array to rearrange the position, velocity, etc. arrays)
Implementing the main optimizations from Fluids v.3 would only require replacing one or two kernels,
but is the 'Fluids-Zlib' license acceptable? It seems very similar to the MIT license.

There is also a more optimized solver(b3FluidSphSolverOpenCL) using a different grid algorithm.
Excluding things such as compiler optimizations(not implemented in Fluids v.3 itself, but due
to CUDA having closer access to the underlying GPU architecture) this solver should be very
competitive with Fluids v.3.

An example timing would be ~12ms for a fluid simulation of 131,072 particles at rest on a Radeon HD 5850.
This timing, which does not include rigid body interactions, may be decomposed as:
  • ~8 ms for the SPH density, SPH force calculation, and position/velocity integration
  • ~4 ms for the grid update
Of these, I expect all stages to be faster than or equal to an OpenCL port of Fluids v.3 except for the grid update.
Additionally, even if an OpenCL port were to reduce the grid update to 0ms/frame and be equally fast on all other
steps, it would be at best ~1.5x faster.

Regarding fluid-rigid interactions, fluid particles are currently able to tunnel through rigid body trimeshs as the
OpenCL raycaster has yet to be optimized. I would like to implement such optimizations -- does testing each ray
against the GPU SAP broadphase sound like a reasonable optimization?
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by Erwin Coumans »

Thanks for all the information, the video looks nice. It does look only one-way interaction. Would it be possible to have the fluid push away the cubes, and cubes floating on sph particle fluids?

Bullet is zlib, and so is fluids v2 and v3, so there is no license issue.

I tried compiling your fork, but the build system is broken. I tried to file a patch but your project has no issues tab, why is that? https://github.com/rtrius/bullet3
Attached is a patch for the premake build system, it lacks BulletFluids and "clew" projects.

After fixing the build system, the Fluids demo crashes, due to an OpenGL issue, on an NVIDIA 650m under Windows 8 (not clear why exactly).
It would be nice if the fluids had the option to render plain particles by default using the Bullet 3 rendering, it is known to work fine cross-platform.

Compounds versus compounds work just fine for me. Can you reproduce the compound versus compound in an unmodified Bullet 3 version? If so, please file the issue here:
https://github.com/erwincoumans/bullet3/issues

Thanks,
Erwin
You do not have the required permissions to view the files attached to this post.
rtrius
Posts: 43
Joined: Sat May 26, 2012 1:09 am

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by rtrius »

The video above is a few months old. In the current version, fluid particles are able to push
rigid bodies and make them float.

As for using the Bullet 3 renderer, which classes or functions should I be looking at? Using
GLInstancingRender::drawPoints() works, but changing the pointDrawSize parameter has no
effect on the point size. Looking at line 1308 (line 1312 in the main branch) of
GLInstancingRender.cpp, it seems to use the shader for rendering lines instead of the one
for spheres.

Also, the fluid-rigid interaction is currently not optimized in terms of memory consumption so
there may be out of memory errors when using large numbers of particles. With 1 GB of video
memory, the error occurs somewhere in the range of 768,000 - 1 million particles.

Thanks for the patch and feedback.
Rvo
Posts: 21
Joined: Fri Nov 01, 2013 1:44 pm

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by Rvo »

Thank rtrius, it is working pretty well now. If you don't mind, can I ask a few more questions?

I am aiming to create some kind of bleed effect. Fluids like blood like to "cluster", by which I mean particles have attraction on those particles that are near them, using some kind of weight. The further a particle is the less it is attracted to the other particle. I guess this would require some sort of neighbour search and adding an attractive force. Is this easy to do?

I tried your btFluidSphSolverPCISPH but yeah it makes fluids very incompressible. When two particles spawn in eachothers radius then they eject eachother. I now use the regular solver and set the stiffness to 0.0-ish. As you know, water particles tend to merge/stick to eachother. Am I correct in assuming it will be very hard to make a convincing looking fluid by just rendering sphere meshes for the particles? I tried tweaking the stiffness, but I guess water is incompressible so the stiffness should be 1.5 - which makes it look a bit strange without any renderer attached. Any suggestions maybe how I might make it look a bit better? I don't really have time to create or copy the screenspace renderer in Ogre3D... I'm not sure which setting is causing this at the moment, but particles tend to overlap a lot in my setup. Is this something related to margin..?

Thanks!
rtrius
Posts: 43
Joined: Sat May 26, 2012 1:09 am

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by rtrius »

btFluidSph::getRigidContacts() contains the contacts for the current frame,
so it should not be necessary to use a contact-pair test. A post-tick callback
(see btFluidRigidDynamicsWorld::setInternalFluidTickCallback) may be used to
modify the particle velocities. As explained below, however, there may be
another option that does not involve adding an additional force for sticking.

Making the fluid particles cluster will require some effort; it would be necessary
to modify the SPH force calculation. There are many methods for this; search
for papers on surface tension forces. A simple implementation may be found in
"Particle-Based Fluid Simulation for Interactive Applications" by Muller et al. In
particular, see equations 5 and 19.

There isn't a very convincing way to draw the fluid using only spheres, but you
could try adding (smaller?) 'secondary particles' to the simulation that are
unaffected by SPH forces but still collide with the mesh.

It should be easy to add a 'null' solver that does not compute interparticle/SPH
forces; create a subclass of btFluidSphSolverDefault in btFluidSphSolver.h and
copy the updateGridAndCalculateSphForces() function. Only insertParticlesIntoGrid()
needs to be called, so removing the other functions will disable the SPH force. Next,
create a second btFluidSph and set the 'override solver' to the null solver.


Using secondary particles may also help solve the issues with particles being unable
to stick to the mesh. The reason that friction is not enough is likely for 2 reasons.
The first reason is that the SPH forces may be too strong, and would as a result
override the friction force.

The second reason is related to the method for resolving fluid-rigid collisions. First,
a force(or 'impulsive force') is applied to stop the particle from penetrating further
into the mesh in the next frame. Next, a second force is applied to remove penetration.
The magnitude of this second force is dependent on m_boundaryErp of the fluid's
'local parameters'. Since this second force causes the particle to be pushed outwards,
using a high m_boundaryErp would only allow the friction force to be applied for a very
short time(as the friction force is only active when the fluid particle is touching the mesh).

A solution for the sticking issue might be to spawn particles at first using the 'null solver'
(make sure to use a low or 0 m_boundaryErp, the default is very high). Then, to swap it
with an SPH particle depending on how high the particle is or how many frames it has existed.
In theory, this method should allow the particles to stick to the mesh, then behave like a fluid
as it falls and hits the ground.
Rvo
Posts: 21
Joined: Fri Nov 01, 2013 1:44 pm

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by Rvo »

Thanks for the ideas! I came up with a different idea while pondering on the sticking issue further. Basically it comes down to this: friction works pretty well on most surfaces, even if they are pretty steep. Although sometimes when spawning the particles from multiple nearby emitters (an emitter is placed onto the mesh at distance "particleRadius + epsilon" to prevent initial particle collision with the mesh when spawning) I think the SPH forces are somehow too erratic/strong that sometimes the partices shoot away from the emitter and sometimes they slowly slide along the mesh. For this I do not know the exact solution, maybe I will try your 'null'-solver under certain conditions. Then again the idea was to use SPH-forces overall...

Your idea about the non-SPH particles seems ok but I don't think friction alone will solve this. At sharp edges the particle will always "fall over the edge", even with high friction. Imagine throwing some SPH-particles on your desk. When they reach the end the friction will only have decreased their velocity, but they will still continue to fly over the edge in a curved trajectory. Even if the speed is really really low there is still the curved trajectory meaning the particle will have a hard time keeping attached to your desk.

Anyway, I was thinking that once a surface is too steep (like 90 degrees or maybe more), and the particle will stop touching the mesh (as it falls off the edge so to speak) I will add a (subtle) force that will push the particle towards the mesh (the force will be perpendicular to the mesh). Depending on the distance, the force will initially be small (particle close to the mesh) and then grow as the particle gets removed further from the mesh. At some breakpoint (eg particle too far from mesh) the force will decline again or it will be removed entirely. This should make it seem like the particle is actually sticking. It might not be entirely accurate but my goal is to find out how an effect can best be achieved, so even "cheating" is allowed.

As for your visually more appealing secondary particles idea, I think I understand what you're trying to say but I'm failing a bit in visualizing it in my mind. Once a real SPH-particle is spawned, your suggestion is to create some secondary particles at the same time (and position?) and letting them be handled by the regular Bullet collision algorithms? That would mean that the fluid looks a bit more dense than when you only add one SPH-particle sphere?

I was also thinking for visual improvements that using the screen space rendering [Van der Laan et al. 2009] technique and the improvements done (see http://www.academia.edu/5272197/Real-ti ... Simulation) might work. This means that, based on the current density of the fluid (in the "local" area of a particle?), the size of the particle's billboard/mesh is reduced. As an example: when a single particle like a water drop jumps up when a wave is hitting the boundary, the local density for that drop is very low and the (billboard/mesh)size is reduced. Once it falls down and approaches the bulk of the fluid again then it's (billboard/mesh)size will increase. I hope this makes sense. If I could bother you to look at the provided link I would be grateful, a visual example is best seen in the slide called "Character Only Example". Do you think it is possible to "easily" find out whether a particle is part of the main liquid or part of a splash? I thought density might be the most appropriate descriptor, but I'm open for suggestions. This way when some particles are close to each other they form a bit of a blob, and if a particle detaches itself then the size reduces, making it look more like a droplet.

One thing though. Once a particle's lifetime is exceeded, it returns to the position of its assigned emitter to be 'spawned' again. The particles however tend to switch places with other emitter positions when they spawn. I've debugged it and every particle is supposed to spawn at the correct emitter with subsequent position. Any ideas...? I hope the m_fluidParticleIndex doesn't change in the SPH-fluid... right? That's how I link my billboard/mesh to each particle, each particle in the fluid has its own mesh/billboard. It is almost as if setting the position of the particle somehow doesn't correspond with the m_fluidParticleIndex anymore. When a particle resets, I grab its m_fluidParticleIndex, which may be 0. I then tell the SphFluid to setPosition(m_fluidParticleIndex, newPosition). But the particle that should be relocated is actually a different one than should. The particle that I expected to have m_fluidParticleIndex is happily sliding along :/ It's almost as if they are being randomized but this flag is off by default in the default solver...? Anyway, when I label my billboards, they constantly switch places, meaning that the initial m_fluidParticleIndex in the SPH-fluid is constantly changing with regard to the m_fluidParticleIndex assigned to a billboard. Can I fix that? Once a SphParticle has a index in the fluid, it should not change...

Thanks so much again, you have no idea how much you've helped already :)

P.S., for the contacts, do I need to loop like this or is this inefficient...?

Code: Select all

m_particles = my array with structs with an reference-index to the SPHFluid particleIndex
btAlignedObjectArray<btFluidSphRigidContactGroup>& contactGroup = _physicsEngine->getFluid()->internalGetRigidContacts();
for (int i = 0; i < m_particles.size(); ++i)
{
     for (int cg = 0; cg < contactGroup.size(); ++cg)
     {
           if (contactGroup.at(cg).numContacts()) 
           {
                for (int ct = 0; ct < contactGroup.at(cg).numContacts(); ++ct)
                {
                      if (m_particles[i]->m_fluidParticleIndex == contactGroup.at(cg).m_contacts.at(ct).m_fluidParticleIndex) then stuff
                }
            }
     }
}
I might loop the contactgroups etc seperately and only update the contacts that are actually there instead of looping through all my particles (although I need to do that loop anyway), but it's about the main idea of retrieving the contacts.
rtrius
Posts: 43
Joined: Sat May 26, 2012 1:09 am

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by rtrius »

You are correct about the edge/downwards normal issue with friction; I did not consider that
case when thinking it up.

The idea about using secondary particles is more or less as you have understood it, except, the
particles could be smaller and spawned with an offset. Another option would be to have the
additional particles exist only on the rendering side and take the previous positions of the SPH
particles, so that each SPH particle has a trail of smaller particles. This probably does not sound
too effective, but there are not many options if only particles are usable.

Varying the billboard size by density sounds like a good idea. One minor issue though: if there is
a pool or column of fluid, the density tends to increase towards the bottom, so the
expansion/contraction of each billboard should be bounded. Also, it would be necessary to make a
modification to transfer the density back to the CPU in case the OpenCL solver is used.

The particle indices(m_fluidParticleIndex) do change from frame to frame, but
btFluidSph::get/setParticleUserPointer() can be used to associate each particle with a unique id
or struct. (As you might expect, this is for optimization reasons - sorting the particles by grid cell
helps improve the cache hit rate).

Each contact group corresponds to a rigid body that is colliding with any of the particles in a
btFluidSph, so it would be better to loop through the contact groups separately, even if the particles
need to be iterated through. An improved version might look something like:

Code: Select all

btAlignedObjectArray<btFluidSphRigidContactGroup>& contactGroup = _physicsEngine->getFluid()->internalGetRigidContacts();

for (int cg = 0; cg < contactGroup.size(); ++cg)
{
	btFluidSphRigidContactGroup& group = contactGroup[cg];

	if( group.m_object == the triangle mesh )
	{
		for(int c = 0; c < group.numContacts(); ++c)
		{
			const btFluidSphRigidContact& contact = group.m_contacts[c];
	
			//fluid->getPosition(contact.m_fluidParticleIndex);
			//...
		}
	}
}
Since the collision detection currently does not include triangles near but not colliding with fluid
particles, I've added a commit at the Github repository to allow expanding the radius of particles
during the collision detection stage.
Rvo
Posts: 21
Joined: Fri Nov 01, 2013 1:44 pm

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by Rvo »

How would the pointer setting work exactly? I have a struct, SphParticle, holding positions, a Ogre node etc, stored in a vector m_particles. Once the particle should spawn, and hasn't already, I do the following:

Code: Select all

for (int i = 0; i < m_particles.size(); ++i) {
   // Check lifetime passed - yes, check if spawned before, if not spawned, add particle to SphFluid
   // Add a new SphParticle to the fluid, setting the position to the spawn point, eg the emitter location.
   m_particles[i]->m_fluidParticleIndex = _physicsEngine->getFluid()->addParticle(
       btVector3(btScalar(emitterPosition.x), btScalar(emitterPosition.y), btScalar(emitterPosition.z))
   );
   _physicsEngine->getFluid()->setParticleUserPointer(m_particles[i]->m_fluidParticleIndex, m_particles[i]);
}
So now the first newly added particle in the SphFluid has m_fluidParticleIndex 0 and I link it to my struct (m_particles[0]) in the particles-vector.
On the next update and I'm looking at particle 0 (m_particles[0]), how do I get the right SphFluid particle that is linked to m_particles[0]?
I assume I'm gonna have to use getParticleUserPointer() but since the index changes over the frames would that mix up the pointers as well?
In other words, do I need to loop over all SphFluidParticles to do a check whether its ParticleUserPointer == the m_particles struct?

And what would be the correct notation? I guess something like this:

Code: Select all

SphParticle* particle = static_cast<SphParticle*>(_physicsEngine->getFluid()->getParticleUserPointer(m_particles[i]->m_fluidParticleIndex));
However that still doesn't make the connection between my Particle struct in my m_particles and the SphFluidParticle it SHOULD be linked to without using the SphFluid's m_fluidParticleIndex that changes over time. I hope I'm clear in typing all this, I imagine it might get a bit vague at times. So a SphParticle-struct is linked to a SphFluidParticle, and at all times when I take any SphParticle-struct I need to know the position of the SphFluidParticle that it was linked to originally but using a User-set pointer (as you told me).

I really need to loop through my own m_particles to get all to-be-updated particles etc.

What I do now, is loop through all the SphFluid particles (iterator s), get the ParticleUserPointer(my SphParticle struct) and then do another loop through my SphParticle* vector m_particles. If "m_particles == SphFluidParticle->getParticleUserPointer(s)" then I update my struct, setting m_particles->m_fluidParticleIndex to the SphFluidParticle m_fluidParticleIndex (s).

This is as efficient as I'm currently capable of coming up with :)

Thanks again!
rtrius
Posts: 43
Joined: Sat May 26, 2012 1:09 am

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by rtrius »

If m_particles has to be looped through, we can try a different approach. A new function (check the repository),
btFluidSortingGrid::getValueIndexPairs(), can be used to access the previous indices of the particles.
The main idea is to think of the array containing previous indices as a function that maps [current_index -> old_index].
In order to get the new index of a particle using the old index, this mapping can be reversed to [old_index -> current_index].

The particle indices change after every internal simulation step, so it would be necessary to update the indices
using a post tick callback (see btFluidRigidDynamicsWorld::setInternalFluidTickCallback(), with isPreTick = false)
if btFluidRigidDynamicsWorld::stepSimulation() is set to run multiple internal simulation steps.

Code: Select all

void postTickCallback(...)
{
	btFluidSph* fluid = ...;
	const btAlignedObjectArray<btFluidGridValueIndexPair>& valueIndexPairs = fluid->getGrid()->getValueIndexPairs();
	
	//valueIndexPairs maps [new index -> old index], create an array mapping [old index -> new index]
	btAlignedObjectArray<int> newIndices;	//Should be created somewhere else to avoid memory allocation overhead
	newIndicies.resize( fluid->numParticles() );

	for(int i = 0; i < fluid->numParticles(); ++i) 
	{
		int newIndex = i;
		int oldIndex = valueIndexPairs[i].m_index;
		newIndicies[oldIndex] = newIndex;
	}
	
	//
	for(each element in your m_particles)
	{
		m_particle[i].m_fluidParticleIndex = newIndices[ m_particles[i].m_fluidParticleIndex ];
	}
}
Now that I think about it, you could also use btFluidSph::getFluidParticleIndex() with your SphParticle struct array
to create the [old index -> new index] mapping.


As another alternative, is it also possible to rearrange the contents of m_particles to match the btFluidSph indices:

Code: Select all

void postTickCallback(...)
{
	//	create an array, btAlignedObjectArray<SphParticle> m_particlesNew, somewhere else

	btFluidSph* fluid = ...;
	const btAlignedObjectArray<btFluidGridValueIndexPair>& valueIndexPairs = fluid->getGrid()->getValueIndexPairs();
	
	for(int i = 0; i < fluid->numParticles(); ++i)
	{
		int newIndex = i;
		int oldIndex = valueIndexPairs[i].m_index;
		m_particlesNew[newIndex] = m_particles[oldIndex];
	}
	
	m_particles = m_particlesNew;
}
Rvo
Posts: 21
Joined: Fri Nov 01, 2013 1:44 pm

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by Rvo »

Ah yes, very helpful! My method worked somewhat but this is so much better.. not to mention more accurate with the postTicks!

Is it good practice to do all the contact-checking and force application in the m_fluidWorld->setInternalFluidTickCallback() too? My application has timesteps of ~0.000101277s (530 fps), so with the regular stepSimulation()'s fixedTimestep I only get a call to setInternalFluidTickCallback every 18-20 application updates... so I think maybe setInternalFluidTickCallback is actually not good to use at the moment, I'd be better off using my physicsEngine update in that case. Surely there's something I need to fix though? I assume it has to do with the fluid's fixed timestep...

I also noticed you added m_particleRadiusExpansion calculations, what is the practical use of this? I know it is used in the collision detection but it is not related to the local density and decreasing or increasing the billboard size? If not, how would you propose to find out the "correct" billboard size for a seperate particle?

Thanks again for your time. I can only hope it might be helpful for someone else in the future :)
rtrius
Posts: 43
Joined: Sat May 26, 2012 1:09 am

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by rtrius »

It is generally better to perform contact-checking and force application in setInternalFluidTickCallback(),
since that corresponds to the actual update of the physics simulation. To clarify, when
btFluidRigidDynamicsWorld::stepSimulation() is called, 3 parameters are passed in:

Code: Select all

timeStep - the delta time, or the amount of time('wall-clock' time) that has passed,
maxSubSteps - the maximum number of internal simulation steps(and also the max number of times setInternalFluidTickCallback() is called), and
fixedTimeStep - the time step of the physics simulation
Unless maxSubSteps is set to 0, the amount passed in timeStep is accumulated and a physics update occurs only
when that accumulated amount execeeds fixedTimeStep, so it is an expected result that setInternalFluidTickCallback()
is only called every ~20 application updates with such a small timestep. If the accumulated time is less, then
calling stepSimulation() only updates the motion states(that is, the rendering positions/rotations) of the rigid bodies.

m_particleRadiusExpansion can be used to include triangles that are near, but not colliding in btFluidSph::getFluidRigidContacts().
Normally, a collision is reported when (distance <= 0), that is, when the particle is penetrating. Using m_particleRadiusExpansion
will report collisions when (distance <= m_particleRadiusExpansion). It should be useful when applying a force to make the particles
stick to the mesh.

The SPH pressure force pushes particles that are below rest density together, and separates particles
that are above rest density. When a fluid particle has settled and is not moving, it should be at the rest density.
So, a method for billboard scaling might be to define a default radius, for when the particles are at rest density,
and then scale the radius with (density / rest density). The scaling should be bounded, though, as particles at the
bottom tend to have higher density then particles at the top, and particles at the boundaries tend to have lower density.

I've also added a function to access the inverted density(m_invDensity == 1.0 / density) of the particles:

Code: Select all

btFluidSph* fluid = ...; 
const btFluidSphSolverDefault::SphParticles* solverData = static_cast<const btFluidSphSolverDefault::SphParticles*>( fluid->getSolverData() );
if(solverData)
{
	//...
}
Thanks for the feedback, it has helped to improve the library.
Rvo
Posts: 21
Joined: Fri Nov 01, 2013 1:44 pm

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by Rvo »

Thanks for the addition, I'll have to look into it more later :)

As for the timestep, would the following give correct results?

Code: Select all

m_fluidWorld->stepSimulation(secondsPassed, 0);
It seems to function well, but it runs a lot faster than

Code: Select all

m_fluidWorld->stepSimulation(secondsPassed);
That makes sense ofcourse. The particles fall down a LOT faster now. Maybe even more realistic... but from a 4 meter high distance they do seem to fall TOO fast. With the maxSubsteps set, the particles fall down in slow motion almost. With 0 maxSubSteps and the fixed timestep set to 0.001 (instead of 0.0166667 default) they fall slower, but fast enough for a visually nice effect. My question is, is there anything "logical" to say about it, in terms of "what's better"? I guess the result that is visually most pleasing could be the most preferable... so is fiddling around with the maxSubsteps/fixedTimestep any good you reckon? I realize this is not directly tied to the fluids ofcourse.

Thanks!
rtrius
Posts: 43
Joined: Sat May 26, 2012 1:09 am

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by rtrius »

Using stepSimulation(secondsPassed, 0), with maxSubSteps == 0, configures the rigid body
simulation to use variable time steps. This should be avoided as the fluid simulation only
supports fixed time steps; calling stepSimulation() in this case will:
  • -Move the rigid body simulation forward by secondsPassed
    -Move the fluid simulation forward by 3 ms(default)
That is, the fluid and rigid body simulations will quickly become unsyncronized. Another issue is
that it will be more difficult to reproduce errors, as secondsPassed is not the same each time
the program is run. For these reasons, maxSubSteps should be set to 1 or greater.

Changing fixedTimeStep will have no effect on the fluid simulation aside from changing how often
it is updated. By default the ratio between fluid and rigid simulations is, 3 ms/16 ms
(or 3 ms/fixedTimeStep). That is, the fluid is updated by 3 ms for every 16 ms that passes in the
rigid body simulation. So, reducing the fixedTimeStep will mean that the fluid is updated more
often. Ideally, a 1:1 ratio should be used, but in practice the fluid simulation cannot be
updated quickly enough.
Rvo
Posts: 21
Joined: Fri Nov 01, 2013 1:44 pm

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by Rvo »

So, if I want to apply a force on a particle to push it back at the mesh, can I do that every 0.0001 seconds in my regular update, or doesn't that any other effect than doing it in the internal callback that happens every 30th iteration of my update (0.003 - fluid)?

I pulled the new library from GitHub too, but now I get a crashing application when starting the simulation with StepSimulation(). Not sure why...

Seems you put const bool USE_IMPULSE_BOUNDARY = 1; in btFluidRigidDynamicsWorld.cpp and switched some stuff around.. prob for your position based things but yeah that kinda crashed it :)
Maybe the !usedSolver->isPositionBasedSolver() check or something, if I remove that it works.
rtrius
Posts: 43
Joined: Sat May 26, 2012 1:09 am

Re: Integration of FLUIDS v.2 (SPH Fluids)

Post by rtrius »

If the update is performed with stepSimulation(0.0001, maxSubSteps, 0.003), for example, then
the force will not be applied until every 30th time stepSimulation() is called. The force accumulates,
so if btSphFluid::applyForce() is called every time stepSimulation() is called, it will be 30 times larger
with the above parameters.

Not sure why its crashing; I'm not having any issues with the OpenCL solver or btFluidSphSolverDefault.
Which solver is used? Does the btFluidSphDemo crash? What happens if isPositionBasedSolver() is called
when the solver is created?

What is the output if printf() is called with the addresses of the overrideSolver and usedSolver?
To be clear, if something like this is added near line 194 in btFluidRigidDynamicsWorld.cpp:

Code: Select all

printf("m_solver: %d, override: %d, used: %d \n", m_fluidSolver, overrideSolver, usedSolver);