using UnityEngine; | |
public static class ConfigurableJointExtensions { | |
/// <summary> | |
/// Sets a joint's targetRotation to match a given local rotation. | |
/// The joint transform's local rotation must be cached on Start and passed into this method. | |
/// </summary> | |
public static void SetTargetRotationLocal (this ConfigurableJoint joint, Quaternion targetLocalRotation, Quaternion startLocalRotation) | |
{ | |
if (joint.configuredInWorldSpace) { | |
Debug.LogError ("SetTargetRotationLocal should not be used with joints that are configured in world space. For world space joints, use SetTargetRotation.", joint); | |
} | |
SetTargetRotationInternal (joint, targetLocalRotation, startLocalRotation, Space.Self); | |
} | |
/// <summary> | |
/// Sets a joint's targetRotation to match a given world rotation. | |
/// The joint transform's world rotation must be cached on Start and passed into this method. | |
/// </summary> | |
public static void SetTargetRotation (this ConfigurableJoint joint, Quaternion targetWorldRotation, Quaternion startWorldRotation) | |
{ | |
if (!joint.configuredInWorldSpace) { | |
Debug.LogError ("SetTargetRotation must be used with joints that are configured in world space. For local space joints, use SetTargetRotationLocal.", joint); | |
} | |
SetTargetRotationInternal (joint, targetWorldRotation, startWorldRotation, Space.World); | |
} | |
static void SetTargetRotationInternal (ConfigurableJoint joint, Quaternion targetRotation, Quaternion startRotation, Space space) | |
{ | |
// Calculate the rotation expressed by the joint's axis and secondary axis | |
var right = joint.axis; | |
var forward = Vector3.Cross (joint.axis, joint.secondaryAxis).normalized; | |
var up = Vector3.Cross (forward, right).normalized; | |
Quaternion worldToJointSpace = Quaternion.LookRotation (forward, up); | |
// Transform into world space | |
Quaternion resultRotation = Quaternion.Inverse (worldToJointSpace); | |
// Counter-rotate and apply the new local rotation. | |
// Joint space is the inverse of world space, so we need to invert our value | |
if (space == Space.World) { | |
resultRotation *= startRotation * Quaternion.Inverse (targetRotation); | |
} else { | |
resultRotation *= Quaternion.Inverse (targetRotation) * startRotation; | |
} | |
// Transform back into joint space | |
resultRotation *= worldToJointSpace; | |
// Set target rotation to our newly calculated rotation | |
joint.targetRotation = resultRotation; | |
} | |
} |
Nevermind, i was using connectedBody rotation, instead of direct parent. This works perfectly fine for setting world target on local joints:
public static void SetTargetRotation(this ConfigurableJoint cj, Quaternion startRot, Quaternion target, Space space)
{
Vector3 right = cj.axis;
Vector3 forward = Vector3.Cross(cj.axis, cj.secondaryAxis).normalized;
Vector3 up = Vector3.Cross(forward, right).normalized;
Quaternion localToJointSpace = Quaternion.LookRotation(forward, up);
if (space == Space.World)
{
Quaternion worldToLocal = Quaternion.Inverse(cj.transform.parent.rotation);
target = worldToLocal * target;
}
cj.targetRotation = Quaternion.Inverse(localToJointSpace) * Quaternion.Inverse(target) * startRot * localToJointSpace;
}
Your script works fine for performing a single rotation, but i always have trouble implementing it in FixedUpdate(). I get the error:
"Skipped updating the transform of this Rigidbody because its components are infinite. Could you have applied infinite forces, acceleration or set huge velocity?"
void Awake() {
Quaternion startRotation = arm.transform.rotation;
joint = arm.GetComponent<ConfigurableJoint>();
}
void FixedUpdate() {
joint.SetTargetRotation(Quaternion.Euler(0, 0.01f, 0), startRotation);
}
I just want to rotate the joint consistently along its joints y-axis. Im currently getting headaches over the simplest tasks using ConfigurableJoints :))
Thanks for any help in advance!
Nevermind, was my mistake. The problem was that i redefined "startRotation" to be a quaternion in the Awake() call, so always go the default Quaternion value for "startRotation" in FixedUpdate()
That's so coool!!!!
Can I request that you add an additional method here to return the Local/World space rotation of the joint's targetRotation? I'm trying to Slerp a joint's targetRotation through to a new orientation but I need to know it's current orientation first.
public static Quaternion GetTargetRotation(ConfigurableJoint joint, Quaternion startRotation, Space space) { ... }
Thanks
Hey @mstevenson, Quick question with the "StartRotation" quaternion. Is this the local rotation (Global, if not a child to anything) of the transform that the joint is created on at the time of joint-creation? Is this ever updated if connected bodies, anchors, etc change?
So is there no way of setting the world-space target on local-configured joint? Ive tried rotating the target to inverse parent rotation, but it doesnt seem to be correct. Any ideas?