102 lines
2.9 KiB
C#
102 lines
2.9 KiB
C#
using Sandbox;
|
|
using System;
|
|
|
|
namespace VeloX;
|
|
|
|
|
|
[GameResource( "Wheel Friction", "tire", "Wheel Friction", Category = "VeloX", Icon = "radio_button_checked" )]
|
|
public class TirePreset : GameResource
|
|
{
|
|
|
|
[Property] public Pacejka Pacejka { get; set; }
|
|
|
|
public float RollResistanceLin { get; set; } = 1E-3f;
|
|
public float RollResistanceQuad { get; set; } = 1E-6f;
|
|
|
|
public float GetRollingResistance( float velocity, float resistance_factor )
|
|
{ // surface influence on rolling resistance
|
|
float resistance = resistance_factor * RollResistanceLin;
|
|
|
|
// heat due to tire deformation increases rolling resistance
|
|
// approximate by quadratic function
|
|
resistance += velocity * velocity * RollResistanceQuad;
|
|
|
|
return resistance;
|
|
}
|
|
|
|
public void ComputeSlip( float vlon, float vlat, float vrot, out float slip_ratio, out float slip_angle )
|
|
{
|
|
float rvlon = 1 / MathF.Max( MathF.Abs( vlon ), 1E-3f );
|
|
float vslip = vrot - vlon;
|
|
slip_ratio = vslip * rvlon;
|
|
slip_angle = -MathF.Atan( vlat * rvlon );
|
|
}
|
|
|
|
/// approximate asin(x) = x + x^3/6 for +-18 deg range
|
|
public static float ComputeCamberAngle( float sin_camber )
|
|
{
|
|
float sc = Math.Clamp( sin_camber, -0.3f, 0.3f );
|
|
return ((1 / 6.0f) * (sc * sc) + 1) * sc;
|
|
}
|
|
|
|
public struct TireState
|
|
{
|
|
public float friction = 0; // surface friction coefficient
|
|
public float camber = 0; // tire camber angle relative to track surface
|
|
public float vcam = 0; // camber thrust induced lateral slip velocity
|
|
public float slip = 0; // ratio of tire contact patch speed to road speed
|
|
public float slip_angle = 0; // the angle between the wheel heading and the wheel velocity
|
|
public float ideal_slip = 0; // peak force slip ratio
|
|
public float ideal_slip_angle = 0; // peak force slip angle
|
|
public float fx = 0; // positive during traction
|
|
public float fy = 0; // positive in a right turn
|
|
public float mz = 0; // positive in a left turn
|
|
|
|
public TireState()
|
|
{
|
|
}
|
|
};
|
|
|
|
public void ComputeState(
|
|
float normal_force,
|
|
float rot_velocity,
|
|
float lon_velocity,
|
|
float lat_velocity,
|
|
float camber_angle,
|
|
out TireState s
|
|
)
|
|
{
|
|
s = new TireState
|
|
{
|
|
camber = camber_angle,
|
|
friction = 1.0f
|
|
};
|
|
|
|
if ( normal_force * s.friction < 1E-6f )
|
|
{
|
|
s.slip = s.slip_angle = 0;
|
|
s.fx = s.fy = s.mz = 0;
|
|
return;
|
|
}
|
|
|
|
float Fz = Math.Min( normal_force * 1E-3f, 30f );
|
|
ComputeSlip( lon_velocity, lat_velocity, rot_velocity, out float slip, out float slip_angle );
|
|
float sigma = slip;
|
|
float alpha = slip_angle.RadianToDegree();
|
|
float gamma = s.camber.RadianToDegree();
|
|
float Fx = Pacejka.PacejkaFx( sigma, Fz, s.friction );
|
|
float Fy = Pacejka.PacejkaFy( alpha, Fz, gamma, s.friction, out float camber_alpha );
|
|
s.vcam = ComputeCamberVelocity( camber_alpha.DegreeToRadian(), lon_velocity );
|
|
s.slip = slip;
|
|
s.slip_angle = slip_angle;
|
|
s.fx = Fx;
|
|
s.fy = Fy;
|
|
}
|
|
|
|
public static float ComputeCamberVelocity( float sa, float vx )
|
|
{
|
|
float tansa = (1 / 3.0f * (sa * sa) + 1) * sa;
|
|
return tansa * vx;
|
|
}
|
|
}
|