Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Usage of particle position variables
#1
hi!


I see multiple variables about particle coordinates in IkSolver. They are: positions, restPositions, prevPosition, startPosition.
What is the specific update time for them?


In my case,I used two rigid bodies to try to lift the soft body.
Since I can't lift the soft body directly through friction, my design is to use collision detection to update the positions of the particles on the contact surface, so that the outer wall of the soft body is lifted by the rigid body.
For example, as shown in the following code, when OnObiCollision, the y component change of the rigid body is provided to the colliding particles. Although this implementation can make the soft body shake slightly, it still cannot be lifted completely.
If my code implementation is correct, I don't quite understand this problem. In my code, shouldn't the contact surface of the soft body be completely at the same height as the rigid body?
   

Code:
    public void OnObiCollision(ObiSolver solver, ObiNativeContactList contacts)
    {
        collisionnParticleSolverIndexes.Clear();
        leftCollisionParticleSolverIndexes.Clear();
        rightCollisionParticleSolverIndexes.Clear();

        for (int index = 0; index < contacts.count; index++)
        {
            Oni.Contact contact = contacts[index];

            int particleIndexInSolver = solver.simplices[contact.bodyA];

            ObiColliderBase collider = colliderWorld.colliderHandles[contact.bodyB].owner;
            if (collider.transform == leftClaw)
            {
                leftCollisionParticleSolverIndexes.Add(particleIndexInSolver);
            }
            else if (collider.transform == rightClaw)
            {
                rightCollisionParticleSolverIndexes.Add(particleIndexInSolver);
            }
        }

        isBind = leftCollisionParticleSolverIndexes.Count + rightCollisionParticleSolverIndexes.Count > 400;

        if (isBind)
        {
            float leftClawHeightOffset = leftClaw.transform.position.y - leftClawHeightBuffer;
            float rightClawHeightOffset = rightClaw.transform.position.y - rightClawHeightBuffer;

            for (int index = 0; index < leftCollisionParticleSolverIndexes.Count; index++)
            {
                int particleIndex = leftCollisionParticleSolverIndexes[index];

                solver.positions[particleIndex] = solver.startPositions[particleIndex] + new Vector4(0, leftClawHeightOffset, 0);
                solver.velocities[particleIndex] = Vector4.zero;
                solver.angularVelocities[particleIndex] = Vector4.zero;
                solver.externalForces[particleIndex] = Vector4.zero;
                solver.externalTorques[particleIndex] = Vector4.zero;
            }
            for (int index = 0; index < rightCollisionParticleSolverIndexes.Count; index++)
            {
                int particleIndex = rightCollisionParticleSolverIndexes[index];


                solver.positions[particleIndex] = solver.startPositions[particleIndex] + new Vector4(0, rightClawHeightOffset, 0);
                solver.velocities[particleIndex] = Vector4.zero;
                solver.angularVelocities[particleIndex] = Vector4.zero;
                solver.externalForces[particleIndex] = Vector4.zero;
                solver.externalTorques[particleIndex] = Vector4.zero;
            }
        }

        leftClawHeightBuffer = leftClaw.transform.position.y;
        rightClawHeightBuffer = rightClaw.transform.position.y;
    }

By the way, in addition to modifying the positions of the contact surface particles during the collision callback, I also tried to provide the particles with additional upward velocity. But I always feel that the particles on the contact surface seem to be given a downward momentum at some point in some way I don't know.

While retaining gravity, I hope to find a way to present the effect of the soft body being stably fixed in the air by external forces. To be honest, the effect I expected is like ObiParticleAttachment, but due to some project reasons, I can't use ObiParticleAttachment.
Reply
#2
(11-07-2024, 03:12 PM)wenhao_zheng Wrote: hi!


I see multiple variables about particle coordinates in IkSolver. They are: positions, restPositions, prevPosition, startPosition.
What is the specific update time for them?

restPositions is never updated: these are the positions of the particles at rest, used to determine whether particles intersect at rest and should ignore collisions with each other.

prevPositions are the positions of particles in the previous simulation step. They are simply copied from positions at the start of each step.

startPositions are the positions of particles at the start of the frame. Used for interpolating physics state, they don't affect the simulation.

You should only concern yourself with positions and velocities. All other data is calculated from them and used by the engine internally, and has no use externally.

(11-07-2024, 03:12 PM)wenhao_zheng Wrote: Although this implementation can make the soft body shake slightly, it still cannot be lifted completely.
If my code implementation is correct, I don't quite understand this problem. In my code, shouldn't the contact surface of the soft body be completely at the same height as the rigid body?

No, since particles are still simulated and will fall due to gravity. Since you're not setting an absolute position but adding a positional delta (clawHeightOffset) particles will still be able to fall.

(11-07-2024, 03:12 PM)wenhao_zheng Wrote: But I always feel that the particles on the contact surface seem to be given a downward momentum at some point in some way I don't know.

This would be gravity: gravity is an acceleration, that is, a change in velocity. Every simulation step, particles get their velocity increased due to gravity and move according to their velocity. Since you're setting particle velocity to zero instead of -gravity*time, you get this:

Engine:
velocity += acceleration (gravity in this case) * time;
position += velocity * time;

Your code:
position += clawOffset;
velocity = 0;

Engine:
velocity += gravity * time;
position += velocity * time;

Your code:
position += clawOffset;
velocity = 0;

and so on.

As you can see, after you set the velocity to zero and add the clawOffset, the engine applies gravity which increases velocity and moves the particle downwards. Your code doesn't take gravitational acceleration into account, so it assumes particles are in zero gravity which isn't the case and will allow particles to fall a little bit each frame.

(11-07-2024, 03:12 PM)wenhao_zheng Wrote: While retaining gravity, I hope to find a way to present the effect of the soft body being stably fixed in the air by external forces. To be honest, the effect I expected is like ObiParticleAttachment, but due to some project reasons, I can't use ObiParticleAttachment.

Why not store the position coordinates of each particle relative to the claw (at the time of grabbing), and just set that position instead of adding an offset? This is simpler than your code, would work in all claw movement directions even with rotations, and would get rid of the issue since you force the particles to be at a specific position instead. This is what ObiParticleAttachment does internally. You can also find an example of doing this with contact callbacks in /Obi/Scripts/Common/Utils/ObiContactGrabber.cs

kind regards,
Reply
#3
(12-07-2024, 08:14 AM)josemendez Wrote: restPositions is never updated: these are the positions of the particles at rest, used to determine whether particles intersect at rest and should ignore collisions with each other.

prevPositions are the positions of particles in the previous simulation step. They are simply copied from positions at the start of each step.

startPositions are the positions of particles at the start of the frame. Used for interpolating physics state, they don't affect the simulation.

You should only concern yourself with positions and velocities. All other data is calculated from them and used by the engine internally, and has no use externally.


No, since particles are still simulated and will fall due to gravity. Since you're not setting an absolute position but adding a positional delta (clawHeightOffset) particles will still be able to fall.


This would be gravity: gravity is an acceleration, that is, a change in velocity. Every simulation step, particles get their velocity increased due to gravity and move according to their velocity. Since you're setting particle velocity to zero instead of -gravity*time, you get this:

Engine:
velocity += acceleration (gravity in this case) * time;
position += velocity * time;

Your code:
position += clawOffset;
velocity = 0;

Engine:
velocity += gravity * time;
position += velocity * time;

Your code:
position += clawOffset;
velocity = 0;

and so on.

As you can see, after you set the velocity to zero and add the clawOffset, the engine applies gravity which increases velocity and moves the particle downwards. Your code doesn't take gravitational acceleration into account, so it assumes particles are in zero gravity which isn't the case and will allow particles to fall a little bit each frame.


Why not store the position coordinates of each particle relative to the claw (at the time of grabbing), and just set that position instead of adding an offset? This is simpler than your code, would work in all claw movement directions even with rotations, and would get rid of the issue since you force the particles to be at a specific position instead. This is what ObiParticleAttachment does internally. You can also find an example of doing this with contact callbacks in /Obi/Scripts/Common/Utils/ObiContactGrabber.cs

kind regards,


Thank you for your reply.

In your last reply, you mentioned two processes in the engine, which are updating velocity according to acceleration and updating position according to velocity.
For me, I implement work based on callback functions, such as the one I organized in the figure below.

What I want to confirm with you is that before OnEndStep, the velocity, acceleration, and position of particles are constantly updated with the operation of constraint simulations, right?
In my current understanding, if I set the absolute values of positions before OnEndStep, it may be overwritten by some physical simulation at some time, right?
So if I need to set the absolute values of positions of particles in the scene,  I can only set them in OnEndStep, right?

   
Reply
#4
(12-07-2024, 01:25 PM)wenhao_zheng Wrote: Thank you for your reply.

In your last reply, you mentioned two processes in the engine, which are updating velocity according to acceleration and updating position according to velocity.
For me, I implement work based on callback functions, such as the one I organized in the figure below.

What I want to confirm with you is that before OnEndStep, the velocity, acceleration, and position of particles are constantly updated with the operation of constraint simulations, right?
In my current understanding, if I set the absolute values of positions before OnEndStep, it may be overwritten by some physical simulation at some time, right?
So if I need to set the absolute values of positions of particles in the scene,  I can only set them in OnEndStep, right?
Hi!

The simulation is performed before collision callbacks are called, so if you modify the positions in the collision callback (as you are doing now) they won't be overwritten by the simulation.

OnEndStep is called immediately after collision callbacks and external force buffers have been cleared. Like this:

Code:
OnBeginStep()

foreach substep
{
OnSubstep()
// engine updates positions, velocities, etc here
}

OnCollision()
OnParticleCollision()
ResetExternalForces()
OnEndStep()

kind regards,
Reply