Tengo este código para mi aceleración y desaceleración lineal.
var currentSpeed = velocity.translation.z; var decelerationDistance = ((currentSpeed * currentSpeed) / movementSettings.acceleration) * 0.5f; if (distanceFromTarget > decelerationDistance) { velocity.translation = float3(0f, 0f, min(currentSpeed + (movementSettings.acceleration * deltaTime), movementSettings.maxSpeed)); } else { velocity.translation = float3(0f, 0f, max(currentSpeed - (movementSettings.acceleration * deltaTime), 0f)); }Suponiendo que el objeto ya está apuntando al objetivo, esto acelera un objeto hasta su velocidad máxima a su tasa de aceleración, y luego lo desacelera según la tasa de aceleración para que se detenga exactamente en el objetivo.
Me gustaría que se aplicara el mismo comportamiento a la rotación (que es un cuaternión). es decir, suponiendo que el objeto está estacionario, gire suavemente a una rotación objetivo, obedeciendo los límites de aceleración y velocidad máxima de rotación.
Comencé a convertir este código para que funcione en cuaterniones:
private static float Magnitude(Unity.Mathematics.quaternion quat) { return CalculateQuaternionDifference(Unity.Mathematics.quaternion.identity, quat); } private static float CalculateQuaternionDifference(Unity.Mathematics.quaternion a, Unity.Mathematics.quaternion b) { float dotProduct = dot(a, b); return dotProduct > 0.99999f ? 0f : acos(min(abs(dotProduct), 1f)) * 2f; } ... var currentRotSpeed = Magnitude(velocity.rotation); var rotDecelerationDistance = ((currentRotSpeed * currentRotSpeed) / movementSettings.acceleration) * 0.5f; if (distance > rotDecelerationDistance) { velocity.rotation = slerp(Unity.Mathematics.quaternion.identity, mul(rotationDiff, velocity.rotation), movementSettings.acceleration); } else { velocity.rotation = slerp(Unity.Mathematics.quaternion.identity, mul(inverse(rotationDiff), velocity.rotation), movementSettings.acceleration); }Mi pregunta es:
Esto no sigue ningún límite máximo de velocidad de rotación ni se detiene en 0. ¿Cuál es el equivalente de min/max() para un cuaternión?
Algunas de las formas más prácticas de sujetar un cuaternión se pueden hacer fácilmente una vez que se descompone en forma de ángulo/eje, y luego se sujetan como se desee:
float angle; Vector3 axis; velocity.rotation.ToAngleAxis(out angle, out axis);Por lo tanto, si su velocidad de rotación se expresa como un cuaternión y desea restringir su magnitud, puede restringir el ángulo y luego volver a convertirlo en un cuaternión:
// clamp rotational angle to be no more than 90 degrees float maxRotSpeed = 90f; // angle should only ever be non-negative but clamping negative shows intent float clampedAngle = Mathf.Clamp(angle, -maxRotSpeed, maxRotSpeed); Quaternion clampedRot = Quaternion.AngleAxis(clampedAngle, axis);El otro lado de sujetar una rotación sería sujetar el eje de rotación. Para hacer eso, puede sujetar el eje y luego volver a convertir:
// clamp rotational axis to aligned with mainAxis within a certain angle Vector mainAxis = Vector3.up; float maxDeviation = 10f; Vector3 deviationDirection = Vector3.Cross(mainAxis, axis); float deviation = Vector3.SignedAngle(mainAxis, axis, deviationDirection); float clampedDeviation = Mathf.Clamp(deviation, -maxDeviation, maxDeviation); Vector3 clampedAxis = Quaternion.AngleAxis(clampedDeviation, deviationDirection) * mainAxis; Quaternion clampedRot = Quaternion.AngleAxis(angle, clampedAxis);