Which joint class will have this behaviour?
-
- Posts: 249
- Joined: Wed Nov 17, 2010 1:49 pm
Which joint class will have this behaviour?
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?
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?
Re: Which joint class will have this behaviour?
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.
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.
-
- Posts: 249
- Joined: Wed Nov 17, 2010 1:49 pm
Re: Which joint class will have this behaviour?
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
Position is not equal to rayCastContactPoint.
WorldTransform.Translation is also not in the same place.
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);
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
);
Re: Which joint class will have this behaviour?
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.
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.
-
- Posts: 249
- Joined: Wed Nov 17, 2010 1:49 pm
Re: Which joint class will have this behaviour?
That makes sense. Thanks for the help
-
- Posts: 249
- Joined: Wed Nov 17, 2010 1:49 pm
Re: Which joint class will have this behaviour?
I'm having problems setting the free axis (presumably because there is some orthogonalization process in effect?).
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:
This also causes problems when trying to translate the object that the joint is attached to (the joint should be translated also)
The freeAxis will appear to "spin" when translating the parent object (probably changing by 90 degrees each frame?)
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
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}
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();
}
Re: Which joint class will have this behaviour?
The RevoluteAngularJoint's WorldFreeAxisA/B property getters erroneously returned the local axis. This was fixed a little while ago in the development version.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?
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);
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();
-
- Posts: 249
- Joined: Wed Nov 17, 2010 1:49 pm
Re: Which joint class will have this behaviour?
I'm not certain that I am. Can you please post in code or elaborate on what you are referring to?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
Re: Which joint class will have this behaviour?
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).
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).
-
- Posts: 249
- Joined: Wed Nov 17, 2010 1:49 pm
Re: Which joint class will have this behaviour?
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.
EDIT:
Downloading the latest development version and using the world axis fixed the problems. Thank you.