Which joint class will have this behaviour?

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
Spankenstein
Posts: 249
Joined: Wed Nov 17, 2010 1:49 pm

Which joint class will have this behaviour?

Post by Spankenstein »

I would like to add a joint to a single entity that acts like a thin rod at a fixed point in space (like a pivot point).

The joint (rod) would be placed in the direction of the surface normal of the shape at the point at which it was created. The entity's rotation would then be constrained around the axis that the joint (rod) would represent.

Similar to nailing a picture to a wall but not too tight as to allow the picture to spin around the nail.

Which joint class would provide this behaviour?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Which joint class will have this behaviour?

Post by Norbo »

A RevoluteJoint (which is a RevoluteAngularJoint and BallSocketJoint used together) would do the trick. You can check the joints and constraints documentation for a complete listing of the constraints and some images representing the constraint.

The free axis of the revolute joint would be the surface normal, and the anchor would be somewhere along the nail.

There is no 'SingleEntityRevoluteJoint', so you'll have to use the RevoluteJoint with a null connection parameter. This is equivalent to connecting an entity to the world (or in other words, any unmoving kinematic entity). Note that the order of the connections matters for some constraints. For example, the line in a PointOnLineJoint is attached to connection A. BallSocketJoints and RevoluteAngularJoints should behave fairly similarly when swapped, though.
Spankenstein
Posts: 249
Joined: Wed Nov 17, 2010 1:49 pm

Re: Which joint class will have this behaviour?

Post by Spankenstein »

That is exactly what I am after thank you.

One question though. If I create the joint at a particular point (Anchor) the final RevoluteJoint class connection position is not at the same point (Anchor) even though the entity rotates around it correctly.

Arguments passed into RevoluteJoint

Code: Select all

new RevoluteJoint(o1.Entity, null, rayCastContactPoint, rayCastNormal);
Position is not equal to rayCastContactPoint.

Code: Select all

                game.WireShapeDrawer.DrawLine(
                    j.Joint.AngularJoint.ConnectionB.Position,                        // Incorrect and doesn't match original anchor
                    j.Joint.AngularJoint.ConnectionB.Position + j.Joint.AngularJoint.WorldFreeAxisB,
                    Color.White
                    );
WorldTransform.Translation is also not in the same place.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Which joint class will have this behaviour?

Post by Norbo »

ConnectionB is the other entity involved in the constraint, not the anchor point. Since you passed null in for the constructor, you're getting back the special 'world' entity used by such null-connected constraints. The position of the world entity is always 0,0,0 unless manually changed.

Additionally, the RevoluteAngularJoint has no anchor point. It operates solely on the angular degrees of freedom. The BallSocketJoint has the anchor. However, there is no single anchor point; each connection has its own view of what the anchor point is. The constraint tries to keep those two anchor points as close as possible.

You can get ConnectionA's view of the anchor point by using the joint.ConnectionA.Position + joint.BallSocketJoint.OffsetA. The OffsetA property is the offset from the center of entity A to the anchor in world space, so simply adding it to the position gets 'AnchorA,' so to speak. The same thing can be done with connection B, though you only need to do both if you want to visualize the current constraint separation.
Spankenstein
Posts: 249
Joined: Wed Nov 17, 2010 1:49 pm

Re: Which joint class will have this behaviour?

Post by Spankenstein »

That makes sense. Thanks for the help :)
Spankenstein
Posts: 249
Joined: Wed Nov 17, 2010 1:49 pm

Re: Which joint class will have this behaviour?

Post by Spankenstein »

I'm having problems setting the free axis (presumably because there is some orthogonalization process in effect?).

Code: Select all

                                    Console.WriteLine(string.Format("RayCastNormal {0}", rayCastNormal));

                                    o1.Joint = new RevoluteJoint(o1.Entity, null, rayCastContactPoint, rayCastNormal);

                                    Console.WriteLine(string.Format("FreeAxis {0}", o1.Joint.AngularJoint.WorldFreeAxisA));   // Doesn't match for local either
The ray cast normal is correct and draws correctly but it doesn't match the free axis of the newly created RevoluteJoint. Why is this?

Ouput:

Code: Select all

RayCastNormal {X:7.240677E-06 Y:-0.9590354 Z:0.2832865}
FreeAxis {X:-1.570847E-13 Y:3.873074E-11 Z:-1}
This also causes problems when trying to translate the object that the joint is attached to (the joint should be translated also)

Code: Select all

            set
            {
                // Difference in position
                Vector3 d = value - entity.Position;

                entity.Position = value;

                // If we are allowing object to be translated when it possesses a joint
                if (joint != null)
                {
                    Vector3 jP = joint.AngularJoint.ConnectionA.Position + joint.BallSocketJoint.OffsetA;
                    Vector3 freeAxis = joint.AngularJoint.LocalFreeAxisA;

                    game.Space.Remove(joint);

                    // Anchor must be translated if the entity is moved
                    joint = new RevoluteJoint(entity, null, jP + d, freeAxis);

                    game.Space.Add(joint);
                }

                // As the physics simulation is paused the following needs to be updated for ray cast information to be correct
                // This should be called for each object being moved this frame
                entity.CollisionInformation.UpdateBoundingBox();
            }
The freeAxis will appear to "spin" when translating the parent object (probably changing by 90 degrees each frame?)
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Which joint class will have this behaviour?

Post by Norbo »

The ray cast normal is correct and draws correctly but it doesn't match the free axis of the newly created RevoluteJoint. Why is this?
The RevoluteAngularJoint's WorldFreeAxisA/B property getters erroneously returned the local axis. This was fixed a little while ago in the development version.

If you don't want to update to the development version, there's also the option of just transforming the local axis by the connection's orientation.

Code: Select all

                    Vector3 freeAxis = joint.AngularJoint.LocalFreeAxisA;
...
                    joint = new RevoluteJoint(entity, null, jP + d, freeAxis);
The local axis is being passed into the RevoluteJoint constructor which expects a world space axis.

As a side note:

Code: Select all

                // As the physics simulation is paused the following needs to be updated for ray cast information to be correct
                // This should be called for each object being moved this frame
                entity.CollisionInformation.UpdateBoundingBox();
Updating the bounding box alone isn't technically sufficient; the broad phase acceleration structure must be refit as well. You may already do this somewhere else, though :)
Spankenstein
Posts: 249
Joined: Wed Nov 17, 2010 1:49 pm

Re: Which joint class will have this behaviour?

Post by Spankenstein »

Updating the bounding box alone isn't technically sufficient; the broad phase acceleration structure must be refit as well. You may already do this somewhere else, though
I'm not certain that I am. :oops: Can you please post in code or elaborate on what you are referring to?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Which joint class will have this behaviour?

Post by Norbo »

Ray casts use the broad phase's acceleration structure. Updating the bounding box of an object updates the bounding box of a leaf node in the acceleration structure, but does not update the internal nodes of the acceleration structure. So, if the change is large enough (such as scooting an object to a totally different position), the parent internal nodes' bounding boxes will no longer contain the leaf node. Rays will no longer be able to find the leaf node in the structure.

The solution is to notify the acceleration structures that leaf nodes have changed. You can force an update using the Space.BroadPhase.Update() method. This only needs to be called once in a 'paused' frame after any modifications to bounding boxes occurs (as opposed to after every single individual bounding box change).
Spankenstein
Posts: 249
Joined: Wed Nov 17, 2010 1:49 pm

Re: Which joint class will have this behaviour?

Post by Spankenstein »

That makes sense. We had a conversation regarding BVHs (node trees, etc.) a fair while back. I have accounted for this elsewhere in the code already :)

EDIT:

Downloading the latest development version and using the world axis fixed the problems. Thank you.
Post Reply