• Advertisement
Sign in to follow this  

Problems in [Cloth Simulation] with Verlet Integration

Recommended Posts

Hey guys,

I'm doing a cloth simulation with verlet intergration, I assume you've all heard about it. But I came across with 2 main problems:

1. How to respond to collisions? 

    Now my update looks like:

    world::Update()

    {

        a. AllSoftBodies:UpdatePosition(); // Update the position using verlet integration, via particle.position and particle.lastPosition

        b. UpdateCollisions();    // using a grid-devided space to calculate collisions. And set particle.position = Contact.position.

        c. AllSoftBodies:UpdateConstraints();    // update all constraints within a certain amount of iterations.

    }

    My problem is that, every time my collided particles' contact position are found and set, but in the constraints update method, the collided particles are pulled away by its connected particles which were not collided.

    No matter what's the order of the a.b.c, they always won't stay at the collision state.

2. How to implement a stiffness in constraints?

    Now the constraints update look like :

        public virtual void Update()
        {
            Vector3 p1_to_p2 = second.position - first.position;
            float curDist = p1_to_p2.magnitude;
            if (curDist == 0.0f) return;
 
            Vector3 correctVecHalf = (p1_to_p2 * (1 - restDistance / curDist)) * 0.5f;   // so this will move back and force depends on the distance
            if (correctVecHalf != Vector3.zero)
            {
                first.ApplyPositionDelta(correctVecHalf);
                second.ApplyPositionDelta(-correctVecHalf);
            }
        }
     If I add a very strong force to the particles, then the constraints will be really large and looks not so realistic. What I want is that the Constraints can come close but can't be push away too far(determined by the so called stiffness).
 
    I would appreciate all the answers! Please help. 

Share this post


Link to post
Share on other sites
Advertisement

I did some tests, and the result shows that the "stiffness" in Verlet, seems to be related how many iterations I use to update the constraints. (BTW, I wonder if there exists any better ways to update the constraints rather than Update all of them multiple times per frame.)

Share this post


Link to post
Share on other sites

You could create a low detailed cloth rig (basically a coarse mesh) and link the actual cloth vertices by a max distance to barycentric coords of its triangles.

Because the coarse mesh has few vertices a low iteration count is enough. Further you can add additional constrains to prevent e.g. fast moving legs going through a long skirt.

I tried something like this and it works very well and fast even with tight cloth, but the downside is you need to create additional tools to set things up, so more time consumig for both programmers and artists.

 

Using a better constraint solver would be another option, but i don't know much about that.

Share this post


Link to post
Share on other sites

You could create a low detailed cloth rig (basically a coarse mesh) and link the actual cloth vertices by a max distance to barycentric coords of its triangles.

Because the coarse mesh has few vertices a low iteration count is enough. Further you can add additional constrains to prevent e.g. fast moving legs going through a long skirt.

I tried something like this and it works very well and fast even with tight cloth, but the downside is you need to create additional tools to set things up, so more time consumig for both programmers and artists.

 

Using a better constraint solver would be another option, but i don't know much about that.

Thanks Joe, I think we might be on the same path...

So I got another question, let's say if we want to have a constraint(most likely multiple constriants) that connects some particle on the leg, and another on a dress, what's the best way of finding these two particles? 

Share this post


Link to post
Share on other sites

In general there are two ways to handle multiple constraints:

 

Sequentially: Calc constraint projection, update particle position(s), calculate next constraint based on updated position and continue.

This is the way described in the original paper from Thomas Jacobsen you probably have read. Problem is that anything is order dependent, resulting in small cycles, jittering, drifting.

 

Parallel: Claculate all constraints based on the current particle positions and sum them up for each particle. Finally apply the sumed projection (multiplied by a damping factor between 0 and 1).

There is no order dependency and the system is more likely to come to rest, but also it's more likely to explode and you may need more iterations.

 

Neither is physically correct, but i always preferred the parallel way. I did still some ordering by constraint types, just an example:

1. Process the cloth rig (which does not depend on the real cloth, only on itself, the character and gravity).

2. Process the cloth vertices as usual (apply distance constraints to the neighbouring vertices and finally update position).

3. Apply distance and plane constraints between cloth rig and cloth vertices (only cloth vertices get affected)

4. Apply Cloth-Skin collisions (I use the cloth rig link here to quickly find the set of skin vertices that may collide based on precomputed data - no runtime acceleration structure necessary. Very fast, but no cloth self collisions.)

 

When this works you only need to improve the rig simulation to get good results. In my case it is a set of connected rings sliding up and down the skeleton bones.

Edited by JoeJ

Share this post


Link to post
Share on other sites

This isn't as complicated a problem as you think -- you just need to remember that collision constraints are a type of constraint, and solve them *together* with the distance constraints in your solving loop.

eg something like:

for(num_solver_iterations)
{
SolveDistanceConstraints();
SolveCollisionConstraints();
}

Of course, this moves collision detection to inside your solver loop, which is bad for performance. Typically people cache the broadphase and update the narrow phase, i.e your collision data knows the face+vertex that are colliding, and when solving the collision constraint you first check if collision is happening (which you have to do anyway to calculate the error term) and if not you skip solving it this iteration.

I hope this makes sense! 

Share this post


Link to post
Share on other sites

This isn't as complicated a problem as you think -- you just need to remember that collision constraints are a type of constraint, and solve them *together* with the distance constraints in your solving loop.

eg something like:

for(num_solver_iterations)
{
SolveDistanceConstraints();
SolveCollisionConstraints();
}

Of course, this moves collision detection to inside your solver loop, which is bad for performance. Typically people cache the broadphase and update the narrow phase, i.e your collision data knows the face+vertex that are colliding, and when solving the collision constraint you first check if collision is happening (which you have to do anyway to calculate the error term) and if not you skip solving it this iteration.

I hope this makes sense! 

Thanks raigan, I tried something like below:

FindCollisionParticles();  // if found one, then mark this particle isActive = false; which makes it also not movable by its physical update or constraints. 

for (num_iterations)

{

    SolveDistanceConstraints();

}

// at the end of the update

RecoverDeactivatedParticles();    // Reactive particles that are marked deactive in FindCollisionParticles();

 

Somehow this doesn't work for me.

Share this post


Link to post
Share on other sites

In general there are two ways to handle multiple constraints:

 

Sequentially: Calc constraint projection, update particle position(s), calculate next constraint based on updated position and continue.

This is the way described in the original paper from Thomas Jacobsen you probably have read. Problem is that anything is order dependent, resulting in small cycles, jittering, drifting.

 

Parallel: Claculate all constraints based on the current particle positions and sum them up for each particle. Finally apply the sumed projection (multiplied by a damping factor between 0 and 1).

There is no order dependency and the system is more likely to come to rest, but also it's more likely to explode and you may need more iterations.

 

Neither is physically correct, but i always preferred the parallel way. I did still some ordering by constraint types, just an example:

1. Process the cloth rig (which does not depend on the real cloth, only on itself, the character and gravity).

2. Process the cloth vertices as usual (apply distance constraints to the neighbouring vertices and finally update position).

3. Apply distance and plane constraints between cloth rig and cloth vertices (only cloth vertices get affected)

4. Apply Cloth-Skin collisions (I use the cloth rig link here to quickly find the set of skin vertices that may collide based on precomputed data - no runtime acceleration structure necessary. Very fast, but no cloth self collisions.)

 

When this works you only need to improve the rig simulation to get good results. In my case it is a set of connected rings sliding up and down the skeleton bones.

Thanks Joe, make great sense to me on why constraints need to be iterated.

Share this post


Link to post
Share on other sites

I've found what went wrong in my code...

It was my collision detection method. I was detecting a particle's position - lastPosition(as a Segment) to test with AABB, and it fails when position equals lastPosition... Stupid me... 

Share this post


Link to post
Share on other sites

 

This isn't as complicated a problem as you think -- you just need to remember that collision constraints are a type of constraint, and solve them *together* with the distance constraints in your solving loop.

eg something like:

for(num_solver_iterations)
{
SolveDistanceConstraints();
SolveCollisionConstraints();
}

Of course, this moves collision detection to inside your solver loop, which is bad for performance. Typically people cache the broadphase and update the narrow phase, i.e your collision data knows the face+vertex that are colliding, and when solving the collision constraint you first check if collision is happening (which you have to do anyway to calculate the error term) and if not you skip solving it this iteration.

I hope this makes sense! 

Thanks raigan, I tried something like below:

FindCollisionParticles();  // if found one, then mark this particle isActive = false; which makes it also not movable by its physical update or constraints. 

for (num_iterations)

{

    SolveDistanceConstraints();

}

// at the end of the update

RecoverDeactivatedParticles();    // Reactive particles that are marked deactive in FindCollisionParticles();

 

Somehow this doesn't work for me.

 

 

Sorry, maybe I didn't explain very well: you need to handle collision *just like a constraint*, i.e you need to solve both collisions and other constraints together in the loop, otherwise the solver won't converge nicely.

Something like:

for (num_iterations)
{
    SolveDistanceConstraints();
    SolveCollisionConstraints();
}

This way the constraint forces can "talk" to each other and find a mutually acceptable equilibrium state.

Of course: what does SolveCollisionConstraints() look like? There are many ways of implementing this; the un-optimized version is to run a full broad+narrow phase collision in here, but that gets slow. Instead you can cache the pairs returned by the broadphase before solving, and re-run narrow phase (i.e calculate the vert-face or edge-edge penetration depth and project out of collision if the two features are penetrating).

JoeJ's approach also works, AFAICT it's Jacobi iterations instead of Gauss-Seidel -- see the paper "Mass Splitting for Jitter-Free Parallel Rigid Body Simulation" for more info: IIRC you shouldn't be scaling by some arbitrary number but instead averaging all particle displacements based on relative mass. The paper has more details. The downside to Jacobi is that it converges more slowly.

Share this post


Link to post
Share on other sites

 

 

This isn't as complicated a problem as you think -- you just need to remember that collision constraints are a type of constraint, and solve them *together* with the distance constraints in your solving loop.

eg something like:

for(num_solver_iterations)
{
SolveDistanceConstraints();
SolveCollisionConstraints();
}

Of course, this moves collision detection to inside your solver loop, which is bad for performance. Typically people cache the broadphase and update the narrow phase, i.e your collision data knows the face+vertex that are colliding, and when solving the collision constraint you first check if collision is happening (which you have to do anyway to calculate the error term) and if not you skip solving it this iteration.

I hope this makes sense! 

Thanks raigan, I tried something like below:

FindCollisionParticles();  // if found one, then mark this particle isActive = false; which makes it also not movable by its physical update or constraints. 

for (num_iterations)

{

    SolveDistanceConstraints();

}

// at the end of the update

RecoverDeactivatedParticles();    // Reactive particles that are marked deactive in FindCollisionParticles();

 

Somehow this doesn't work for me.

 

 

Sorry, maybe I didn't explain very well: you need to handle collision *just like a constraint*, i.e you need to solve both collisions and other constraints together in the loop, otherwise the solver won't converge nicely.

Something like:

for (num_iterations)
{
    SolveDistanceConstraints();
    SolveCollisionConstraints();
}

This way the constraint forces can "talk" to each other and find a mutually acceptable equilibrium state.

Of course: what does SolveCollisionConstraints() look like? There are many ways of implementing this; the un-optimized version is to run a full broad+narrow phase collision in here, but that gets slow. Instead you can cache the pairs returned by the broadphase before solving, and re-run narrow phase (i.e calculate the vert-face or edge-edge penetration depth and project out of collision if the two features are penetrating).

JoeJ's approach also works, AFAICT it's Jacobi iterations instead of Gauss-Seidel -- see the paper "Mass Splitting for Jitter-Free Parallel Rigid Body Simulation" for more info: IIRC you shouldn't be scaling by some arbitrary number but instead averaging all particle displacements based on relative mass. The paper has more details. The downside to Jacobi is that it converges more slowly.

 

Thanks raigan, 

    I'm now focusing on the cloth simulation on an animated character. I tried to use a AABB hierachy for the character, and use a 3d grid spatial hashing for the broad phase collision detection, yes, for an AABB, I calculate its center and min and max, find which grids it's in, this part is fast, since it's just simple calculations. But since the character is animated, the AABB needs to be updated every frame, and besides, there is no access to the SkinnedMeshRenderer's current skinned vertices' position, I have to do the skinning my self. So the flow would look like:

UpdateOfACharacter()

{

    Skinning Character();

    Update Character AABB();

    Update AABB spatial hashing();

}

UpdateOfAClothObject()

{

    UpdateVerletIntegration();

    UpdateConstraints();    // Through iterations of cause.

    UpdateClothParticleSpatialHashing();

}

then Do the Collision Operations.

I found this process not running so fast, avg 25 FPS on a CPU i5 7500(on my android device it count down to 16 FPS on avg). Running with unity, C#, no multi-threading used yet.

So now I'm trying to do something unity cloth has already accomplished: cloth simulation blending animation and physics.

The idea is to do the physics first, and the compare the physics particles position with skinned vertices position, and find a proper way to blend those two, it's collision free, so it could be really fast. 

I just need to figure out how to blend those positions... Don't know how to do that yet...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Advertisement