Во избежание недопонимания, опишу ситуацию. Имеется трансформ. Из него нужно высчитать другой (хотя это может быть один и тот же, но не суть), "ограниченны" трансформ, в соответствии с условиями - ограничение (в градусах) тангажа и крена относительно горизонта. Т.е. нужно ограничивать углы вращения вокруг оси transform.forward(крен) на заданные углы относительно горизонта(выравнен по горизонту - угол равен нулю), и вокруг оси transform.right(тангаж) аналогично.
Сразу оговорюсь. городить матрешку из гейм обжектов мне не подходит.
Задачу можно сформулировать и по другому. Например, как ограничить отклонения "направляющей оси" трансформа(в данном случае это ось transform.up), относительно заданного произвольного направления(в данном случае это ось Vector.up). Таким образом, если поворот относительно осей transform.forward и transform.right, ограничивается на равные углы, допустимое вращения происходят в рамках некого конуса(ось конуса Vector.up в данном случае). Но мне еще и нужна возможность ограничивать углы индивидуально для вращения вокруг transform.forward и transform.right.
Я нагородил своего гавнокода, но может есть что-то более приличное?
Синтаксис:
Используется csharp
public float _angleForward;
public float _angleRight;
void Update()
{
reorientationMove.transform.rotation = ReorientationAngle(reorientationMove.transform, Vector3.up);
// тут проверяю расхожение _angleForward (и _angleRight) с angleForward (и angleRight)
_angleForward = 90f - Vector3.Angle(Vector3.up, reorientationMove.transform.forward);
_angleRight = 90f - Vector3.Angle(Vector3.up, reorientationMove.transform.right);
}
public float angleForward;
public float angleRight;
public float angleForward01;
public float angleRight01;
Quaternion ReorientationAngle(Transform transf, Vector3 normal)
{
// замеряю углы
angleForward = 90f - Vector3.Angle(normal, transf.forward);
angleRight = 90f - Vector3.Angle(normal, transf.right);
//тут типа ограничивающие условия будут, а пока просто проверяю
/*
float _angleForward = Mathf.Clamp(angleForward, -15f, 15f);
float _angleRight = Mathf.Clamp(angleRight, -15f, 15f);
*/
// это для проверки передаю, чтобы сверить корректность углов на входе и на выходе
_angleForward = angleForward;
_angleRight = angleRight;
// первый вариант, работает не корректно
angleForward01 = 1f - (_angleForward / 90f);
angleRight01 = 1f - (_angleRight / 90f);
Vector3 _forward = Vector3.SlerpUnclamped(normal, Vector3.Cross(transf.right, normal), angleForward01);
Vector3 _right = Vector3.SlerpUnclamped(normal, -Vector3.Cross(transf.forward, normal), angleRight01);
Quaternion output = Quaternion.LookRotation(_forward, Vector3.Cross(_forward, _right));
// второй вариант, работает лучше, но все равно с погрешностью
Quaternion output =
Quaternion.AngleAxis(_angleRight, transf.forward) *
Quaternion.AngleAxis(-_angleForward, transf.right) *
Quaternion.AngleAxis(transf.eulerAngles.y, normal);
// третий вариант, тоже плохо
Quaternion output =
Quaternion.AngleAxis(_angleRight, Vector3.Cross(transf.right, normal)) *
Quaternion.AngleAxis(_angleForward, Vector3.Cross(transf.forward, normal)) *
Quaternion.AngleAxis(transf.eulerAngles.y, normal);
return output;
}
public float _angleRight;
void Update()
{
reorientationMove.transform.rotation = ReorientationAngle(reorientationMove.transform, Vector3.up);
// тут проверяю расхожение _angleForward (и _angleRight) с angleForward (и angleRight)
_angleForward = 90f - Vector3.Angle(Vector3.up, reorientationMove.transform.forward);
_angleRight = 90f - Vector3.Angle(Vector3.up, reorientationMove.transform.right);
}
public float angleForward;
public float angleRight;
public float angleForward01;
public float angleRight01;
Quaternion ReorientationAngle(Transform transf, Vector3 normal)
{
// замеряю углы
angleForward = 90f - Vector3.Angle(normal, transf.forward);
angleRight = 90f - Vector3.Angle(normal, transf.right);
//тут типа ограничивающие условия будут, а пока просто проверяю
/*
float _angleForward = Mathf.Clamp(angleForward, -15f, 15f);
float _angleRight = Mathf.Clamp(angleRight, -15f, 15f);
*/
// это для проверки передаю, чтобы сверить корректность углов на входе и на выходе
_angleForward = angleForward;
_angleRight = angleRight;
// первый вариант, работает не корректно
angleForward01 = 1f - (_angleForward / 90f);
angleRight01 = 1f - (_angleRight / 90f);
Vector3 _forward = Vector3.SlerpUnclamped(normal, Vector3.Cross(transf.right, normal), angleForward01);
Vector3 _right = Vector3.SlerpUnclamped(normal, -Vector3.Cross(transf.forward, normal), angleRight01);
Quaternion output = Quaternion.LookRotation(_forward, Vector3.Cross(_forward, _right));
// второй вариант, работает лучше, но все равно с погрешностью
Quaternion output =
Quaternion.AngleAxis(_angleRight, transf.forward) *
Quaternion.AngleAxis(-_angleForward, transf.right) *
Quaternion.AngleAxis(transf.eulerAngles.y, normal);
// третий вариант, тоже плохо
Quaternion output =
Quaternion.AngleAxis(_angleRight, Vector3.Cross(transf.right, normal)) *
Quaternion.AngleAxis(_angleForward, Vector3.Cross(transf.forward, normal)) *
Quaternion.AngleAxis(transf.eulerAngles.y, normal);
return output;
}