Using Movers & Rotators and Finding Target Angles

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
cincoutprabu
Posts: 15
Joined: Mon Jan 12, 2015 11:59 pm

Using Movers & Rotators and Finding Target Angles

Post by cincoutprabu »

Hi, I'm animating a MobileMesh model using EntityMover and EntityRotator classes. The objective is the model should rotate and move to a known position. ConstantLinearSpeedCurve and ConstantAngularSpeedCurve are used as input paths to EntityMover and EntityRotator objects respectively. Since I have only the initial (current) and target position & angle of the model, LinearInterpolationCurve3D and QuaternionSlerpCurve objects with only two control points are used as inputs to ConstantLinearSpeedCurve and ConstantAngularSpeedCurve. First control point at time=0 is set to current position & orientation and another control point at time=1 is set to target position and orientation. Both PreLoop and PostLoop are set to Clamp.

With this setup, translation (movement) and rotation animations are working correctly, but not consistently. Can you please help on the following questions.

1) Wondering whether EntityMover and EntityRotator classes are the right choice for the above mentioned objective. Also, the animation is already working with only two control points but should we give few intermediate positions and angles as inputs to position and rotation paths?

2) How to find whether mover and rotator has finished moving and rotating the model to target? Currently, Vector3.Distance and Quaternion.GetRelativeRotation methods are used in PositionUpdated event in order to check whether the model has reached the target location and angle. Not sure whether this is correct and whether this is the only possible solution for this.

3) The mover and rotator seems to work fine only for first time; the consecutive attempts to move/rotate the same model is not working - the model keeps flickering at the same location. It appears like it is trying to move to the 2nd target position from 1st target position but something is trying to hold it back to the 1st target position, so it keeps flickering to and fro at same position (between 1st and 2nd target positions) with quick random animations. A dictionary is maintained to store multiple movers and rotators and each mover/rotator is removed from the dictionary once it has reached the target. The flickering issue happens both with and without the dictionary. Without dictionary, same mover/rotator object is reused (but each time new instance is created). Time step variable (used in Path.Evaluate) is reset to 0 while creating the mover/rotator object. The same issue happens even with or without removing the mover/rotator from space after it has reached the target.

4) Another question (however not related to mover/rotator) is... how to find the target quaternion for a model when it needs to be aligned perpendicular to a line in 3D space. If there are two Vector3 points that might form a straight line in 3D space and the model need to be aligned perpendicular to that straight line, the question is how to find the quaternion to be applied to the model so that the model is parallel to a plane that is perpendicular to the line connecting the two points. I can see the method Quaternion.GetQuaternionBetweenNormalizedVectors and its usage in BEPUphysicsDemos, but some valuable inputs on this problem would be very helpful. ** EDIT ** Since perpendicular is always 90 degree, quaternion can be easily created using Quaternion.CreateFromAxisAngle or Quaternion.CreateFromYawPitchRoll, but still 90 degree is applicable for one axis only if I'm correct and still need to find values for x, z and w components of quaternion if y is set to 90 degree... maybe I'm missing something basic here.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Using Movers & Rotators and Finding Target Angles

Post by Norbo »

1) Wondering whether EntityMover and EntityRotator classes are the right choice for the above mentioned objective. Also, the animation is already working with only two control points but should we give few intermediate positions and angles as inputs to position and rotation paths?
EntityMover and EntityRotator should work for this, yes. Note that they're just simple convenience classes that wrap motors for dynamic entities, or just set velocities directly for kinematic entities.

Adding additional points in between would not help. If all you want is a constant speed interpolation between start and end points, I would recommend ignoring the paths/curves entirely and just directly computing the goal using lerp and slerp, or just configuring motors directly such that they make the objects move towards the goal with the desired speed. (For example, you could change the BaseCorrectiveSpeed to introduce a constant speed on top of the springlike behavior of the motor.)
2) How to find whether mover and rotator has finished moving and rotating the model to target? Currently, Vector3.Distance and Quaternion.GetRelativeRotation methods are used in PositionUpdated event in order to check whether the model has reached the target location and angle. Not sure whether this is correct and whether this is the only possible solution for this.
There's no single correct way to do this; the physics engine itself has no special awareness of something 'reaching' the goal- it's just simulating physics, and what happens happens. It's just a matter of choosing a heuristic that does what you want. If checking the distance does what you want, there's nothing wrong with it.

I would recommend not doing polling work in a physics event when possible, though. They are associated with physical events, after all- even PositionUpdated won't fire under certain circumstances. Unless your work corresponds perfectly to the conditions under which PositionUpdated gets called, avoid it. If you need a callback to fire within a timestep, use one of the stage Starting or Finishing events instead (e.g. Space.EndOfTimeStepUpdateables.Finishing).
3) The mover and rotator seems to work fine only for first time; the consecutive attempts to move/rotate the same model is not working - the model keeps flickering at the same location. It appears like it is trying to move to the 2nd target position from 1st target position but something is trying to hold it back to the 1st target position, so it keeps flickering to and fro at same position (between 1st and 2nd target positions) with quick random animations. A dictionary is maintained to store multiple movers and rotators and each mover/rotator is removed from the dictionary once it has reached the target. The flickering issue happens both with and without the dictionary. Without dictionary, same mover/rotator object is reused (but each time new instance is created). Time step variable (used in Path.Evaluate) is reset to 0 while creating the mover/rotator object. The same issue happens even with or without removing the mover/rotator from space after it has reached the target.
My guess is that there's some goofiness going on with the paths, but I don't have enough information to make a specific prediction. I would recommend getting rid of the paths and just controlling the goals directly. If something weird still happens, it should be easier to figure out.
4) Another question (however not related to mover/rotator) is... how to find the target quaternion for a model when it needs to be aligned perpendicular to a line in 3D space. If there are two Vector3 points that might form a straight line in 3D space and the model need to be aligned perpendicular to that straight line, the question is how to find the quaternion to be applied to the model so that the model is parallel to a plane that is perpendicular to the line connecting the two points. I can see the method Quaternion.GetQuaternionBetweenNormalizedVectors and its usage in BEPUphysicsDemos, but some valuable inputs on this problem would be very helpful.
There are a few undefined degrees of freedom that need to be decided on.
1) There are an infinite number of directions which are perpendicular to a given 3d line.
2) There are an infinite number of directions attached to the model which could be rotated such that they are perpendicular to the line.
3) There are an infinite number of orientations which make the model's attached direction point in the desired perpendicular direction.

One example which constrains these degrees of freedom:
1) Choose one perpendicular by taking the cross product of the line direction and some other arbitrary direction (perhaps world right, if the line isn't aligned with right, with a fallback to world forward if it is).
2) Choose the model's up vector (object.OrientationMatrix.Up) as the direction you wish to align with the perpendicular.
3) Choose the orientation by taking the shortest rotation between the chosen model up vector and the chosen perpendicular by applying Quaternion.GetQuaternionBetweenNormalizedVectors. Apply the rotation to the model.
cincoutprabu
Posts: 15
Joined: Mon Jan 12, 2015 11:59 pm

Re: Using Movers & Rotators and Finding Target Angles

Post by cincoutprabu »

Hi Norbo, thanks really for the definitive answers. However, I'm still having the same flickering issue as mentioned above in #3 even after replacing LinearInterpolationCurve3D + ConstantLinearSpeedCurve combination with SingleEntityLinearMotor. The results are same like the animation works smoothly only for the first time, and then the entity is getting stuck between the consecutive target positions. It appears like something is pulling the entity towards both target positions and hence it is stuck close to the middle of the imaginary path and wanting to goto both 1st and 2nd target positions. One additional thing found out this time is the animation starts working even if motor.Update(dt) is not called from game.Update method. Looks like the motor starts working as soon as it is added to the space. And this could be the reason for the flickering issue as multiple motors are acting on the entity. The results are same even after trying several things like reusing the same motor instance variable, using dictionary and removing the motor from space after it has reached the destination. Motor instance is created like this:

SingleEntityLinearMotor m = new SingleEntityLinearMotor();
m.Entity = mobileMeshEntity;
m.Settings.Mode = MotorMode.Servomechanism;
m.Settings.Servo.BaseCorrectiveSpeed = 5;
m.Settings.Servo.Goal = targetPosition;
m.IsActive = true;
space.Add(m);

If movers and motors doesn't help, then maybe the only option left out will be finding the intermediate positions and rotations using lerp and slerp and manually updating the entity.Position and entity.Orientation by implementing custom timers. However, threading and performance issues are always the fear of using custom timers.

***** EDIT *****

The issue got resolved after fixing a bug while removing the motor from space. Previous logic was trying to remove the motor if the distance goes <= 0, which will never happen. Distance might go close to zero but not less than zero. So changing the distance comparison to < 0.001f fixed the issue. Let me summarize the findings, so that it could be useful for someone:

1) Since multiple motors (SingleEntityLinearMotor) were added to space and never removed, entity is being acted upon by multiple motors and hence there were random movements. After fixing the distance comparison bug, testing again with ConstantLinearSpeedCurve reproduces the flickering issue. Something might be wrong with LinearInterpolationCurve3D + ConstantLinearSpeedCurve combination or the way they were used in the app.

2) No time step update required when SingleEntityLinearMotor is used. Using curves might require time step updates in Update(GameTime) method.
cincoutprabu
Posts: 15
Joined: Mon Jan 12, 2015 11:59 pm

Re: Using Movers & Rotators and Finding Target Angles

Post by cincoutprabu »

1) Choose one perpendicular by taking the cross product of the line direction and some other arbitrary direction (perhaps world right, if the line isn't aligned with right, with a fallback to world forward if it is).
Hi Norbo, can you please clarify how can I choose a correct perpendicular for the model. Looks like the line direction vector can be calculated as (x2-x1, y2-y1, z2-z1), please correct me if I'm wrong. But how can I choose between world right or world forward as stated above. For example, if the 3D line is pointing right, up and outwards (meaning +x, +y, +z directions), it wont be aligned with world right or world forward (assuming the world right means +x axis and word forward means -z axis in right-handed 3d coordinate system). The model in question is a flat/thin cylinder... flat => less height.

Sorry if the questions sound dumb... for pure programmers, bridging the gap with math & physics are always challenging !!!
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Using Movers & Rotators and Finding Target Angles

Post by Norbo »

Using curves might require time step updates in Update(GameTime) method.
That's correct- the curves are not managed by the Space at all and must be independently stepped.
Looks like the line direction vector can be calculated as (x2-x1, y2-y1, z2-z1), please correct me if I'm wrong.
That's correct.
But how can I choose between world right or world forward as stated above. For example, if the 3D line is pointing right, up and outwards (meaning +x, +y, +z directions), it wont be aligned with world right or world forward (assuming the world right means +x axis and word forward means -z axis in right-handed 3d coordinate system).
The cross product between two vectors is a vector perpendicular to both of those vectors. However, if the two vectors are parallel, the cross product will have zero length, which fails to provide a usable direction. In other words, you want the line direction to not be aligned with these other test directions.

In the corner case where the first test direction is aligned, all you have to do is pick another direction and try the cross product again. The second time won't fail, since the line direction can't be parallel with two different directions. (If the line direction itself has zero length, just pick a direction arbitrarily since any direction is 'perpendicular' in that case.)

(Note that this isn't the only way to find a perpendicular vector, just a fairly easy one.)
Post Reply