你好!我正在尝试重建Toribash的核心机制,其中您可以控制单独的肌肉以保持、放松、伸展或收缩。我的当前实现已经基本完成了 - 伸展设置目标旋转为关节的最大限制,收缩设置为最小限制。问题在于当限制之间的差异大于180°时,如果它处于最小限制,并且您设置目标为最大限制,它会尝试取最短路径,即使该旋转是向限制的方向。 我希望有一个简单的方法可以强制旋转的方向为正欧拉旋转(用于伸展)和负欧拉旋转(用于收缩),但我尝试了无数种方法,似乎都没有解决问题。我的四元数理解非常模糊。 是否有办法用可配置的关节来解决这个问题,还是我完全走错了路?谢谢! p.s. 我从 [这个 gist](https://gist.github.com/mstevenson/4958837) 中适应了扩展方法,希望正确。
using NaughtyAttributes;
using UnityEngine;
public class MuscleDriver : MonoBehaviour
{
private ConfigurableJoint configurableJoint;
private Quaternion initialRotation;
// Start 是一个 MonoBehaviour 的方法,会在 Update 方法第一次被调用之前被调用。
void Start()
{
configurableJoint = GetComponent<ConfigurableJoint>();
initialRotation = transform.localRotation;
Hold();
}
void ChangeState(MuscleDriverMode mode)
{
// Helper 来方便地切换驱动力度
JointDrive activeDrive = new JointDrive
{
positionSpring = 1000f,
positionDamper = 50f,
maximumForce = float.MaxValue
};
JointDrive relaxedDrive = new JointDrive
{
positionSpring = 0f,
positionDamper = 0f,
maximumForce = 0f
};
configurableJoint.slerpDrive = activeDrive;
switch (mode)
{
case MuscleDriverMode.Extend:
float high = configurableJoint.highAngularXLimit.limit; // 高限制(例如 112 度周围 X)
Quaternion extendRot = Quaternion.Euler(high, 0, 0);
configurableJoint.SetTargetRotationLocal(extendRot, initialRotation);
break;
case MuscleDriverMode.Contract:
float low = configurableJoint.lowAngularXLimit.limit; // 低限制(例如 -102 度周围 X)
Quaternion contractRot = Quaternion.Euler(low, 0, 0);
configurableJoint.SetTargetRotationLocal(contractRot, initialRotation);
break;
case MuscleDriverMode.Hold:
// 锁定到当前本地旋转
configurableJoint.SetTargetRotationLocal(transform.localRotation, initialRotation);
break;
case MuscleDriverMode.Relax:
configurableJoint.slerpDrive = relaxedDrive;
break;
}
}
}
public static class JointExtensions
{
/// <summary>
/// 设置一个关节的目标旋转使用一个本地空间旋转。
/// </summary>
public static void SetTargetRotationLocal(this ConfigurableJoint joint, Quaternion targetLocalRotation, Quaternion startLocalRotation)
{
// 计算相对于开始本地旋转的旋转
Quaternion internalRotation = Quaternion.Inverse(targetLocalRotation) * startLocalRotation;
// 转换到关节的自定义坐标系统
Vector3 right = joint.axis;
Vector3 forward = Vector3.Cross(joint.axis, joint.secondaryAxis);
Vector3 up = Vector3.Cross(forward, right);
Quaternion worldToJointSpace = Quaternion.LookRotation(forward, up);
// 应用关节空间转换
joint.targetRotation = Quaternion.Inverse(worldToJointSpace) * internalRotation * worldToJointSpace;
}
}
评论 (0)