Vector3 position increases unexpectdly

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
jaja1
Posts: 43
Joined: Sat Nov 15, 2014 3:27 am

Vector3 position increases unexpectdly

Post by jaja1 »

I am creating an enemy ai script for my game. In that script I am lerping between a collider's old position and a new position I have defined. The defined position is fine (I checked using a debugger), but the new position of the colliders goes whack. Here is the code:

Code: Select all

mType.compactCollider.Position = mType.extendedCollider.Position =
            Vector3.Lerp(mType.compactCollider.Position, new_pos, mType.walk_speed);
Note: mType.walk_speed is a single precision floating point decimal and is defined as 5f in this case.

The values of say the x position go from 52 to 318 to 1142 to 4658 etc.

The Lerp is also called by a timer every 'x' amount of seconds. The time varies randomly and so I'm not sure if the lerp actually completes before the timer event is called again to determine the next waypoint for the monster to lerp to. I considered using "await" at the Lerp so that the line is completed before the next line is executed, but I am still some hours away from VS 2013 being downloaded. So until then could this be the source of the position changing so erratically or something else?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Vector3 position increases unexpectdly

Post by Norbo »

Vector3.Lerp is a + (b-a)*t, so passing in a fixed value of 5 as the interpolation parameter gives a + 5 * (b-a), causing massive overshoot beyond the endpoint.

Further, setting the Position of an Entity is equivalent to teleporting the entity. Dynamic collisions will not respond properly to teleporting entities because there is no velocity to respond to. If you want collision to work properly, control the entity by setting its velocity, applying impulses, or using constraints instead. For example, try setting linear velocity to Direction * mType.walk_speed, where Direction is the normalized direction from the current position to the target position.
jaja1
Posts: 43
Joined: Sat Nov 15, 2014 3:27 am

Re: Vector3 position increases unexpectdly

Post by jaja1 »

Thanks Norbo! I got the monster to update his position properly but now I'm having some issues with the rotation. I wasn't sure exactly how to determine the direction an entity was facing so I assumed that the entity was initiated with its Orientation property as Quaternion.Identity (which I thought was a reasonable assumption, I may be wrong). From there I updated the Orientation based on the current Vector3 position of the entity and the position I want it to be in. For some reason though I'm not getting the correct position in my client. In fact, the monster does not appear to change its rotation at all. Here is my code:

Code: Select all

Vector3 new_pos = new Vector3(mType.waypoints_x[mType.next_waypoint_index], mType.waypoints_y[mType.next_waypoint_index],
                                    mType.waypoints_z[mType.next_waypoint_index]);

            Vector3 direction = new_pos - mType.compactCollider.Position;
            direction.Normalize();

            Quaternion new_dir = new Quaternion();
            Vector3 temp1 = mType.extendedCollider.Position;
            Vector3 temp2 = new_pos;
            temp1.Normalize();
            temp2.Normalize();
            Quaternion.GetQuaternionBetweenNormalizedVectors(ref temp1, ref temp2, out new_dir);

            mType.extendedCollider.Orientation = mType.extendedCollider.Orientation * new_dir;

            mType.compactCollider.LinearVelocity = direction * mType.walk_speed;
            mType.extendedCollider.LinearVelocity = direction * mType.walk_speed;

            while ((mType.compactCollider.Position - new_pos).Length() >= 0)
            {
                if ((mType.compactCollider.Position - new_pos).Length() < 0.1f)
                {
                    mType.compactCollider.LinearVelocity = Vector3.Zero;
                    mType.extendedCollider.LinearVelocity = Vector3.Zero;
                    break;
                }
            }
I know I did not use the angular velocity property. This was a temporary solution because unlike the position update, I was unable to come up with a way to actually stop the entity from rotating when I had the desired orientation.

This is what it looks like on the client side. Note: array indices 3 - 6 are the X, Y, Z and W components of the entity's current Orientation from the server.

Code: Select all

 PHashtable hash = (PHashtable)operationResponse.Parameters[37];

                    foreach (string name in hash.Keys)
                    {
                        GameObject monster = GameObject.Find(name);
                        float[] f = (float[])hash[name];

                        Quaternion new_dir = new Quaternion(f[3], f[4], f[5], f[6]);
                        monster.transform.rotation = new_dir;
                    
                        Vector3 new_pos = new Vector3(f[0], f[1], f[2]);
                        monster.transform.position = Vector3.Lerp(monster.transform.position, new_pos, 10f * Time.deltaTime);
                    }
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Vector3 position increases unexpectdly

Post by Norbo »

I assumed that the entity was initiated with its Orientation property as Quaternion.Identity (which I thought was a reasonable assumption, I may be wrong).
Orientation does indeed default to Identity.

Code: Select all

            Quaternion new_dir = new Quaternion();
            Vector3 temp1 = mType.extendedCollider.Position;
            Vector3 temp2 = new_pos;
            temp1.Normalize();
            temp2.Normalize();
            Quaternion.GetQuaternionBetweenNormalizedVectors(ref temp1, ref temp2, out new_dir);

            mType.extendedCollider.Orientation = mType.extendedCollider.Orientation * new_dir;
GetQuaternionBetweenNormalizedVectors gets the rotation that would make the first direction parallel with the second direction if the first direction were transformed by the resulting orientation. Doing this on the directions from the origin to the positions isn't meaningful.

If you wanted to get the shortest rotation that makes the entity's forward direction point at the target position, you could use the entity.OrientationMatrix.Forward and normalize(newPosition - oldPosition) as the directions.
I know I did not use the angular velocity property. This was a temporary solution because unlike the position update, I was unable to come up with a way to actually stop the entity from rotating when I had the desired orientation.
You may want to use the EntityMover and EntityRotator. They compute the velocities required to reach a goal position/orientation for you (either directly for kinematics or using motors for dynamics). You could also check their source to see how to handle that sort of thing.
jaja1
Posts: 43
Joined: Sat Nov 15, 2014 3:27 am

Re: Vector3 position increases unexpectdly

Post by jaja1 »

Thanks again Norbo!
I will try what you said and edit this post when I find success.

Just want to point out one thing. You may have forgotten to edit the description for the EntityMover. Its the same as EntityRotator :)
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Vector3 position increases unexpectdly

Post by Norbo »

Just want to point out one thing. You may have forgotten to edit the description for the EntityMover. Its the same as EntityRotator :)
Noted! Thanks for the report.
jaja1
Posts: 43
Joined: Sat Nov 15, 2014 3:27 am

Re: Vector3 position increases unexpectdly

Post by jaja1 »

No problem Norbo :)

I think I may have been going about this all wrong. I am thinking of this as plain code with no dynamics involved. This is physics :lol:
I may be wrong, but using the EntityRotator yields the same results as before. I still find myself having to "stop" the entity using a loop. Same goes for EntityMover. But then it hit me....friction/air resistance?! Would I have to define this additional force to get the object to stop moving? Its the only logical explanation I could come up with. Once again here is my code:

Code: Select all

 Vector3 new_pos = new Vector3(mType.waypoints_x[mType.next_waypoint_index], mType.waypoints_y[mType.next_waypoint_index],
                                    mType.waypoints_z[mType.next_waypoint_index]);

            Vector3 direction = new_pos - mType.compactCollider.Position;
            direction.Normalize();

            Quaternion rot = new Quaternion();
            Vector3 forward = mType.extendedCollider.OrientationMatrix.Forward;
            forward.Normalize();
            Quaternion.GetQuaternionBetweenNormalizedVectors(ref forward, ref direction, out rot);

            mType.extendedCollider.AngularVelocity = 
            EntityRotator.GetAngularVelocity(mType.extendedCollider.Orientation, mType.extendedCollider.Orientation * rot, 0.05f);

            while (mType.extendedCollider.AngularVelocity.Length() >= 0.001f)
            {
                if (mType.extendedCollider.AngularVelocity.Length() <= 0.001f)
                {
                    mType.extendedCollider.AngularVelocity = Vector3.Zero;
                    break;
                }
            }
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Vector3 position increases unexpectdly

Post by Norbo »

You can create instances of EntityMover/Rotator and add them to the space. They change the velocities of the given entity to achieve the specified goal, so you don't have to specify the velocities yourself. It will stop at the goal.
jaja1
Posts: 43
Joined: Sat Nov 15, 2014 3:27 am

Re: Vector3 position increases unexpectdly

Post by jaja1 »

I managed to implement the movers and rotators, however I a still having some issues with the rotation. Sometimes things work (rarely), and other times I end up getting "NaN" values in my quaternion rotation being sent back to the client. I simply send the x, y, z and w components of the extendedCollider.Orientation back to the client after updating the monster's position server side, so I think the issue is on the server itself. I just to confirm that. (Note: I am only worrying about the rotation of the extended collider because it is offset from its localPosition. The compact Collider is centered along the Up axis).

Here is how I initialize the monster's colliders/motors/movers/rotators and add them to the space:

Code: Select all

Vector3 init_pos = new Vector3(mType.current_pos[0], mType.current_pos[1], mType.current_pos[2]);

            Cylinder compactCollider = new Cylinder(init_pos, 1.12f, 0.12f);
            Cylinder extendedCollider = new Cylinder(init_pos, 1f, 1f);

            //offset local positions
            compactCollider.CollisionInformation.LocalPosition = new Vector3(0, 0.56f, 0);

            //motors
            SingleEntityLinearMotor compactLinearMotor = new SingleEntityLinearMotor();
            SingleEntityLinearMotor extendedLinearMotor = new SingleEntityLinearMotor();
            SingleEntityAngularMotor extendedAngularMotor = new SingleEntityAngularMotor();

            //set entity movers/rotators
            EntityMover compactEmover = new EntityMover(compactCollider, compactLinearMotor);
            EntityMover extendedEmover = new EntityMover(extendedCollider, extendedLinearMotor);
            EntityRotator extendedErotator = new EntityRotator(extendedCollider, extendedAngularMotor);

            //tags
            compactCollider.Tag = "[MONSTER] [body] " + mType.monsterInstance; //the [MONSTER] string is a tag
            extendedCollider.Tag = "[MONSTER] [weapon] " + mType.monsterInstance;//used for collision detection

            //enable collision on colliders
            compactCollider.CollisionInformation.CollisionRules.Personal = BEPUphysics.CollisionRuleManagement.CollisionRule.Normal;
            extendedCollider.CollisionInformation.CollisionRules.Personal = BEPUphysics.CollisionRuleManagement.CollisionRule.Normal;

            //enable motors
            extendedErotator.AngularMotor.IsActive = true;
            extendedEmover.LinearMotor.IsActive = true;
            compactEmover.LinearMotor.IsActive = true;

            mType.compactCollider = compactCollider;
            mType.extendedCollider = extendedCollider;
            mType.compactEmover = compactEmover;
            mType.extendedEmover = extendedEmover;
            mType.extendedErotator = extendedErotator;

            if (mType.map == 0.00f)
            {
                VandelliaPhysicsMap.Add(compactCollider);
                VandelliaPhysicsMap.Add(compactEmover);

                VandelliaPhysicsMap.Add(extendedCollider);
                VandelliaPhysicsMap.Add(extendedEmover);
                VandelliaPhysicsMap.Add(extendedErotator);
            }
This is how I update the monster;s position now:

Code: Select all

Vector3 new_pos = new Vector3(mType.waypoints_x[mType.next_waypoint_index], mType.waypoints_y[mType.next_waypoint_index],
                                    mType.waypoints_z[mType.next_waypoint_index]);

            Vector3 direction = new_pos - mType.compactCollider.Position;
            direction.Normalize();

            Quaternion rot = new Quaternion();
            Vector3 forward = mType.extendedCollider.OrientationMatrix.Forward;
            forward.Normalize();
            Quaternion.GetQuaternionBetweenNormalizedVectors(ref forward, ref direction, out rot);

            Quaternion rotTo = mType.extendedCollider.Orientation * rot;
            mType.extendedErotator.TargetOrientation = rotTo;

            mType.compactEmover.TargetPosition = new_pos;
            mType.extendedEmover.TargetPosition = new_pos;
I also would like to know if there is another method for "waiting" for the monster to rotate and move before moving to the next line of code without using timers or anything too complex (this code is run quite frequently for many...many entities).

Let me know if there is anything I am still not quite getting right. If you can point me to a specific example in the docs as well that would be most appreciated. I can't seem to find anything on Movers and/or Rotators as yet.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Vector3 position increases unexpectdly

Post by Norbo »

Some notes:
1) Make sure all divisions capable of dividing by zero at runtime are protected against. For example, right now, the direction.Normalize will produce a NaN-filled vector if mType.compactCollider.Position and new_pos are the same. This could be what you're seeing.
2) The orientation matrix's forward vector is already unit length thanks to the properties of a rotation matrix, so normalizing it has no effect.
3) The cylinders are kinematic since they were created without specifying a mass. The motors won't be used, since kinematic objects have effectively infinite mass and can't be moved by forces. The EntityMover/EntityRotator will control the velocities directly instead.
4) Even if the objects were dynamic, you don't have to create your own motors to pass into the constructors. That constructor overload is simply there if you already have a motor sitting around available for use. I would recommend just using the simpler entity-only constructor of the EntityMover/EntityRotator. This would avoid the other boilerplate, like setting IsActive to true.
I also would like to know if there is another method for "waiting" for the monster to rotate and move before moving to the next line of code without using timers or anything too complex (this code is run quite frequently for many...many entities).
There are a few options here, but none of them have any engine-level convenience functions:
1) If a completely arbitrary dynamic simulation is involved, the only way to know when a goal is met is by polling, because there is no closed form expression for when the simulation will finish in general. Polling is not as horrible as it might seem, even if you have 1000 entities and you're polling every frame. Consider that the engine is doing orders of magnitude more work on every single individual entity. Provided that the polling process isn't abnormal/crazy expensive, it will likely be irrelevant to the running time.
2) If the simulation is constrained in some way, those constraints might make it possible to predict particular time of completion. For example, if you want to know when the EntityMover is going to succeed in reaching its goal when operating on a kinematic entity, the answer is always 'at the end of the next update' because it sets the velocity to exactly the values required to hit the goal, and no dynamic interference will stop it from reaching the goal because it has effectively infinite mass.
If you can point me to a specific example in the docs as well that would be most appreciated. I can't seem to find anything on Movers and/or Rotators as yet.
EntityMovers and EntityRotators don't have any dedicated documentation since they're a very thin convenience layer around just setting velocities or using motors. There are some examples of their usage in the BEPUphysicsDemos, though. For example, the In the CharacterPlayergroundDemo, they move the platforms around, and in the PathFollowingDemo, they move the... flying block thing.
jaja1
Posts: 43
Joined: Sat Nov 15, 2014 3:27 am

Re: Vector3 position increases unexpectdly

Post by jaja1 »

Thanks for the notes Norbo. Made some major changes to the code. I am just faced with one issue now though, will the EntityMover.GetLinearVelocity move the entity to the correct position as the EntityMover.TargetPosition does? With targetposition I am able to move the entity to the right position just fine but I need to do so in a certain amount of time. By setting the targetposition it almost has the same visual effect as "teleporting" the entity. If GetLinearVelocity is supposed to stop the entity at the specified position it apparently does not in my code.

Code: Select all

mType.compactCollider.LinearVelocity = EntityMover.GetLinearVelocity(oldpos, new_pos, 4f);
                mType.extendedCollider.LinearVelocity = EntityMover.GetLinearVelocity(oldpos, new_pos, 4f);
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Vector3 position increases unexpectdly

Post by Norbo »

GetLinearVelocity just computes the velocity needed to reach the goal in the specified time frame. It doesn't apply any persistent monitoring that would stop it later. You can check the source code for it- it's a very simple function. The EntityMover stops it because it's changing the linear velocity of the entity every single time step, so once it's at the goal, the monitored entity's velocity gets set to zero.

If you want to use an EntityMover instance to move an object gradually, change its TargetPosition gradually.
jaja1
Posts: 43
Joined: Sat Nov 15, 2014 3:27 am

Re: Vector3 position increases unexpectdly

Post by jaja1 »

Thanks again Norbo. I managed to implement a better system using paths for the enemy ai. A new problem has sprung up so I will create a new thread.
Post Reply