Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How do I take 2D magnus effect to the 3D world? (Sample code included)

Discussion in 'Physics' started by icandothemath, Apr 27, 2015.

  1. icandothemath

    icandothemath

    Joined:
    Apr 27, 2015
    Posts:
    5
    Hi, I have been looking for a few days now for this answer. If anyone could help I would appreciate it a lot. I am trying to add the magnus effect to my golf ball simulation. (It is the force that the ball's spin applies to the ball in flight) Right now I have it working in a 2D plane. I was wondering if someone could show me how to make this work in 3D space for any rotation angle?

    I spent a good amount of time tidying and commenting my code to make it easy to understand. To use the script just place a sphere in your scene and attach this script. Then run. It will simulate the effect. (You can throw a trail renderer on the sphere to see the flight path.
    The original 2D calculation I got from here http://aolab.phys.dal.ca/~tomduck/classes/phyc2050/notes/phyc2050_ch4.pdf

    *edit* I just found this article that explains the effect in 3d but don't know how to implement it.
    http://www.crm.cat/en/publications/publications/2013/pr1154.pdf

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class magnus2D : MonoBehaviour
    5. {
    6.     // Meters per second (magnitude)
    7.     public float Speed = 70f;
    8.     // Degrees (converts to radians in Start())
    9.     public float Angle = 15f;
    10.     // Z axis spin (RPM)
    11.     public float ZSpin = 4000f;
    12.     // Gravity (m/s^2)
    13.     private float Gravity = 9.8f;
    14.     // X component of Speed
    15.     private float XSpeed = 0f;
    16.     // Y component of Speed
    17.     private float YSpeed = 0f;
    18.     // Mass of golf ball (kg)
    19.     private float Mass_KG = 45.93e-3f;
    20.     // Ball diameter (m)
    21.     private float Diameter_M = 42.67e-3f;
    22.     // Cross-sectional area of golf ball (m^2)
    23.     private float Area_M = 0f;
    24.     // Air density (kg/m^3) (1.2 at sea level)
    25.     private float AirDensity_KG = 1.2f;
    26.  
    27.     void Start()
    28.     {
    29.         // Scale so we can see size
    30.         transform.localScale = new Vector3(Diameter_M, Diameter_M, Diameter_M);
    31.         // Cross-sectional area of golf ball (m^2)
    32.         Area_M = AreaofCircle(Diameter_M / 2.0f);
    33.         // angle needs to be in radians
    34.         Angle = Mathf.Deg2Rad * Angle;
    35.         // gets opposite side length of triangle
    36.         YSpeed = Speed * Mathf.Sin(Angle);
    37.         // gets adjacent side length of triangle
    38.         XSpeed = Speed * Mathf.Cos(Angle);
    39.     }
    40.  
    41.     Vector3 Calculate2DMagnusAndDrag()
    42.     {
    43.         // Velocity along the XY plane
    44.         float Velocity = magnitude(XSpeed, YSpeed);
    45.         // Convert spin RPM to radians
    46.         float SpinRateRAD = RPM2Radians(ZSpin);
    47.         // Get spin ratio to calculate coefficients
    48.         float spinRatio = get_spin_ratio(SpinRateRAD, Velocity);
    49.         // Drag Coefficient (Dependant on speed)
    50.         float DragCoefficient = get_DragCoefficient(spinRatio);
    51.         // Lift Coefficient (Dependant on speed)
    52.         float LiftCoefficient = get_LiftCoefficient(spinRatio);
    53.  
    54.         float D = AirDensity_KG * Area_M * Velocity / (2 * Mass_KG);
    55.         float xAirDrag = D * (DragCoefficient * XSpeed + LiftCoefficient * YSpeed);
    56.         float yAirDrag = D * (DragCoefficient * YSpeed - LiftCoefficient * XSpeed);
    57.         float zAirDrag = 0f;
    58.         return new Vector3(xAirDrag, yAirDrag, zAirDrag);
    59.     }
    60.  
    61.     void FixedUpdate()
    62.     {
    63.         // calculates air and magnus force drag
    64.         Vector3 drag = Calculate2DMagnusAndDrag();
    65.         // subtract drag from x speed
    66.         XSpeed -= drag.x * Time.fixedDeltaTime;
    67.         // get next x coordinate increment
    68.         float xStep = XSpeed * Time.fixedDeltaTime;
    69.         // subtract gravity from y speed
    70.         YSpeed -= Gravity * Time.fixedDeltaTime;
    71.         // subtract drag from y speed
    72.         YSpeed -= drag.y * Time.fixedDeltaTime;
    73.         // get next y coordinate increment
    74.         float yStep = YSpeed * Time.fixedDeltaTime;
    75.         // get new x coordinate
    76.         float newx = transform.position.x + xStep;
    77.         // get new y coordinate
    78.         float newy = transform.position.y + yStep;
    79.         // check if above ground
    80.         if (newy > -0f)
    81.             // set position of ball
    82.             transform.position = new Vector3(newx, newy, 0f);
    83.     }
    84.  
    85.     // Determin spin ratio
    86.     float get_spin_ratio(float SpinRateRAD, float Velocity)
    87.     {
    88.         return SpinRateRAD * (Diameter_M / 2.0f) / Velocity;
    89.     }
    90.  
    91.     // Determine the drag coefficient
    92.     float get_DragCoefficient(float SpinRatio)
    93.     {
    94.         return (float)(0.1403 - 0.3406 * SpinRatio * Mathf.Log(SpinRatio) + 0.3747 * Mathf.Pow(SpinRatio, 1.5f));
    95.     }
    96.  
    97.     // Determine the lift coefficient
    98.     float get_LiftCoefficient(float SpinRatio)
    99.     {
    100.         return (float)(0.3996 + 0.1583 * Mathf.Log(SpinRatio) + 0.03790 * Mathf.Pow(SpinRatio, -0.5f));
    101.     }
    102.  
    103.     // Spin rate (radians/s) [Convert RPM]
    104.     float RPM2Radians(float rpm)
    105.     {
    106.         return 2f * Mathf.PI * rpm / 60f;
    107.     }
    108.  
    109.     // pi r^2
    110.     float AreaofCircle(float radius)
    111.     {
    112.         return Mathf.PI * Mathf.Pow(radius, 2.0f);
    113.     }
    114.  
    115.     // a^2 + b^2 = c^2
    116.     float magnitude(float speedx, float speedy)
    117.     {
    118.         return Mathf.Sqrt(Mathf.Pow(speedx, 2.0f) + Mathf.Pow(speedy, 2.0f));
    119.     }
    120. }
     
    Last edited: Apr 27, 2015