assets and etc.

This commit is contained in:
2025-11-08 17:05:04 +07:00
parent ae5cd2c8b6
commit ab8cc70785
12 changed files with 63 additions and 104 deletions

View File

@@ -34,12 +34,9 @@ public partial class VeloXWheel
/// </summary>
public float CounterTorque { get; private set; }
[Property, Sync] public bool AutoSetFriction { get; set; } = true;
[Property, Sync] public bool UseGroundVelocity { get; set; } = true;
[Property, Range( 0, 2 )] public float BrakeMult { get; set; } = 1f;
[Property] public Friction ForwardFriction = new();
[Property] public Friction SidewayFriction = new();
public Friction ForwardFriction = new();
public Friction SidewayFriction = new();
public Vector3 FrictionForce;
@@ -102,8 +99,6 @@ public partial class VeloXWheel
private Vector3 correctiveForce;
private void UpdateFriction( float dt )
{
var motorTorque = DriveTorque;
var brakeTorque = BrakeTorque * BrakeMult;
@@ -151,7 +146,7 @@ public partial class VeloXWheel
float absMotorTorque = Math.Abs( motorTorque );
float absBrakeTorque = Math.Abs( brakeTorque );
float maxForwardForce = Tire.Evaluate( Math.Abs( ForwardFriction.Slip ) ) * Math.Min( peakForwardFrictionForce, forwardForceClamp );
float maxForwardForce = Math.Min( peakForwardFrictionForce, forwardForceClamp );
maxForwardForce = absMotorTorque < absBrakeTorque ? maxForwardForce : peakForwardFrictionForce;
ForwardFriction.Force = forwardInputForce > maxForwardForce ? maxForwardForce
@@ -204,7 +199,7 @@ public partial class VeloXWheel
ForwardFriction.Slip = (ForwardFriction.Speed - AngularVelocity * mRadius) / clampedAbsForwardSpeed;
ForwardFriction.Slip *= slipLoadModifier;
SidewayFriction.Slip = MathF.Atan2( SidewayFriction.Speed, clampedAbsForwardSpeed ).RadianToDegree() * 0.01111f;
SidewayFriction.Slip = MathF.Atan2( SidewayFriction.Speed, clampedAbsForwardSpeed );
SidewayFriction.Slip *= slipLoadModifier;
float sideSlipSign = SidewayFriction.Slip > 0 ? 1 : -1;
@@ -288,7 +283,8 @@ public partial class VeloXWheel
//DebugOverlay.Normal( WorldPosition, hitSidewaysDirection * 10, overlay: true );
//DebugOverlay.Normal( WorldPosition, hitForwardDirection * 10, overlay: true );
//DebugOverlay.Normal( WorldPosition, FrictionForce / 100, overlay: true );
//DebugOverlay.Normal( ContactPosition, ContactNormal * 10, overlay: true );
//DebugOverlay.Normal( ContactPosition, Vector3.Up * AngularVelocity, overlay: true );
//DebugOverlay.Sphere( new( ContactPosition, 4 ), overlay: true );
//Vehicle.Body.ApplyForceAt( ContactPosition, FrictionForce );

View File

@@ -5,7 +5,9 @@ namespace VeloX;
public partial class VeloXWheel : Component
{
protected override void DrawGizmos()
protected override void DrawGizmos() => GizmoDraw();
public void GizmoDraw()
{
if ( !Gizmo.IsSelected )
@@ -60,15 +62,5 @@ public partial class VeloXWheel : Component
}
}
////
//// Forward direction
////
//{
// var arrowStart = Vector3.Forward * Radius.MeterToInch();
// var arrowEnd = arrowStart + Vector3.Forward * 8f;
// Gizmo.Draw.Color = Color.Red;
// Gizmo.Draw.Arrow( arrowStart, arrowEnd, 4, 1 );
//}
}
}

View File

@@ -47,6 +47,7 @@ public partial class VeloXWheel
_skidMark.AutoCalculateNormals = false;
_skidMark.SplineInterpolation = 4;
go.Flags = go.Flags.WithFlag( GameObjectFlags.Hidden, true );
go.Flags = go.Flags.WithFlag( GameObjectFlags.NotNetworked, true );
SkidMarks.Enqueue( _skidMark );
}
@@ -84,6 +85,7 @@ public partial class VeloXWheel
WorldRotation = Rotation.LookAt( ContactNormal.RotateAround( Vector3.Zero, Rotation.FromRoll( 90 ) ) )
};
go.Flags = go.Flags.WithFlag( GameObjectFlags.Hidden, true );
go.Flags = go.Flags.WithFlag( GameObjectFlags.NotNetworked, true );
_skidMark.Points.Add( go );
}
}

View File

@@ -32,10 +32,9 @@ public partial class VeloXWheel
var val = Math.Abs( LateralSlip ) + Math.Abs( LongitudinalSlip );
timeMul = timeMul.LerpTo( val, 0.1f );
if ( timeMul > 2 )
return val;
return 0;
//if ( timeMul > 2 )
// return val;
return val * 5;
}
protected override void OnUpdate()
{
@@ -78,7 +77,7 @@ public partial class VeloXWheel
{
Type = ParticleFloat.ValueType.Curve,
Evaluation = ParticleFloat.EvaluationType.Life,
CurveA = new( new List<Curve.Frame>() { new( 0, 10f ), new( 0.8f, 50f ), new( 1f, 160f * sizeMul ) } ),
CurveA = new( new List<Curve.Frame>() { new( 0, 10f ), new( 0.8f, 50f ), new( 1f, 160f ) } ),
};
effect.StartDelay = 0.025f + (1 - smokeMul) * 0.03f;
@@ -98,7 +97,7 @@ public partial class VeloXWheel
ConstantB = 70,
};
effect.Force = true;
effect.InitialVelocity = hitForwardDirection * LongitudinalSlip * 10f;
effect.InitialVelocity = Vehicle.Body.Velocity / 3 + hitForwardDirection * LongitudinalSlip * 10f;
effect.ForceDirection = 0;
effect.SheetSequence = true;
effect.SequenceSpeed = 0.5f;

View File

@@ -24,15 +24,10 @@ public partial class VeloXWheel : Component
public float BaseInertia => Mass * (Radius * Radius); // kg·m²
[Property] public float Inertia { get; set; } = 1.5f; // kg·m²
public float SideSlip => SlipAngle;
public float ForwardSlip => DynamicSlipRatio;
[Sync] public float Torque { get; set; }
[Sync, Range( 0, 1 )] public float Brake { get; set; }
[Property] public bool IsFront { get; protected set; }
[Property] public float SteerMultiplier { get; set; }
public float RPM { get => AngularVelocity * 60f / MathF.Tau; set => AngularVelocity = value / (60 / MathF.Tau); }
[Sync] internal float DistributionFactor { get; set; }
private Vector3 StartPos { get; set; }
private static Rotation CylinderOffset = Rotation.FromRoll( 90 );
@@ -40,25 +35,19 @@ public partial class VeloXWheel : Component
[Sync] public bool IsOnGround { get; private set; }
[Property] public float DriveTorque => Torque;
[Property] public float BrakeTorque => Brake * 5000f;
[Property] public float DriveTorque { get; set; }
[Property] public float BrakeTorque { get; set; }
public float Compression { get; protected set; } // meters
public float LastLength { get; protected set; } // meters
public float Fz { get; protected set; } // N
public float AngularVelocity { get; protected set; } // rad/s
public float Fx { get; protected set; } // N
public float Fy { get; protected set; } // N
public float RollAngle { get; protected set; } // degrees
private VeloXBase Vehicle;
[Sync] public Vector3 ContactNormal { get; protected set; }
[Sync] public Vector3 ContactPosition { get; protected set; }
public float SlipRatio { get; protected set; }
public float SlipAngle { get; protected set; }
public float DynamicSlipRatio { get; protected set; }
public float DynamicSlipAngle { get; protected set; }
Rotation TransformRotationSteer => Vehicle.WorldTransform.RotationToWorld( Vehicle.SteerAngle * SteerMultiplier );
protected override void OnAwake()
@@ -96,15 +85,9 @@ public partial class VeloXWheel : Component
internal void StepPhys( VeloXBase vehicle, in float dt )
{
var _rigidbody = vehicle.Body;
const int numSamples = 3;
float halfWidth = Width.MeterToInch() * 0.5f;
var ang = vehicle.WorldTransform.RotationToWorld( vehicle.SteerAngle * SteerMultiplier );
Vector3 right = Vector3.VectorPlaneProject( ang.Right, Vector3.Up ).Normal;
int hitCount = 0;
WheelTraceData wheelTraceData = new();
for ( int i = 0; i < numSamples; i++ )
@@ -123,7 +106,6 @@ public partial class VeloXWheel : Component
IsOnGround = true;
//// Average all contacts
Fz = Math.Max( wheelTraceData.Force / hitCount, 0 );
Compression = wheelTraceData.Compression / hitCount;
ContactNormal = (wheelTraceData.ContactNormal / hitCount).Normal;
@@ -131,32 +113,7 @@ public partial class VeloXWheel : Component
//DoSuspensionSounds( vehicle, (RestLength - Compression) * 0.8f);
LastLength = RestLength - Compression;
//DebugOverlay.Normal( ContactPosition, ContactNormal * Fz / 1000 );
// Apply suspension force
//_rigidbody.ApplyForceAt( ContactPosition, ContactNormal * Fz.MeterToInch() );
UpdateHitVariables();
// Friction
Vector3 forward = ContactNormal.Cross( right ).Normal;
right = Rotation.FromAxis( ContactNormal, 90f ) * forward;
var velAtContact = _rigidbody.GetVelocityAtPoint( ContactPosition + vehicle.Body.MassCenter ) * 0.0254f;
float vx = Vector3.Dot( velAtContact, forward );
float vy = Vector3.Dot( velAtContact, right );
float wheelLinearVel = AngularVelocity * Radius;
float creepVel = 0.5f;
SlipRatio = (wheelLinearVel - vx) / (MathF.Abs( vx ) + creepVel);
SlipAngle = MathX.RadianToDegree( MathF.Atan2( vy, MathF.Abs( vx ) + creepVel ) );
float latCoeff = 1.0f - MathF.Exp( -MathF.Max( MathF.Abs( vx ), 1f ) * dt / 0.01f );
float longCoeff = 1.0f - MathF.Exp( -MathF.Max( MathF.Abs( vx ), 1f ) * dt / 0.01f );
DynamicSlipAngle += (SlipAngle - DynamicSlipAngle) * latCoeff;
DynamicSlipRatio += (SlipRatio - DynamicSlipRatio) * longCoeff;
UpdateFriction( dt );
}
else
@@ -165,8 +122,6 @@ public partial class VeloXWheel : Component
// Wheel is off the ground
Compression = 0f;
Fz = 0f;
Fx = 0f;
Fy = 0f;
ContactNormal = Vector3.Up;
ContactPosition = WorldPosition;
}
@@ -225,22 +180,20 @@ public partial class VeloXWheel : Component
{
if ( IsProxy )
return;
StepRotation( Vehicle, dt );
if ( AutoSimulate )
StepPhys( Vehicle, dt );
StepRotation( Vehicle, dt );
}
const float HubCoulombNm = 20f;
const float HubViscous = 0.1f;
private void StepRotation( VeloXBase vehicle, in float dt )
{
float inertia = MathF.Max( 1f, Inertia );
float roadTorque = Fx * Radius;
float roadTorque = ForwardFriction.Speed * Radius;
float externalTorque = DriveTorque - roadTorque;
float rollingResistanceTorque = Fz * Radius * SurfaceResistance;
const float HubCoulombNm = 20f;
const float HubViscous = 0.1f;
float coulombTorque = BrakeTorque + rollingResistanceTorque + HubCoulombNm;
float omega = AngularVelocity;
@@ -251,11 +204,8 @@ public partial class VeloXWheel : Component
}
else
{
// viscous decay
if ( HubViscous > 0f ) omega *= MathF.Exp( -(HubViscous / inertia) * dt );
// Coulomb drag
if ( coulombTorque > 0f && omega != 0f )
{
float dir = MathF.Sign( omega );
@@ -266,7 +216,7 @@ public partial class VeloXWheel : Component
if ( MathF.Abs( omega ) < 0.01f ) omega = 0f;
}
AngularVelocity = omega; // wider sanity range
AngularVelocity = omega;
RollAngle += MathX.RadianToDegree( AngularVelocity ) * dt;
RollAngle = (RollAngle % 360f + 360f) % 360f;