Calculating Angular Velocity Needed to Travel a Certain Distance Via the Magnus Effect











up vote
0
down vote

favorite
1












Aight so I've been at this for several days and with how much it's slowing the project down I've made the hard decision to come beg the internet.
I'm working on a physics-based golf game in Unity and am working on implementing the magnus effect. This is my calculation for tangential force based on torque:



    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);
}


This works well enough, but now I need to figure out the correct amount to give the ball to get this result:
Diagram of Desired Curve



I've tried several different approaches, and I've come to the conclusion that this is mostly comes down to trigonometry. Here is where I'm at currently (this is before the tangential direction is applied to the final velocity vector):



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);
}


Logic behind this



The result is very inconsistent based on xdir and V_BallForce, sometimes travels further, sometimes barely at all. This has been a pretty sobering adventure in discovering that I'm pretty bad at math.
If anyone has any advice for this issue I would forever be in your debt.



Update: Here is some visualization of the issue:
visualization



Update: I figured I should include a code sample of the function GetMagnusTorque is called from, to better put things in context:



 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);
}


Update 11/21: I'm currently in the process of faking it through trial and error. But for those still interested in solving this anomaly, I may have found in issue in how I'm calculating the direction to apply the side-spin derived force to the ball. Hitting the ball with a lob wedge, which has a maximum distance of 70 yards and a loft angle of 60 deg, the desired curve looks something like this: Lob Wedge This obviously makes no sense, because the ball flies behind the golfer for a short period of time. I'll report back with the final numbers and calculations, though it will not answer the question it could help point it in the correct direction.










share|improve this question




















  • 1




    This question eventually comes down to a coding problem. All of the 'physics' could have been easily abstracted while retaining the message.
    – Taslim
    Nov 11 at 0:22










  • I could be misinterpreting what you mean, but this seems to be the opposite to me. Given a formula for force over time based on torque, an initial torque must be set such that by the end of a time calculated from horizontal range and velocity, the projectile's velocity in the tangent direction is equal to negative its tangent velocity at the start.
    – Jacob Sirotta
    Nov 11 at 1:22










  • Is the problem 2D or 3D? It currently looks like a mixture of both, because although the velocity's Y-component is assumed to be zero, so is the angular velocity's Y-component. A 3D simulation has no such constraints, but the angular velocity should only have an effective Y-component in the 2D case.
    – meowgoesthedog
    Nov 11 at 19:03










  • Vertical spin is done separately, this is purely for side spin. angularVelocity.y is used because that is the axis for the side spin. Oh I see though, angularVelocity.z shouldn't be factored into the side-spin calculation. I'll update the code with this fix, but the main issue should persist since angularVelocity.z isn't applied on hit.
    – Jacob Sirotta
    Nov 11 at 21:34










  • The 2D top-down case is fairly simple - the ball travels in a circular arc; the 3D case, when gravity is taken into account, might not be analytical (you might need numerical integration).
    – meowgoesthedog
    Nov 12 at 10:44

















up vote
0
down vote

favorite
1












Aight so I've been at this for several days and with how much it's slowing the project down I've made the hard decision to come beg the internet.
I'm working on a physics-based golf game in Unity and am working on implementing the magnus effect. This is my calculation for tangential force based on torque:



    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);
}


This works well enough, but now I need to figure out the correct amount to give the ball to get this result:
Diagram of Desired Curve



I've tried several different approaches, and I've come to the conclusion that this is mostly comes down to trigonometry. Here is where I'm at currently (this is before the tangential direction is applied to the final velocity vector):



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);
}


Logic behind this



The result is very inconsistent based on xdir and V_BallForce, sometimes travels further, sometimes barely at all. This has been a pretty sobering adventure in discovering that I'm pretty bad at math.
If anyone has any advice for this issue I would forever be in your debt.



Update: Here is some visualization of the issue:
visualization



Update: I figured I should include a code sample of the function GetMagnusTorque is called from, to better put things in context:



 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);
}


Update 11/21: I'm currently in the process of faking it through trial and error. But for those still interested in solving this anomaly, I may have found in issue in how I'm calculating the direction to apply the side-spin derived force to the ball. Hitting the ball with a lob wedge, which has a maximum distance of 70 yards and a loft angle of 60 deg, the desired curve looks something like this: Lob Wedge This obviously makes no sense, because the ball flies behind the golfer for a short period of time. I'll report back with the final numbers and calculations, though it will not answer the question it could help point it in the correct direction.










share|improve this question




















  • 1




    This question eventually comes down to a coding problem. All of the 'physics' could have been easily abstracted while retaining the message.
    – Taslim
    Nov 11 at 0:22










  • I could be misinterpreting what you mean, but this seems to be the opposite to me. Given a formula for force over time based on torque, an initial torque must be set such that by the end of a time calculated from horizontal range and velocity, the projectile's velocity in the tangent direction is equal to negative its tangent velocity at the start.
    – Jacob Sirotta
    Nov 11 at 1:22










  • Is the problem 2D or 3D? It currently looks like a mixture of both, because although the velocity's Y-component is assumed to be zero, so is the angular velocity's Y-component. A 3D simulation has no such constraints, but the angular velocity should only have an effective Y-component in the 2D case.
    – meowgoesthedog
    Nov 11 at 19:03










  • Vertical spin is done separately, this is purely for side spin. angularVelocity.y is used because that is the axis for the side spin. Oh I see though, angularVelocity.z shouldn't be factored into the side-spin calculation. I'll update the code with this fix, but the main issue should persist since angularVelocity.z isn't applied on hit.
    – Jacob Sirotta
    Nov 11 at 21:34










  • The 2D top-down case is fairly simple - the ball travels in a circular arc; the 3D case, when gravity is taken into account, might not be analytical (you might need numerical integration).
    – meowgoesthedog
    Nov 12 at 10:44















up vote
0
down vote

favorite
1









up vote
0
down vote

favorite
1






1





Aight so I've been at this for several days and with how much it's slowing the project down I've made the hard decision to come beg the internet.
I'm working on a physics-based golf game in Unity and am working on implementing the magnus effect. This is my calculation for tangential force based on torque:



    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);
}


This works well enough, but now I need to figure out the correct amount to give the ball to get this result:
Diagram of Desired Curve



I've tried several different approaches, and I've come to the conclusion that this is mostly comes down to trigonometry. Here is where I'm at currently (this is before the tangential direction is applied to the final velocity vector):



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);
}


Logic behind this



The result is very inconsistent based on xdir and V_BallForce, sometimes travels further, sometimes barely at all. This has been a pretty sobering adventure in discovering that I'm pretty bad at math.
If anyone has any advice for this issue I would forever be in your debt.



Update: Here is some visualization of the issue:
visualization



Update: I figured I should include a code sample of the function GetMagnusTorque is called from, to better put things in context:



 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);
}


Update 11/21: I'm currently in the process of faking it through trial and error. But for those still interested in solving this anomaly, I may have found in issue in how I'm calculating the direction to apply the side-spin derived force to the ball. Hitting the ball with a lob wedge, which has a maximum distance of 70 yards and a loft angle of 60 deg, the desired curve looks something like this: Lob Wedge This obviously makes no sense, because the ball flies behind the golfer for a short period of time. I'll report back with the final numbers and calculations, though it will not answer the question it could help point it in the correct direction.










share|improve this question















Aight so I've been at this for several days and with how much it's slowing the project down I've made the hard decision to come beg the internet.
I'm working on a physics-based golf game in Unity and am working on implementing the magnus effect. This is my calculation for tangential force based on torque:



    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);
}


This works well enough, but now I need to figure out the correct amount to give the ball to get this result:
Diagram of Desired Curve



I've tried several different approaches, and I've come to the conclusion that this is mostly comes down to trigonometry. Here is where I'm at currently (this is before the tangential direction is applied to the final velocity vector):



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);
}


Logic behind this



The result is very inconsistent based on xdir and V_BallForce, sometimes travels further, sometimes barely at all. This has been a pretty sobering adventure in discovering that I'm pretty bad at math.
If anyone has any advice for this issue I would forever be in your debt.



Update: Here is some visualization of the issue:
visualization



Update: I figured I should include a code sample of the function GetMagnusTorque is called from, to better put things in context:



 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);
}


Update 11/21: I'm currently in the process of faking it through trial and error. But for those still interested in solving this anomaly, I may have found in issue in how I'm calculating the direction to apply the side-spin derived force to the ball. Hitting the ball with a lob wedge, which has a maximum distance of 70 yards and a loft angle of 60 deg, the desired curve looks something like this: Lob Wedge This obviously makes no sense, because the ball flies behind the golfer for a short period of time. I'll report back with the final numbers and calculations, though it will not answer the question it could help point it in the correct direction.







c# unity3d physics trigonometry






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 21 at 17:07

























asked Nov 10 at 23:59









Jacob Sirotta

12




12








  • 1




    This question eventually comes down to a coding problem. All of the 'physics' could have been easily abstracted while retaining the message.
    – Taslim
    Nov 11 at 0:22










  • I could be misinterpreting what you mean, but this seems to be the opposite to me. Given a formula for force over time based on torque, an initial torque must be set such that by the end of a time calculated from horizontal range and velocity, the projectile's velocity in the tangent direction is equal to negative its tangent velocity at the start.
    – Jacob Sirotta
    Nov 11 at 1:22










  • Is the problem 2D or 3D? It currently looks like a mixture of both, because although the velocity's Y-component is assumed to be zero, so is the angular velocity's Y-component. A 3D simulation has no such constraints, but the angular velocity should only have an effective Y-component in the 2D case.
    – meowgoesthedog
    Nov 11 at 19:03










  • Vertical spin is done separately, this is purely for side spin. angularVelocity.y is used because that is the axis for the side spin. Oh I see though, angularVelocity.z shouldn't be factored into the side-spin calculation. I'll update the code with this fix, but the main issue should persist since angularVelocity.z isn't applied on hit.
    – Jacob Sirotta
    Nov 11 at 21:34










  • The 2D top-down case is fairly simple - the ball travels in a circular arc; the 3D case, when gravity is taken into account, might not be analytical (you might need numerical integration).
    – meowgoesthedog
    Nov 12 at 10:44
















  • 1




    This question eventually comes down to a coding problem. All of the 'physics' could have been easily abstracted while retaining the message.
    – Taslim
    Nov 11 at 0:22










  • I could be misinterpreting what you mean, but this seems to be the opposite to me. Given a formula for force over time based on torque, an initial torque must be set such that by the end of a time calculated from horizontal range and velocity, the projectile's velocity in the tangent direction is equal to negative its tangent velocity at the start.
    – Jacob Sirotta
    Nov 11 at 1:22










  • Is the problem 2D or 3D? It currently looks like a mixture of both, because although the velocity's Y-component is assumed to be zero, so is the angular velocity's Y-component. A 3D simulation has no such constraints, but the angular velocity should only have an effective Y-component in the 2D case.
    – meowgoesthedog
    Nov 11 at 19:03










  • Vertical spin is done separately, this is purely for side spin. angularVelocity.y is used because that is the axis for the side spin. Oh I see though, angularVelocity.z shouldn't be factored into the side-spin calculation. I'll update the code with this fix, but the main issue should persist since angularVelocity.z isn't applied on hit.
    – Jacob Sirotta
    Nov 11 at 21:34










  • The 2D top-down case is fairly simple - the ball travels in a circular arc; the 3D case, when gravity is taken into account, might not be analytical (you might need numerical integration).
    – meowgoesthedog
    Nov 12 at 10:44










1




1




This question eventually comes down to a coding problem. All of the 'physics' could have been easily abstracted while retaining the message.
– Taslim
Nov 11 at 0:22




This question eventually comes down to a coding problem. All of the 'physics' could have been easily abstracted while retaining the message.
– Taslim
Nov 11 at 0:22












I could be misinterpreting what you mean, but this seems to be the opposite to me. Given a formula for force over time based on torque, an initial torque must be set such that by the end of a time calculated from horizontal range and velocity, the projectile's velocity in the tangent direction is equal to negative its tangent velocity at the start.
– Jacob Sirotta
Nov 11 at 1:22




I could be misinterpreting what you mean, but this seems to be the opposite to me. Given a formula for force over time based on torque, an initial torque must be set such that by the end of a time calculated from horizontal range and velocity, the projectile's velocity in the tangent direction is equal to negative its tangent velocity at the start.
– Jacob Sirotta
Nov 11 at 1:22












Is the problem 2D or 3D? It currently looks like a mixture of both, because although the velocity's Y-component is assumed to be zero, so is the angular velocity's Y-component. A 3D simulation has no such constraints, but the angular velocity should only have an effective Y-component in the 2D case.
– meowgoesthedog
Nov 11 at 19:03




Is the problem 2D or 3D? It currently looks like a mixture of both, because although the velocity's Y-component is assumed to be zero, so is the angular velocity's Y-component. A 3D simulation has no such constraints, but the angular velocity should only have an effective Y-component in the 2D case.
– meowgoesthedog
Nov 11 at 19:03












Vertical spin is done separately, this is purely for side spin. angularVelocity.y is used because that is the axis for the side spin. Oh I see though, angularVelocity.z shouldn't be factored into the side-spin calculation. I'll update the code with this fix, but the main issue should persist since angularVelocity.z isn't applied on hit.
– Jacob Sirotta
Nov 11 at 21:34




Vertical spin is done separately, this is purely for side spin. angularVelocity.y is used because that is the axis for the side spin. Oh I see though, angularVelocity.z shouldn't be factored into the side-spin calculation. I'll update the code with this fix, but the main issue should persist since angularVelocity.z isn't applied on hit.
– Jacob Sirotta
Nov 11 at 21:34












The 2D top-down case is fairly simple - the ball travels in a circular arc; the 3D case, when gravity is taken into account, might not be analytical (you might need numerical integration).
– meowgoesthedog
Nov 12 at 10:44






The 2D top-down case is fairly simple - the ball travels in a circular arc; the 3D case, when gravity is taken into account, might not be analytical (you might need numerical integration).
– meowgoesthedog
Nov 12 at 10:44



















active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53244613%2fcalculating-angular-velocity-needed-to-travel-a-certain-distance-via-the-magnus%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown






























active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes
















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53244613%2fcalculating-angular-velocity-needed-to-travel-a-certain-distance-via-the-magnus%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Florida Star v. B. J. F.

Danny Elfman

Lugert, Oklahoma