уже лучше
This commit is contained in:
parent
4912d0ae1a
commit
f0f89ff947
@ -1,5 +1,56 @@
|
|||||||
{
|
{
|
||||||
"Pacejka": {},
|
"Pacejka": {
|
||||||
|
"Lateral": {
|
||||||
|
"a0": 1.4,
|
||||||
|
"a1": -0,
|
||||||
|
"a2": 1688,
|
||||||
|
"a3": 2400,
|
||||||
|
"a4": 6.026,
|
||||||
|
"a5": 0,
|
||||||
|
"a6": -0.359,
|
||||||
|
"a7": 1,
|
||||||
|
"a8": 0,
|
||||||
|
"a9": 0,
|
||||||
|
"a10": 0,
|
||||||
|
"a111": 0,
|
||||||
|
"a112": 0,
|
||||||
|
"a12": 0,
|
||||||
|
"a13": 0
|
||||||
|
},
|
||||||
|
"Longitudinal": {
|
||||||
|
"b0": 1.65,
|
||||||
|
"b1": 0,
|
||||||
|
"b2": 1690,
|
||||||
|
"b3": 0,
|
||||||
|
"b4": 229,
|
||||||
|
"b5": 0,
|
||||||
|
"b6": 0,
|
||||||
|
"b7": 0,
|
||||||
|
"b8": -10,
|
||||||
|
"b9": 0,
|
||||||
|
"b10": 0
|
||||||
|
},
|
||||||
|
"Aligning": {
|
||||||
|
"c0": 2,
|
||||||
|
"c1": -3.8,
|
||||||
|
"c2": -3.14,
|
||||||
|
"c3": -1.16,
|
||||||
|
"c4": -7.2,
|
||||||
|
"c5": 0,
|
||||||
|
"c6": 0,
|
||||||
|
"c7": 0.044,
|
||||||
|
"c8": -0.58,
|
||||||
|
"c9": 0.18,
|
||||||
|
"c10": 0,
|
||||||
|
"c11": 0,
|
||||||
|
"c12": 0,
|
||||||
|
"c13": 0,
|
||||||
|
"c14": 0.14,
|
||||||
|
"c15": -1.029,
|
||||||
|
"c16": 0,
|
||||||
|
"c17": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
"RollResistanceLin": 0.001,
|
"RollResistanceLin": 0.001,
|
||||||
"RollResistanceQuad": 1E-06,
|
"RollResistanceQuad": 1E-06,
|
||||||
"__references": [],
|
"__references": [],
|
||||||
|
|||||||
@ -87,7 +87,7 @@ public class Engine : PowertrainComponent
|
|||||||
angularVelocity += finalTorque / inertiaSum * Time.Delta;
|
angularVelocity += finalTorque / inertiaSum * Time.Delta;
|
||||||
angularVelocity = Math.Max( angularVelocity, 0 );
|
angularVelocity = Math.Max( angularVelocity, 0 );
|
||||||
|
|
||||||
//UpdateStream();
|
UpdateStream();
|
||||||
|
|
||||||
return finalTorque;
|
return finalTorque;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,11 @@ public class PowerWheel : PowertrainComponent
|
|||||||
{
|
{
|
||||||
[Property] public VeloXWheel Wheel { get; set; }
|
[Property] public VeloXWheel Wheel { get; set; }
|
||||||
|
|
||||||
public override float QueryInertia() => Wheel.Inertia;
|
public override float QueryInertia()
|
||||||
|
{
|
||||||
|
float dtScale = Math.Clamp( Time.Delta, 0.01f, 0.05f ) / 0.005f;
|
||||||
|
return Wheel.BaseInertia * dtScale;
|
||||||
|
}
|
||||||
|
|
||||||
public override float QueryAngularVelocity( float angularVelocity )
|
public override float QueryAngularVelocity( float angularVelocity )
|
||||||
{
|
{
|
||||||
@ -19,7 +23,8 @@ public class PowerWheel : PowertrainComponent
|
|||||||
Wheel.AutoPhysics = false;
|
Wheel.AutoPhysics = false;
|
||||||
Wheel.Torque = torque;
|
Wheel.Torque = torque;
|
||||||
Wheel.Brake = Vehicle.Brake;
|
Wheel.Brake = Vehicle.Brake;
|
||||||
|
Inertia = Wheel.BaseInertia + inertia;
|
||||||
|
Wheel.Inertia = inertia;
|
||||||
Wheel.DoPhysics( Vehicle );
|
Wheel.DoPhysics( Vehicle );
|
||||||
|
|
||||||
angularVelocity = Wheel.AngularVelocity;
|
angularVelocity = Wheel.AngularVelocity;
|
||||||
|
|||||||
@ -167,7 +167,7 @@ public class Pacejka
|
|||||||
|
|
||||||
|
|
||||||
/// pacejka magic formula for longitudinal force
|
/// pacejka magic formula for longitudinal force
|
||||||
public float PacejkaFx( float sigma, float Fz, float friction_coeff )
|
public float PacejkaFx( float sigma, float Fz, float friction_coeff, out float maxforce_output )
|
||||||
{
|
{
|
||||||
var b = Longitudinal;
|
var b = Longitudinal;
|
||||||
|
|
||||||
@ -198,6 +198,7 @@ public class Pacejka
|
|||||||
|
|
||||||
// scale by surface friction
|
// scale by surface friction
|
||||||
Fx *= friction_coeff;
|
Fx *= friction_coeff;
|
||||||
|
maxforce_output = D;
|
||||||
|
|
||||||
return Fx;
|
return Fx;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,12 +24,24 @@ public class TirePreset : GameResource
|
|||||||
return resistance;
|
return resistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ComputeSlip( float vlon, float vlat, float vrot, out float slip_ratio, out float slip_angle )
|
public static void ComputeSlip( float lon_velocity, float lat_velocity, float rot_velocity, float wheel_radius, out float slip_ratio, out float slip_angle )
|
||||||
{
|
{
|
||||||
float rvlon = 1 / MathF.Max( MathF.Abs( vlon ), 1E-3f );
|
var abs_lon = Math.Max( MathF.Abs( lon_velocity ), 1e-3f );
|
||||||
float vslip = vrot - vlon;
|
|
||||||
slip_ratio = vslip * rvlon;
|
slip_ratio = lon_velocity - rot_velocity * wheel_radius;
|
||||||
slip_angle = -MathF.Atan( vlat * rvlon );
|
|
||||||
|
if ( abs_lon >= 0.005f )
|
||||||
|
slip_ratio /= abs_lon;
|
||||||
|
else
|
||||||
|
slip_ratio *= abs_lon;
|
||||||
|
|
||||||
|
if ( abs_lon >= 0.5f )
|
||||||
|
slip_angle = MathF.Atan2( -lat_velocity, abs_lon ).RadianToDegree() / 50f;
|
||||||
|
else
|
||||||
|
slip_angle = -lat_velocity * (0.01f / Time.Delta);
|
||||||
|
|
||||||
|
slip_ratio = Math.Clamp( slip_ratio, -1, 1 );
|
||||||
|
slip_angle = Math.Clamp( slip_angle, -1, 1 );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,104 +52,6 @@ public class TirePreset : GameResource
|
|||||||
return ((1 / 6.0f) * (sc * sc) + 1) * sc;
|
return ((1 / 6.0f) * (sc * sc) + 1) * sc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct TireState()
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// surface friction coefficient
|
|
||||||
/// </summary>
|
|
||||||
public float friction = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// tire camber angle relative to track surface
|
|
||||||
/// </summary>
|
|
||||||
public float camber = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// camber thrust induced lateral slip velocity
|
|
||||||
/// </summary>
|
|
||||||
public float vcam = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// ratio of tire contact patch speed to road speed
|
|
||||||
/// </summary>
|
|
||||||
public float slip = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// the angle between the wheel heading and the wheel velocity
|
|
||||||
/// </summary>
|
|
||||||
public float slip_angle = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// peak force slip ratio
|
|
||||||
/// </summary>
|
|
||||||
public float ideal_slip = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// peak force slip angle
|
|
||||||
/// </summary>
|
|
||||||
public float ideal_slip_angle = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// positive during traction
|
|
||||||
/// </summary>
|
|
||||||
public float fx = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// positive during traction in a right turn
|
|
||||||
/// </summary>
|
|
||||||
public float fy = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// positive during traction in a left turn
|
|
||||||
/// </summary>
|
|
||||||
public float mz = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
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 = MathF.Min( normal_force * 0.001f, 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 Fx0 = Pacejka.PacejkaFx( sigma, Fz, s.friction );
|
|
||||||
float Fy0 = Pacejka.PacejkaFy( alpha, Fz, gamma, s.friction, out float camber_alpha );
|
|
||||||
|
|
||||||
// combined slip
|
|
||||||
float Gx = Pacejka.PacejkaGx( slip, slip_angle );
|
|
||||||
float Gy = Pacejka.PacejkaGy( slip, slip_angle );
|
|
||||||
float Fx = Gx * Fx0;
|
|
||||||
float Fy = Gy * Fy0;
|
|
||||||
|
|
||||||
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 )
|
public static float ComputeCamberVelocity( float sa, float vx )
|
||||||
{
|
{
|
||||||
float tansa = (1 / 3.0f * (sa * sa) + 1) * sa;
|
float tansa = (1 / 3.0f * (sa * sa) + 1) * sa;
|
||||||
|
|||||||
@ -1,10 +1,14 @@
|
|||||||
using Sandbox;
|
using Sandbox;
|
||||||
|
using Sandbox.Rendering;
|
||||||
using Sandbox.Services;
|
using Sandbox.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
using static Sandbox.CameraComponent;
|
using static Sandbox.CameraComponent;
|
||||||
|
using static Sandbox.Package;
|
||||||
|
using static Sandbox.SkinnedModelRenderer;
|
||||||
|
|
||||||
namespace VeloX;
|
namespace VeloX;
|
||||||
|
|
||||||
@ -40,7 +44,7 @@ public partial class VeloXWheel : Component
|
|||||||
public float Spin { get; private set; }
|
public float Spin { get; private set; }
|
||||||
|
|
||||||
public float RPM { get => angularVelocity * 30f / MathF.PI; set => angularVelocity = value / (30f / MathF.PI); }
|
public float RPM { get => angularVelocity * 30f / MathF.PI; set => angularVelocity = value / (30f / MathF.PI); }
|
||||||
public float AngularVelocity => angularVelocity;
|
public float AngularVelocity { get => angularVelocity; set => angularVelocity = value; }
|
||||||
|
|
||||||
internal float DistributionFactor { get; set; }
|
internal float DistributionFactor { get; set; }
|
||||||
|
|
||||||
@ -65,8 +69,12 @@ public partial class VeloXWheel : Component
|
|||||||
private Vector3 force;
|
private Vector3 force;
|
||||||
public float CounterTorque { get; private set; }
|
public float CounterTorque { get; private set; }
|
||||||
|
|
||||||
private float BaseInertia => Mass * MathF.Pow( Radius.InchToMeter(), 2 );
|
internal float BaseInertia => 0.5f * Mass * MathF.Pow( Radius.InchToMeter(), 2 );
|
||||||
public float Inertia => BaseInertia;
|
public float Inertia
|
||||||
|
{
|
||||||
|
get => BaseInertia + inertia;
|
||||||
|
set => inertia = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override void OnAwake()
|
protected override void OnAwake()
|
||||||
@ -83,12 +91,8 @@ public partial class VeloXWheel : Component
|
|||||||
|
|
||||||
private void UpdateVisuals( VeloXBase vehicle, in float dt )
|
private void UpdateVisuals( VeloXBase vehicle, in float dt )
|
||||||
{
|
{
|
||||||
var entityAngles = vehicle.WorldRotation;
|
Spin -= angularVelocity.RadianToDegree() * dt;
|
||||||
|
|
||||||
Spin -= angularVelocity.MeterToInch() * dt;
|
|
||||||
|
|
||||||
WorldRotation = vehicle.WorldTransform.RotationToWorld( GetSteer( vehicle.SteerAngle.yaw ) ) * Rotation.FromAxis( Vector3.Right, Spin );
|
WorldRotation = vehicle.WorldTransform.RotationToWorld( GetSteer( vehicle.SteerAngle.yaw ) ) * Rotation.FromAxis( Vector3.Right, Spin );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Rotation GetSteer( float steer )
|
private Rotation GetSteer( float steer )
|
||||||
@ -108,16 +112,14 @@ public partial class VeloXWheel : Component
|
|||||||
private static float GetLongitudinalLoadCoefficient( float load ) => 11000 * (1 - MathF.Exp( -0.00014f * load ));
|
private static float GetLongitudinalLoadCoefficient( float load ) => 11000 * (1 - MathF.Exp( -0.00014f * load ));
|
||||||
private static float GetLateralLoadCoefficient( float load ) => 18000 * (1 - MathF.Exp( -0.0001f * load ));
|
private static float GetLateralLoadCoefficient( float load ) => 18000 * (1 - MathF.Exp( -0.0001f * load ));
|
||||||
float lastload;
|
float lastload;
|
||||||
|
private float inertia;
|
||||||
|
|
||||||
public void DoPhysics( VeloXBase vehicle )
|
public void DoPhysics( VeloXBase vehicle )
|
||||||
{
|
{
|
||||||
var pos = vehicle.WorldTransform.PointToWorld( StartPos );
|
var pos = vehicle.WorldTransform.PointToWorld( StartPos );
|
||||||
|
|
||||||
var ang = vehicle.WorldTransform.RotationToWorld( GetSteer( vehicle.SteerAngle.yaw ) );
|
var ang = vehicle.WorldTransform.RotationToWorld( GetSteer( vehicle.SteerAngle.yaw ) );
|
||||||
|
|
||||||
forward = ang.Forward;
|
|
||||||
right = ang.Right;
|
|
||||||
up = ang.Up;
|
|
||||||
|
|
||||||
var maxLen = SuspensionLength;
|
var maxLen = SuspensionLength;
|
||||||
|
|
||||||
var endPos = pos + ang.Down * maxLen;
|
var endPos = pos + ang.Down * maxLen;
|
||||||
@ -129,6 +131,12 @@ public partial class VeloXWheel : Component
|
|||||||
.UseHitPosition( false )
|
.UseHitPosition( false )
|
||||||
.WithoutTags( vehicle.WheelIgnoredTags )
|
.WithoutTags( vehicle.WheelIgnoredTags )
|
||||||
.Run();
|
.Run();
|
||||||
|
//forward = ang.Forward;
|
||||||
|
//right = ang.Right;
|
||||||
|
up = ang.Up;
|
||||||
|
|
||||||
|
forward = Vector3.VectorPlaneProject( ang.Forward, Trace.Normal ).Normal;
|
||||||
|
right = Vector3.VectorPlaneProject( ang.Right, Trace.Normal ).Normal;
|
||||||
|
|
||||||
var fraction = Trace.Fraction;
|
var fraction = Trace.Fraction;
|
||||||
|
|
||||||
@ -141,7 +149,9 @@ public partial class VeloXWheel : Component
|
|||||||
|
|
||||||
var normal = Trace.Normal;
|
var normal = Trace.Normal;
|
||||||
|
|
||||||
var vel = vehicle.Body.GetVelocityAtPoint( pos );
|
var vel = vehicle.Body.GetVelocityAtPoint( contactPos );
|
||||||
|
|
||||||
|
//var vel = vehicle.Body.GetVelocityAtPoint( pos );
|
||||||
|
|
||||||
if ( !IsOnGround )
|
if ( !IsOnGround )
|
||||||
{
|
{
|
||||||
@ -191,76 +201,105 @@ public partial class VeloXWheel : Component
|
|||||||
|
|
||||||
float camber_rad = CamberAngle.DegreeToRadian();
|
float camber_rad = CamberAngle.DegreeToRadian();
|
||||||
float R = Radius.InchToMeter();
|
float R = Radius.InchToMeter();
|
||||||
TirePreset.ComputeState(
|
|
||||||
2500,
|
//TirePreset.ComputeState(
|
||||||
angularVelocity * R,
|
// load,
|
||||||
forwardSpeed,
|
// angularVelocity,
|
||||||
sideSpeed,
|
// forwardSpeed,
|
||||||
camber_rad,
|
// sideSpeed,
|
||||||
out var tireState
|
// camber_rad,
|
||||||
);
|
// R,
|
||||||
|
// Inertia,
|
||||||
|
// out var tireState
|
||||||
|
//);
|
||||||
|
|
||||||
float linearSpeed = angularVelocity * Radius.InchToMeter();
|
float linearSpeed = angularVelocity * Radius.InchToMeter();
|
||||||
float F_roll = TirePreset.GetRollingResistance( linearSpeed, 1.0f );
|
float F_roll = TirePreset.GetRollingResistance( linearSpeed, 1.0f );
|
||||||
F_roll = -MathF.Sign( forwardSpeed ) * F_roll;
|
F_roll *= -Math.Clamp( linearSpeed * 0.25f, -1, 1 );
|
||||||
|
|
||||||
float Fx_total = tireState.fx + F_roll;
|
//float Fx_total = tireState.fx + F_roll;
|
||||||
|
|
||||||
float T_brake = Brake * BrakePowerMax;
|
float T_brake = Brake * BrakePowerMax;
|
||||||
|
|
||||||
if ( angularVelocity > 0 ) T_brake = -T_brake;
|
if ( angularVelocity > 0 ) T_brake = -T_brake;
|
||||||
else T_brake = angularVelocity < 0 ? T_brake : -MathF.Sign( Torque ) * T_brake;
|
else T_brake = angularVelocity < 0 ? T_brake : -MathF.Sign( Torque ) * T_brake;
|
||||||
float totalTorque = Torque + T_brake - Fx_total * R;
|
//float totalTorque = Torque + tireState.fx;
|
||||||
|
|
||||||
// not work
|
angularVelocity += Torque / Inertia * Time.Delta;
|
||||||
Vector3 c = pos.Cross( forward );
|
angularVelocity += T_brake / Inertia * Time.Delta;
|
||||||
Vector3 v = (c * vehicle.Body.PhysicsBody.Inertia).Cross( pos );
|
angularVelocity += F_roll * 9.80665f / Inertia * Time.Delta;
|
||||||
var m = 1 / (1 / vehicle.Body.Mass + forward.Dot( v ));
|
TirePreset.ComputeSlip( forwardSpeed, sideSpeed, angularVelocity, R, out var slip, out var slip_ang );
|
||||||
m *= Inertia / (m * R * R + Inertia);
|
var fx = TirePreset.Pacejka.PacejkaFx( slip, load, 1, out var maxTorque );
|
||||||
float ve = forward.Dot( vel ).InchToMeter() - angularVelocity;
|
var fy = TirePreset.Pacejka.PacejkaFy( slip_ang * load, load, camber_rad, 1, out var _ );
|
||||||
|
|
||||||
angularVelocity += ve * m * Radius * (1 / Inertia);// totalTorque * (1 / Inertia) * Time.Delta;
|
maxTorque *= R;
|
||||||
|
var errorTorque = (angularVelocity - forwardSpeed / R) * Inertia / Time.Delta;
|
||||||
|
|
||||||
|
var surfaceTorque = Math.Clamp( errorTorque, -maxTorque, maxTorque );
|
||||||
|
|
||||||
|
angularVelocity -= surfaceTorque / Inertia * Time.Delta;
|
||||||
|
|
||||||
forwardFriction = new Friction()
|
forwardFriction = new Friction()
|
||||||
{
|
{
|
||||||
Slip = tireState.slip,
|
Slip = slip,
|
||||||
Force = Fx_total,
|
Force = -fx,
|
||||||
Speed = forwardSpeed
|
Speed = forwardSpeed
|
||||||
};
|
};
|
||||||
|
|
||||||
sideFriction = new Friction()
|
sideFriction = new Friction()
|
||||||
{
|
{
|
||||||
Slip = tireState.slip_angle,
|
Slip = slip_ang,
|
||||||
Force = tireState.fy,
|
Force = fy,
|
||||||
Speed = sideSpeed
|
Speed = sideSpeed
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector3 frictionForce = forward * forwardFriction.Force + right * sideFriction.Force;
|
Vector3 frictionForce = forward * forwardFriction.Force + right * sideFriction.Force;
|
||||||
vehicle.Body.ApplyForceAt( contactPos, (force + frictionForce) / Time.Delta );
|
|
||||||
|
vehicle.Body.ApplyForceAt( pos, force / Time.Delta * ProjectSettings.Physics.SubSteps );
|
||||||
|
vehicle.Body.ApplyForceAt( pos, frictionForce * ProjectSettings.Physics.SubSteps );
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo
|
||||||
|
protected (float Mass, float Inertia) CalcMassAndInertia()
|
||||||
{
|
{
|
||||||
// Колесо в воздухе: сбрасываем силы
|
// section width in millimeters, measured from sidewall to sidewall
|
||||||
forwardFriction = new Friction();
|
// ratio of sidewall height to section width in percent
|
||||||
sideFriction = new Friction();
|
// diameter of the wheel in inches
|
||||||
|
var tire_size = new Vector3( 215, 45, 17 );
|
||||||
|
|
||||||
// Обновление угловой скорости только от мотора/тормозов
|
float tire_width = tire_size[0] * 0.001f;
|
||||||
float T_brake = Brake * BrakePowerMax;
|
float tire_aspect_ratio = tire_size[1] * 0.01f;
|
||||||
|
float tire_radius = tire_size[2] * 0.5f * 0.0254f + tire_width * tire_aspect_ratio;
|
||||||
|
float tire_thickness = 0.02f;
|
||||||
|
float tire_density = 1000; // rubber
|
||||||
|
|
||||||
if ( angularVelocity > 0 ) T_brake = -T_brake;
|
float rim_radius = tire_radius - tire_width * tire_aspect_ratio;
|
||||||
else T_brake = angularVelocity < 0 ? T_brake : -MathF.Sign( Torque ) * T_brake;
|
float rim_width = tire_width;
|
||||||
angularVelocity += (Torque + T_brake) / Inertia * Time.Delta;
|
float rim_thickness = 0.01f;
|
||||||
|
float rim_density = 2700; // aluminium
|
||||||
|
|
||||||
|
float tire_volume = float.Pi * tire_width * tire_thickness * (2 * tire_radius - tire_thickness);
|
||||||
|
float rim_volume = float.Pi * rim_width * rim_thickness * (2 * rim_radius - rim_thickness);
|
||||||
|
float tire_mass = tire_density * tire_volume;
|
||||||
|
float rim_mass = rim_density * rim_volume;
|
||||||
|
float tire_inertia = tire_mass * tire_radius * tire_radius;
|
||||||
|
float rim_inertia = rim_mass * rim_radius * rim_radius;
|
||||||
|
|
||||||
|
float mass = tire_mass + rim_mass;
|
||||||
|
float inertia = tire_inertia + rim_inertia;
|
||||||
|
|
||||||
|
return (mass, inertia);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// debug
|
// debug
|
||||||
protected override void OnUpdate()
|
protected override void OnUpdate()
|
||||||
{
|
{
|
||||||
DebugOverlay.Normal( contactPos, forward * forwardFriction.Force / 100f, Color.Red, overlay: true );
|
DebugOverlay.Normal( contactPos, forward * forwardFriction.Force / 1000f, Color.Red, overlay: true );
|
||||||
DebugOverlay.Normal( contactPos, right * sideFriction.Force / 100f, Color.Green, overlay: true );
|
DebugOverlay.Normal( contactPos, right * sideFriction.Force / 1000f, Color.Green, overlay: true );
|
||||||
DebugOverlay.Normal( contactPos, up * force / 1000f, Color.Blue, overlay: true );
|
DebugOverlay.Normal( contactPos, up * force / 1000f, Color.Blue, overlay: true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,33 +14,40 @@ public partial class VeloXCar
|
|||||||
[Property, Feature( "Steer" )] public float MaxSteerAngle { get; set; } = 35f;
|
[Property, Feature( "Steer" )] public float MaxSteerAngle { get; set; } = 35f;
|
||||||
|
|
||||||
[Sync] public float Steering { get; private set; }
|
[Sync] public float Steering { get; private set; }
|
||||||
private float jTurnMultiplier;
|
|
||||||
|
|
||||||
private float inputSteer;
|
private float inputSteer;
|
||||||
|
|
||||||
|
public static float SignedAngle( Vector3 from, Vector3 to, Vector3 axis )
|
||||||
|
{
|
||||||
|
float unsignedAngle = Vector3.GetAngle( from, to );
|
||||||
|
|
||||||
|
float cross_x = from.y * to.z - from.z * to.y;
|
||||||
|
float cross_y = from.z * to.x - from.x * to.z;
|
||||||
|
float cross_z = from.x * to.y - from.y * to.x;
|
||||||
|
float sign = MathF.Sign( axis.x * cross_x + axis.y * cross_y + axis.z * cross_z );
|
||||||
|
return unsignedAngle * sign;
|
||||||
|
}
|
||||||
|
public float VelocityAngle { get; private set; }
|
||||||
|
public int CarDirection { get { return ForwardSpeed.InchToMeter() < 5 ? 0 : (VelocityAngle < 90 && VelocityAngle > -90 ? 1 : -1); } }
|
||||||
private void UpdateSteering( float dt )
|
private void UpdateSteering( float dt )
|
||||||
{
|
{
|
||||||
var inputSteer = Input.AnalogMove.y;
|
var inputSteer = Input.AnalogMove.y;
|
||||||
var absInputSteer = Math.Abs( inputSteer );
|
|
||||||
|
|
||||||
var sideSlip = Math.Clamp( avgSideSlip, -1, 1 );
|
|
||||||
|
VelocityAngle = -SignedAngle( Body.Velocity, WorldRotation.Forward, WorldRotation.Up );
|
||||||
|
|
||||||
var steerConeFactor = Math.Clamp( TotalSpeed / SteerConeMaxSpeed, 0, 1 );
|
var steerConeFactor = Math.Clamp( TotalSpeed / SteerConeMaxSpeed, 0, 1 );
|
||||||
var steerCone = 1 - steerConeFactor * (1 - SteerConeMaxAngle);
|
var steerCone = 1 - steerConeFactor * (1 - SteerConeMaxAngle);
|
||||||
|
|
||||||
steerCone = Math.Clamp( steerCone, Math.Abs( sideSlip ), 1 );
|
|
||||||
|
|
||||||
inputSteer = ExpDecay( this.inputSteer, inputSteer * steerCone, SteerConeChangeRate, dt );
|
inputSteer = ExpDecay( this.inputSteer, inputSteer * steerCone, SteerConeChangeRate, dt );
|
||||||
this.inputSteer = inputSteer;
|
this.inputSteer = inputSteer;
|
||||||
var counterSteer = sideSlip * steerConeFactor * (1 - absInputSteer);
|
|
||||||
counterSteer = Math.Clamp( counterSteer, -1, 1 ) * CounterSteer;
|
|
||||||
|
|
||||||
inputSteer = Math.Clamp( inputSteer + counterSteer, -1, 1 );
|
float target = -inputSteer * MaxSteerAngle;
|
||||||
|
if ( CarDirection > 0 )
|
||||||
|
target -= VelocityAngle * CounterSteer;
|
||||||
|
|
||||||
|
inputSteer = Math.Clamp( inputSteer, -1, 1 );
|
||||||
Steering = inputSteer;
|
Steering = inputSteer;
|
||||||
SteerAngle = new( 0, -inputSteer * MaxSteerAngle, 0 );
|
SteerAngle = new( 0, target, 0 );
|
||||||
|
|
||||||
if ( ForwardSpeed < -100 )
|
|
||||||
jTurnMultiplier = 0.5f;
|
|
||||||
else
|
|
||||||
jTurnMultiplier = ExpDecay( jTurnMultiplier, 1, 2, dt );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,27 +2,9 @@
|
|||||||
|
|
||||||
public partial class VeloXCar
|
public partial class VeloXCar
|
||||||
{
|
{
|
||||||
private float avgSideSlip;
|
|
||||||
private float avgPoweredRPM;
|
|
||||||
private float avgForwardSlip;
|
|
||||||
private void WheelThink( in float dt )
|
private void WheelThink( in float dt )
|
||||||
{
|
{
|
||||||
float avgRPM = 0, totalSideSlip = 0, totalForwardSlip = 0;
|
|
||||||
|
|
||||||
foreach ( var w in Wheels )
|
foreach ( var w in Wheels )
|
||||||
{
|
|
||||||
w.Update( this, dt );
|
w.Update( this, dt );
|
||||||
|
|
||||||
totalSideSlip += w.SideSlip;
|
|
||||||
totalForwardSlip += w.ForwardSlip;
|
|
||||||
var rpm = w.RPM;
|
|
||||||
|
|
||||||
avgRPM += rpm * w.DistributionFactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
avgPoweredRPM = avgRPM;
|
|
||||||
avgSideSlip = totalSideSlip / Wheels.Count;
|
|
||||||
avgForwardSlip = totalForwardSlip / Wheels.Count;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,32 +7,6 @@ namespace VeloX;
|
|||||||
[Title( "VeloX - Car" )]
|
[Title( "VeloX - Car" )]
|
||||||
public partial class VeloXCar : VeloXBase
|
public partial class VeloXCar : VeloXBase
|
||||||
{
|
{
|
||||||
protected override void OnStart()
|
|
||||||
{
|
|
||||||
base.OnStart();
|
|
||||||
//StreamPlayer = new( Stream );
|
|
||||||
//if ( IsDriver )
|
|
||||||
//{
|
|
||||||
// UpdateGearList();
|
|
||||||
// UpdatePowerDistribution();
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnUpdate()
|
|
||||||
{
|
|
||||||
base.OnUpdate();
|
|
||||||
//if ( StreamPlayer is not null )
|
|
||||||
//{
|
|
||||||
|
|
||||||
// StreamPlayer.Throttle = Throttle;
|
|
||||||
// StreamPlayer.RPMPercent = RPMPercent;
|
|
||||||
// StreamPlayer.EngineState = EngineState;
|
|
||||||
// StreamPlayer.IsRedlining = IsRedlining;
|
|
||||||
|
|
||||||
// StreamPlayer.Update( Time.Delta, WorldPosition );
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
|
||||||
protected override void OnFixedUpdate()
|
protected override void OnFixedUpdate()
|
||||||
{
|
{
|
||||||
if ( !IsDriver )
|
if ( !IsDriver )
|
||||||
|
|||||||
@ -17,7 +17,7 @@ public class PacejkaWidget : ControlObjectWidget
|
|||||||
Layout = Layout.Column();
|
Layout = Layout.Column();
|
||||||
Layout.Margin = 8f;
|
Layout.Margin = 8f;
|
||||||
Layout.Spacing = 8;
|
Layout.Spacing = 8;
|
||||||
foreach ( var item in TypeLibrary.GetType<Pacejka.LateralForce>().Fields )
|
foreach ( var item in TypeLibrary.GetType<Pacejka.LateralForce>().Properties )
|
||||||
{
|
{
|
||||||
var row = Layout.AddRow();
|
var row = Layout.AddRow();
|
||||||
row.Spacing = 8;
|
row.Spacing = 8;
|
||||||
@ -36,7 +36,7 @@ public class PacejkaWidget : ControlObjectWidget
|
|||||||
Layout = Layout.Column();
|
Layout = Layout.Column();
|
||||||
Layout.Margin = 8f;
|
Layout.Margin = 8f;
|
||||||
Layout.Spacing = 8;
|
Layout.Spacing = 8;
|
||||||
foreach ( var item in TypeLibrary.GetType<Pacejka.LongitudinalForce>().Fields )
|
foreach ( var item in TypeLibrary.GetType<Pacejka.LongitudinalForce>().Properties )
|
||||||
{
|
{
|
||||||
var row = Layout.AddRow();
|
var row = Layout.AddRow();
|
||||||
row.Spacing = 8;
|
row.Spacing = 8;
|
||||||
@ -55,7 +55,7 @@ public class PacejkaWidget : ControlObjectWidget
|
|||||||
Layout = Layout.Column();
|
Layout = Layout.Column();
|
||||||
Layout.Margin = 8f;
|
Layout.Margin = 8f;
|
||||||
Layout.Spacing = 8;
|
Layout.Spacing = 8;
|
||||||
foreach ( var item in TypeLibrary.GetType<Pacejka.AligningMoment>().Fields )
|
foreach ( var item in TypeLibrary.GetType<Pacejka.AligningMoment>().Properties )
|
||||||
{
|
{
|
||||||
var row = Layout.AddRow();
|
var row = Layout.AddRow();
|
||||||
row.Spacing = 8;
|
row.Spacing = 8;
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
using Editor;
|
using Editor;
|
||||||
using Editor.Assets;
|
using Editor.Assets;
|
||||||
using Editor.Inspectors;
|
using Editor.Inspectors;
|
||||||
using Editor.ShaderGraph.Nodes;
|
|
||||||
using Sandbox;
|
using Sandbox;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -68,15 +67,12 @@ class TirePresetPreview( Asset asset ) : PixmapAssetPreview( asset )
|
|||||||
for ( float x = x0; x <= xn; x += (xn - x0) / points )
|
for ( float x = x0; x <= xn; x += (xn - x0) / points )
|
||||||
{
|
{
|
||||||
|
|
||||||
float yval = tire.PacejkaFy( x, load, Camber, 1.0f, out float maxforce ) / load;
|
float yval = tire.PacejkaFy( x, load, Camber, 1.0f, out float _ ) / load;
|
||||||
float xval = width * (x - x0) / (xn - x0);
|
float xval = width * (x - x0) / (xn - x0);
|
||||||
yval /= ymax - ymin;
|
yval /= ymax - ymin;
|
||||||
yval = (yval + 1.0f) * 0.5f;
|
yval = (yval + 1.0f) * 0.5f;
|
||||||
yval = 1.0f - yval;
|
yval = 1.0f - yval;
|
||||||
yval *= height;
|
yval *= height;
|
||||||
if ( x == x0 )
|
|
||||||
pointCache.Add( new( xval, yval ) );
|
|
||||||
else
|
|
||||||
pointCache.Add( new( xval, yval ) );
|
pointCache.Add( new( xval, yval ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,6 +82,29 @@ class TirePresetPreview( Asset asset ) : PixmapAssetPreview( asset )
|
|||||||
{ // draw longitudinal line
|
{ // draw longitudinal line
|
||||||
pointCache.Clear();
|
pointCache.Clear();
|
||||||
|
|
||||||
|
Paint.SetPen( Color.Green, 1 );
|
||||||
|
float x0 = -zoom * 0.5f;
|
||||||
|
float xn = zoom * 0.5f;
|
||||||
|
float ymin = -1000.0f;
|
||||||
|
float ymax = 1000.0f;
|
||||||
|
int points = 500;
|
||||||
|
|
||||||
|
for ( float x = x0; x <= xn; x += (xn - x0) / points )
|
||||||
|
{
|
||||||
|
float yval = tire.PacejkaFx( x, load, 1.0f, out var _ ) / load;
|
||||||
|
float xval = width * (x - x0) / (xn - x0);
|
||||||
|
yval /= ymax - ymin;
|
||||||
|
yval = (yval + 1.0f) * 0.5f;
|
||||||
|
yval = 1.0f - yval;
|
||||||
|
yval *= height;
|
||||||
|
pointCache.Add( new( xval, yval ) );
|
||||||
|
}
|
||||||
|
Paint.DrawLine( pointCache );
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // draw aligning line
|
||||||
|
pointCache.Clear();
|
||||||
|
|
||||||
Paint.SetPen( Color.Blue, 1 );
|
Paint.SetPen( Color.Blue, 1 );
|
||||||
float x0 = -zoom * 0.5f * 10.0f;
|
float x0 = -zoom * 0.5f * 10.0f;
|
||||||
float xn = zoom * 0.5f * 10.0f;
|
float xn = zoom * 0.5f * 10.0f;
|
||||||
@ -101,35 +120,6 @@ class TirePresetPreview( Asset asset ) : PixmapAssetPreview( asset )
|
|||||||
yval = (yval + 1.0f) * 0.5f;
|
yval = (yval + 1.0f) * 0.5f;
|
||||||
yval = 1.0f - yval;
|
yval = 1.0f - yval;
|
||||||
yval *= height;
|
yval *= height;
|
||||||
if ( x == x0 )
|
|
||||||
pointCache.Add( new( xval, yval ) );
|
|
||||||
else
|
|
||||||
pointCache.Add( new( xval, yval ) );
|
|
||||||
}
|
|
||||||
Paint.DrawLine( pointCache );
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // draw aligning line
|
|
||||||
pointCache.Clear();
|
|
||||||
|
|
||||||
Paint.SetPen( Color.Green, 1 );
|
|
||||||
float x0 = -zoom * 0.5f;
|
|
||||||
float xn = zoom * 0.5f;
|
|
||||||
float ymin = -1000.0f;
|
|
||||||
float ymax = 1000.0f;
|
|
||||||
int points = 500;
|
|
||||||
|
|
||||||
for ( float x = x0; x <= xn; x += (xn - x0) / points )
|
|
||||||
{
|
|
||||||
float yval = tire.PacejkaFx( x, load, 1.0f ) / load;
|
|
||||||
float xval = width * (x - x0) / (xn - x0);
|
|
||||||
yval /= ymax - ymin;
|
|
||||||
yval = (yval + 1.0f) * 0.5f;
|
|
||||||
yval = 1.0f - yval;
|
|
||||||
yval *= height;
|
|
||||||
if ( x == x0 )
|
|
||||||
pointCache.Add( new( xval, yval ) );
|
|
||||||
else
|
|
||||||
pointCache.Add( new( xval, yval ) );
|
pointCache.Add( new( xval, yval ) );
|
||||||
}
|
}
|
||||||
Paint.DrawLine( pointCache );
|
Paint.DrawLine( pointCache );
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user