Skip to content

Instantly share code, notes, and snippets.

@mstevenson
Last active April 22, 2025 13:06
Show Gist options
  • Save mstevenson/4958837 to your computer and use it in GitHub Desktop.
Save mstevenson/4958837 to your computer and use it in GitHub Desktop.
Unity extension methods for computing a ConfigurableJoint.TargetRotation value from a given local or world rotation.
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;
}
}
@BatmanVN
Copy link

Pls help me.
public class TheropodJointAngleCopy : MonoBehaviour
{
[Header("Left Foot Transform")]
public Transform tibiaLRef;

public Transform fibulaLRef;

public Transform footLRef;

public Transform footL2Ref;

[Header("Right Foot Transform")]
public Transform tibiaRRef;

public Transform fibulaRRef;

public Transform footRRef;

public Transform footR2Ref;

[Header("Arm Transform")]
public Transform upperArmLRef;

public Transform lowerArmLRef;

public Transform upperArmRRef;

public Transform lowerArmRRef;

[Header("Head & Neck Transform")]
public Transform neckRef;

public Transform neck2Ref;

public Transform headRef;

public Transform jawRef;

[Header("Spine Transform")]
public Transform frontSpineRef;

[Header("Tail Transform")]
public Transform tail1Ref;

public Transform tail2Ref;

public Transform tail3Ref;

public Transform tail4Ref;

public Transform tail5Ref;

[Header("Left Foot Joint")]
public ConfigurableJoint tibiaL;

public ConfigurableJoint fibulaL;

public ConfigurableJoint footL;

public ConfigurableJoint footL2;

[Header("Right Foot Joint")]
public ConfigurableJoint tibiaR;

public ConfigurableJoint fibulaR;

public ConfigurableJoint footR;

public ConfigurableJoint footR2;

[Header("Arm Joint")]
public ConfigurableJoint upperArmL;

public ConfigurableJoint lowerArmL;

public ConfigurableJoint upperArmR;

public ConfigurableJoint lowerArmR;

[Header("Head & Neck Joint")]
public ConfigurableJoint neck;

public ConfigurableJoint neck2;

public ConfigurableJoint head;

public ConfigurableJoint jaw;

[Header("Spine Joint")]
public ConfigurableJoint frontSpine;

[Header("Tails Joint")]
public ConfigurableJoint tail1;

public ConfigurableJoint tail2;

public ConfigurableJoint tail3;

public ConfigurableJoint tail4;

public ConfigurableJoint tail5;

public bool old;
private Dictionary<ConfigurableJoint, Quaternion> startRotations = new Dictionary<ConfigurableJoint, Quaternion>();

private void Awake()
{
    // Lưu lại startRotation của từng joint
    SaveStartRotation(tibiaL);
    SaveStartRotation(fibulaL);
    SaveStartRotation(footL);
    SaveStartRotation(footL2);

    SaveStartRotation(tibiaR);
    SaveStartRotation(fibulaR);
    SaveStartRotation(footR);
    SaveStartRotation(footR2);

    SaveStartRotation(upperArmL);
    SaveStartRotation(lowerArmL);
    SaveStartRotation(upperArmR);
    SaveStartRotation(lowerArmR);

    SaveStartRotation(neck);
    SaveStartRotation(neck2);
    SaveStartRotation(head);
    SaveStartRotation(jaw);

    SaveStartRotation(frontSpine);
    SaveStartRotation(tail1);
    SaveStartRotation(tail2);
    SaveStartRotation(tail3);
    SaveStartRotation(tail4);
    SaveStartRotation(tail5);
}
private void SaveStartRotation(ConfigurableJoint joint)
{
    if (joint != null)
    {
        startRotations[joint] = joint.transform.localRotation;
    }
}


private void FixedUpdate()
{
    ApplyAllJointRotations();

}
private void ApplyAllJointRotations()
{
    ApplyJointRotation(tibiaL, tibiaLRef);
    ApplyJointRotation(fibulaL, fibulaLRef);
    ApplyJointRotation(footL, footLRef);
    ApplyJointRotation(footL2, footL2Ref);

    ApplyJointRotation(tibiaR, tibiaRRef);
    ApplyJointRotation(fibulaR, fibulaRRef);
    ApplyJointRotation(footR, footRRef);
    ApplyJointRotation(footR2, footR2Ref);

    ApplyJointRotation(upperArmL, upperArmLRef);
    ApplyJointRotation(lowerArmL, lowerArmLRef);
    ApplyJointRotation(upperArmR, upperArmRRef);
    ApplyJointRotation(lowerArmR, lowerArmRRef);

    ApplyJointRotation(neck, neckRef);
    ApplyJointRotation(neck2, neck2Ref);
    ApplyJointRotation(head, headRef);
    ApplyJointRotation(jaw, jawRef);

    ApplyJointRotation(frontSpine, frontSpineRef);
    ApplyJointRotation(tail1, tail1Ref);
    ApplyJointRotation(tail2, tail2Ref);
    ApplyJointRotation(tail3, tail3Ref);
    ApplyJointRotation(tail4, tail4Ref);
    ApplyJointRotation(tail5, tail5Ref);
}
public void ApplyJointRotation(ConfigurableJoint joint, Transform refTransform)
{
    if (joint == null || refTransform == null || !startRotations.ContainsKey(joint)) return;

    joint.targetRotation = Quaternion.LookRotation(refTransform.localPosition);
    Quaternion targetRotation = Quaternion.Inverse(refTransform.localRotation);

    joint.targetRotation = targetRotation;


    //Lấy góc quay mong muốn dựa trên Transform tham chiếu
    //Quaternion targetRotation = refTransform.localRotation;

    // Lấy góc quay ban đầu của khớp
    //Quaternion startRotation = startRotations[joint];
    //Quaternion targetRotation = /*Quaternion.Inverse(startRotation) **/ refTransform.localRotation;
    //joint.SetTargetRotationLocal(targetRotation, startRotation); // if i set like this my TRex will wrong

}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment