Page 1 of 1

MotorizedGrabSpring class applies extraneous impulse?!

Posted: Thu Jul 21, 2011 11:56 pm
by Spankenstein
Each time the MotorizedGrabSpring.Setup method is called a small impulse is applied to the Entity associated with the class causing the selected object to move slightly each time it is grabbed.

If I check the value of the Entity's LinearMomentum then it is: (0, -0.16454, 0)

This is especially noticeable if the Entity.IsActive is false.

Here is a video demostrating what I mean (notice the values at the right hand side): http://www.youtube.com/watch?v=JkDGnnCov-c

Here's my extended Setup method for a MotorizedGrabSpring class:

Code: Select all

        public void Setup(Entity e, Vector3 grabLocation)
        {
            Entity = e;

            // Get the original entity properties that will need to be changed for this GrabSpring to function correctly
            isActive = Entity.IsActive;
            isAffectedByGravity = Entity.IsAffectedByGravity;
            isEntityDynamic = Entity.IsDynamic;
            originalEntityCollisonRule = Entity.CollisionInformation.CollisionRules.Personal;

            // Now change those properties so that the entity can be manipulated by the 'GrabSpring' in the desired manner

            // Make sure that the grabbed entity is active so it can be moved by the 'GrabSpring' if the simulation is paused
            Entity.IsActive = true;
            
            if (!isEntityDynamic)
            {
                Entity.BecomeDynamic(1f);
            }

            // Must be disabled AFTER becoming dynamic
            Entity.IsAffectedByGravity = false;

            // Can I assign a rule to this entity's collision pairs?
            // This way the other object in the collision pair will also react in the same way as this object for that particular collision.
            if (!(Entity.CollisionInformation.Tag is EntityAttractor))
            {
                Entity.CollisionInformation.CollisionRules.Personal = CollisionRule.NoBroadPhase;
            }

            LocalOffset = Vector3.Transform(grabLocation - e.Position, Quaternion.Conjugate(e.Orientation));

            GrabbedOrientation = e.Orientation;
            GoalPosition = grabLocation;

            angularMotor.Settings.Servo.Goal = e.Orientation;
            angularMotor.Settings.Servo.SpringSettings.StiffnessConstant = 60000f * Entity.Mass;
            angularMotor.Settings.Servo.SpringSettings.DampingConstant = 900f * Entity.Mass;
            angularMotor.Settings.MaximumForce = 10000f * Entity.Mass;
            angularMotor.Settings.VelocityMotor.Softness = .1f / e.Mass;

            // The stiffness, damping, and maximum force could be assigned during setup if the motor
            // needs to behave similarly for entities of varying masses.  
            // When using a fixed configuration, the grabspring will behave weakly when trying to move extremely heavy objects,
            // while staying very responsive for sufficiently light objects.
            linearMotor.Settings.Servo.SpringSettings.StiffnessConstant = 60000f * Entity.Mass;
            linearMotor.Settings.Servo.SpringSettings.DampingConstant = 900f * Entity.Mass;

            // An unlimited motor will gladly push the entity through other objects.
            // Putting a limit on the strength of the motor will prevent it from doing so.
            linearMotor.Settings.MaximumForce = 10000f * Entity.Mass;

            linearMotor.IsActive = grabSpringMode == GrabSpringMode.Rotation ? false : true;
        }
but it is the same for the original method also.

What is going on?

Re: MotorizedGrabSpring class applies extraneous impulse?!

Posted: Fri Jul 22, 2011 12:14 am
by Norbo
I don't see anything at a glance that applies a linear impulse in the set up. I can't read the number in the video, but the one you report is extremely close to a single frame's change in velocity due to gravity assuming you're using a standard time step and gravity.

Is the object's linear velocity being set to 0 every frame or something, while still being affected by gravity? That would result in one frame's worth of velocity building up each timestep. To avoid this, it should not be affected by gravity, or the object's velocity should be set at an appropriate point in the update (this isn't the easiest approach), or use a linear motor to keep it at a desired location or velocity.

If it's not affected by gravity at the moment, it's possible that it's a hold-over from a previous update that hasn't been zeroed out.

I would recommend just looking at the state of the entity before the setup and after the setup, finding the difference (is the velocity truly different before and after?), and if it exists, walk through line-by-line until the exact cause is found.

Re: MotorizedGrabSpring class applies extraneous impulse?!

Posted: Fri Jul 22, 2011 12:49 am
by Spankenstein
The cause seems to be the following.

If I pause the simulation by setting the Entity.IsActive property to false:

Code: Select all

        private void PauseSimulation()
        {
            for (int i = 0; i < space.Entities.Count; ++i)
            {
                space.Entities[i].IsActive = false;
            }

            for (int i = 0; i < entityAttractors.Count; ++i)
            {
                // Force fields are not allow to wake any object up when the simulation is paused
                entityAttractors[i].GravitationalField.ForceWakeUp = false;
            }
        }
Releasing the entity wakes it up again no matter what:

Code: Select all

        public void Release()
        {
            if (!isEntityDynamic)
            {
                Entity.BecomeKinematic();
            }

            Entity.IsActive = isActive;                                              // false has no effect?
            Entity.IsAffectedByGravity = isAffectedByGravity;

            // Reset the entity's collision rule back to its original state
            Entity.CollisionInformation.CollisionRules.Personal = originalEntityCollisonRule;

            if (game.IsPaused)
            {
                // Remove all forces acting on the entity so it doesn't move in last direction of grabber after unpausing
                Entity.AngularMomentum = Vector3.Zero;
                Entity.AngularVelocity = Vector3.Zero;
                Entity.LinearMomentum = Vector3.Zero;
                Entity.LinearVelocity = Vector3.Zero;
            }

            Entity = null;
        }
EDIT: I could create a separate space for the MotorizedGrabSpring and only update that space instead of relying on IsActive? Is that a better idea?

Re: MotorizedGrabSpring class applies extraneous impulse?!

Posted: Fri Jul 22, 2011 12:54 am
by Norbo
There are multiple operations which cause the object to wake up, even after that IsActive = false line. This is proper behavior for a regular simulation; the state of the simulation has changed in a way that will change the motion states of objects, so the object cannot continue to sleep.

By the way, setting velocity and momentum both to zero is redundant. They differ only in a scaling transform: LinearVelocity = LinearMomentum / Mass, and AngularVelocity = Transform(AngularMomentum, InertiaTensorInverse).

Re: MotorizedGrabSpring class applies extraneous impulse?!

Posted: Fri Jul 22, 2011 12:56 am
by Norbo
EDIT: I could create a separate space for the MotorizedGrabSpring and only update that space instead of relying on IsActive? Is that a better idea?
I'm not clear on how that would operate on an object that exists in another space. There would be a lot of bookkeeping to do there (removing from one space, adding to another, and vice versa, repeatedly). I would avoid that if possible.

For me to provide a suggestion, I would need the specific behaviors and goals desired.

Re: MotorizedGrabSpring class applies extraneous impulse?!

Posted: Fri Jul 22, 2011 1:06 am
by Spankenstein
For me to provide a suggestion, I would need the specific behaviors and goals desired.
- Objects should move freely when the physics isn't paused.
- Objects will not undergo any physics calculations when the physics is paused.
- I would like to be able to move objects around with the MotorizedGrabSpring class no matter what the paused status is.

I can currently do this but I have the (0, -0.16454, 0) momentum problem.
Setting IsActive = false after each Space.Update causes the momentum problem.
Setting IsActive = false before each Space.Update makes the objects unmovable using the MotorizedGrabSpring class.
Bypassing the Space.Update method means I won't be able to move any objects.

Re: MotorizedGrabSpring class applies extraneous impulse?!

Posted: Fri Jul 22, 2011 1:25 am
by Norbo
The first thing I'd recommend is to pin down exactly where the unwanted velocity is coming from. If you find that it is actually expected velocity, perhaps because you want to preserve velocity during pauses, then you can take a snapshot of the velocity states at the time of the pause and re-apply those velocities upon unpause. In the interim, you can modify velocities however you'd like, which would include using whatever motors or other modifications you wanted.

If the velocity isn't actually expected, then finding it will let you address it directly.

By the way, if you just want to pause for the purpose of modifying orientation or position, it may be easier to stop calling the space's Update and enter a sort of 'edit mode' where you can change the position/orientations using widgets. Re-enabling the simulation would involve simply calling space.Update again. You would no longer use motors or physical interactions to modify the positions/orientations of objects.

Also, if you are using buffered/interpolated positions and internal time stepping, you can continue to call space.Update(0) during the pause. The engine will continue to update the buffers (if enabled), but no regular simulation will occur because no time is passing (since you're passing in 0).

Re: MotorizedGrabSpring class applies extraneous impulse?!

Posted: Fri Jul 22, 2011 1:48 am
by Spankenstein
If I call this method before Space.Update each frame then all works as intended:

Code: Select all

        private void PauseSimulation()
        {
            for (int i = 0; i < space.Entities.Count; ++i)
            {
                space.Entities[i].IsActive = false;
            }

            if (gui.GrabSpring.Entity != null)
            {
                gui.GrabSpring.Entity.IsActive = true;
            }

            for (int i = 0; i < entityAttractors.Count; ++i)
            {
                // Force fields are not allow to wake any object up when the simulation is paused
                entityAttractors[i].GravitationalField.ForceWakeUp = false;
            }
        }
That way I can throw objects around, pause, adjust, resume, etc.

There are no more unwanted accumulated forces, so I guess I'm happy. It's not very elegant but I'll implement a method that swaps between a motorized grab spring and position/orientations using widgets, like you suggested, some point soon.

Thanks again for the help.