Отлично, так что я занимался этим несколько дней, и из-за того, насколько он замедляет проект, я принял трудное решение просить Интернет.
Я работаю над основанной на физике игрой в гольф в Unity и работаю над реализацией эффекта магнуса. Это мой расчет тангенциальной силы на основе крутящего момента:
void FixedUpdate()
{
float _BallRadius = .0427f;
float _halfmass = Mathf.Sqrt(_BallRadius*.5f );
float _vv = new Vector3(GetComponent<Rigidbody>().velocity.x, 0,
GetComponent<Rigidbody>().velocity.z).magnitude;
//MAGNUS FORMULA (SIDESPIN ONLY)//
float _mag = -((1.429f * Mathf.Abs(_vv)* (2 * Mathf.PI * _halfmass *
GetComponent<Rigidbody>().angularVelocity.y))) * (_BallRadius * .5f);
Vector3 _xmagdir = new Vector3(GetComponent<Rigidbody>().velocity.x, 0, GetComponent<Rigidbody>().velocity.z);
GetComponent<Rigidbody().AddForce(Vector3.Cross(_xmagdir.normalized,Vector3.up)*_mag, ForceMode.Acceleration);
}
Это работает достаточно хорошо, но теперь мне нужно вычислить правильную сумму, чтобы дать мяч, чтобы получить такой результат:
Диаграмма желаемой кривой
Я пробовал несколько разных подходов и пришел к выводу, что это в основном сводится к тригонометрии. Вот где я сейчас нахожусь (это до того, как тангенциальное направление будет применено к конечному вектору скорости):
Vector3 GetMagnusTorque(float Distance, Vector3 V_BallForce, float xdir)
{
float _BallRadius = .0427f;
float _halfmass = Mathf.Sqrt(_BallRadius*.5f);
Vector3 v = GO_Camera.transform.InverseTransformDirection(V_BallForce);
float HorizontalRange = Distance;
//THIS IS THE LATERAL DISTANCE WE NEED TO TRAVEL//
float opposite = (Mathf.Abs(Mathf.Tan(Mathf.Deg2Rad * xdir))) * (HorizontalRange*.5f);
//THIS IS THE TIME IT WILL NEED TO TAKE//
float time = ((2 * v.magnitude * Mathf.Sin((2 * (v.normalized.y )))) / -Physics.gravity.y);
//THIS IS THE SPEED THE MAGNUS EFFECT WILL NEED TO PRODUCE//
float linearSpeed =Mathf.Abs((opposite/time))*Mathf.Sign(xdir)Mathf.Abs((opposite/time))*Mathf.Sign(xdir)*(Time.timeScale+Time.fixedDeltaTime);
return GO_Camera.transform.TransformDirection((((linearSpeed /( 2 * Mathf.PI * _halfmass * (_BallRadius * .5f))) / 1.429f))*Mathf.Deg2Rad*GO_PGolfBall.transform.up);
}
Логика позади этого
Результат очень противоречивый, основанный на xdir и V_BallForce, иногда продвигается дальше, а иногда и вовсе. Это было довольно отрезвляющее приключение, когда я обнаружил, что я довольно плохо разбираюсь в математике.
Если у кого-нибудь есть какие-либо советы по этому вопросу, я всегда буду у вас в долгу.
Обновление: вот некоторая визуализация проблемы:
визуализация
Обновление: я решил, что должен включить пример кода функции, из которой вызывается GetMagnusTorque, чтобы лучше понять ситуацию:
void BallApplyForce()
{
//_rmult is a [0,1] value that is dependent on the accuracy of the player's swing//
float _rmult = GetRMult();
//GETS BALL READY BY ENABLING PHYSICS AND SETTING ITS ROTATION TO THE CAMERA//
GO_PGolfBall.transform.rotation = new Quaternion(0, GO_Camera.transform.rotation.y, GO_Camera.transform.rotation.z, GO_Camera.transform.rotation.w);
GO_PGolfBall.GetComponent<SCR_GOLFBALLCONTROL>().B_PhysicsActive = true;
//YDIR = PITCH, XDIR = YAW. V_ContactPoint is a [-1,1] Vector2 used similar to Mario Golf//
Vector3 _vdir = Vector3.zero;
float ydir = ((Mathf.Rad2Deg * DIC_Clubs[I_CurrentClub].LandAngle) + (-2.5f * (.1f) * (DIC_Clubs[I_CurrentClub].LoftAngle * Mathf.Rad2Deg)));
float _xdir = Mathf.Rad2Deg * (-(V_ContactPoint.x) * (DIC_Clubs[I_CurrentClub].LoftAngle)*3f);
_vdir.y = ydir;
_vdir = _vdir.normalized;
_vdir.y *= Mathf.Rad2Deg;
//MAX DISTANCE OF THE CLUB BEING USED TO METERS//
float _dist = ((DIC_Clubs[I_CurrentClub].MaxDistance * F_UPower) * _rmult) * .9144f;
//GET FORWARD AND UPWARDS VELOCITIES BASED ON THE DISTANCE GIVEN, XDIR ISN'T FACTORED FOR NOW//
float Vi = Mathf.Sqrt(_dist * -Physics.gravity.y / (Mathf.Sin(Mathf.Deg2Rad * _vdir.y * 2)));
float Vy, Vz;
Vy = Vi * Mathf.Sin(Mathf.Deg2Rad*_vdir.y);
Vz = Vi * Mathf.Cos(Mathf.Deg2Rad*_vdir.y);
GO_Camera.transform.eulerAngles = new Vector3(0, GO_Camera.transform.eulerAngles.y, 0);
Vector3 _velo = GO_Camera.transform.TransformVector(new Vector3(0f, Vy, Vz));
//CALCULATE VERTICAL ANGULAR VELOCITY, THIS DOESNT NEED TO FOLLOW ANY SORT OF PATTERN FOR NOW//
float _verRoll = Mathf.Sign(V_ContactPoint.y - .1f) * ((.7135f) * _dist) * Mathf.Sin(DIC_Clubs[I_CurrentClub].LoftAngle +
((Mathf.Abs(V_ContactPoint.y + .1f)) * (DIC_Clubs[I_CurrentClub].LaunchAngle))) * 60 * Mathf.Deg2Rad;
GO_PGolfBall.GetComponent<Rigidbody>().AddTorque(Vector3.Scale(GO_PGolfBall.transform.right, new Vector3(1, 0, 0)) * _verRoll, ForceMode.VelocityChange);
//CALCULATE HORIZONTAL ANGULAR VELOCITY//
Debug.Log("MAGNUS CALC:" + GetMagnusTorque(_dist, _velo, _xdir));
GO_PGolfBall.GetComponent<Rigidbody>().AddTorque(GetMagnusTorque(_dist, _velo, _xdir), ForceMode.VelocityChange);
//APPLY XDIR TO THE CAMERA ANGLE AND RECALCULATE VELOCITY//
GO_Camera.transform.eulerAngles = new Vector3(0, GO_Camera.transform.eulerAngles.y+_xdir, 0);
_velo = GO_Camera.transform.TransformVector(new Vector3(0f, Vy, Vz));
//APPLY VELOCITY//
GO_PGolfBall.transform.GetComponent<Rigidbody>().AddForce(_velo, ForceMode.VelocityChange);
}
Обновление 11/21: в настоящее время я подделываю его методом проб и ошибок. Но для тех, кто все еще заинтересован в решении этой аномалии, я, возможно, нашел вопрос в том, как я рассчитываю направление, чтобы применить к мячу силу, полученную из бокового вращения. Удар по мячу с помощью лопастного клина, который имеет максимальное расстояние 70 ярдов и угол наклона 60 градусов, искомая кривая выглядит примерно так: Клин лопасти Это, очевидно, не имеет смысла, потому что шар летит позади игрока в гольф на короткий период времени. Я сообщу об окончательных числах и расчетах, хотя это не ответит на вопрос, это могло бы помочь указать это в правильном направлении.