Class StandardFriction
Default friction implementation using Pacejka-based curves for tire force calculations. Uses a semi-implicit Newton-Raphson solver for stable equilibrium convergence in 2-3 iterations. Includes static friction anchoring with critical damping for low-speed stability.
Inherited Members
Namespace: NWH.WheelController3D
Assembly: NWH.WheelController.dll
Syntax
[DisallowMultipleComponent]
public class StandardFriction : FrictionBase
Fields
| Edit this page View Source_prevForceX
Previous-substep longitudinal force, filtered by relaxation length (N).
Declaration
[NonSerialized]
public float _prevForceX
Field Value
| Type | Description |
|---|---|
| float |
_prevForceY
Previous-substep lateral force, filtered by relaxation length (N).
Declaration
[NonSerialized]
public float _prevForceY
Field Value
| Type | Description |
|---|---|
| float |
_staticFrictionPoint
World-space static friction anchor used when the contact surface has no transform to track.
Declaration
[NonSerialized]
public Vector3 _staticFrictionPoint
Field Value
| Type | Description |
|---|---|
| Vector3 |
absPulseInterval
ABS pump cycle (s): the brake modifier is sampled then held this long. 0 = resample every substep.
Declaration
[Range(0, 0.2)]
[Tooltip("ABS pump cycle interval (s). Brake modifier is sampled then held for this long, like a real pump (0.05 = 20 Hz). 0 = resample every substep.")]
public float absPulseInterval
Field Value
| Type | Description |
|---|---|
| float |
brakeBlendThreshold
Wheel angular-velocity threshold (rad/s) below which brake force direction is blended to avoid sign flips.
Declaration
[Tooltip("Angular velocity threshold for brake direction blending (rad/s).")]
public float brakeBlendThreshold
Field Value
| Type | Description |
|---|---|
| float |
brakeLockThreshold
Minimum brake torque (Nm) before wheel-lock handling is evaluated.
Declaration
[Tooltip("Minimum brake torque to trigger wheel lock checks (Nm).")]
public float brakeLockThreshold
Field Value
| Type | Description |
|---|---|
| float |
camberGripFalloff
Grip lost per squared degree of camber away from optimal. 0 = off; keep 0 for motorcycles.
Declaration
[Range(0, 0.05)]
[Tooltip("Grip lost per squared degree of camber away from optimal. 0 = off. Keep 0 for motorcycles.")]
public float camberGripFalloff
Field Value
| Type | Description |
|---|---|
| float |
ellipseLateralPriority
On ellipse overflow at very low speed / brake-lock, how much lateral force is preserved before longitudinal. 0 = symmetric clamp; 1 = lateral keeps full capacity, longitudinal takes the remainder. Keeps a locked wheel (handbrake) holding sideways on a cross-slope instead of trading lateral grip for brake reaction.
Declaration
[Range(0, 1)]
[Tooltip("On ellipse overflow at low speed / brake-lock, how much lateral grip is preserved before longitudinal. 0 = symmetric (default model). 1 = full lateral priority. Helps a locked wheel hold across a slope.")]
public float ellipseLateralPriority
Field Value
| Type | Description |
|---|---|
| float |
frictionEllipticity
Friction-ellipse shape for combined slip. 1 = circle; above 1 degrades lateral grip faster under combined load.
Declaration
[Range(0.5, 2)]
[Tooltip("Friction ellipse shape. 1.0 = circle (default). >1.0 = lateral forces degrade faster under combined loading (realistic). <1.0 = more forgiving.")]
public float frictionEllipticity
Field Value
| Type | Description |
|---|---|
| float |
grip
Per-axis friction force multiplier (X = longitudinal, Y = lateral). Scales the Y of the friction curve.
Declaration
[Tooltip("Multiplies the calculated friction force (Y-axis of curve). X=Longitudinal, Y=Lateral.")]
public Vector2 grip
Field Value
| Type | Description |
|---|---|
| Vector2 |
lateralLowSpeedMinScale
Minimum lateral slip scale at the static/dynamic transition. 1 = no low-speed lateral trim (recovers grip at the handoff); lower trims lateral force there. Lateral is not in the Newton solver, so trimming is optional.
Declaration
[Range(0, 1)]
[Tooltip("Minimum lateral slip scale at the static/dynamic transition. 1.0 = no trim (recovers grip at handoff). Lower trims lateral force at the transition.")]
public float lateralLowSpeedMinScale
Field Value
| Type | Description |
|---|---|
| float |
loadPeakSlipShift
How much the slip at peak grip grows with load. Loaded tires peak later and softer; 0 = load-independent.
Declaration
[Range(0, 1)]
[Tooltip("How much the slip needed for peak grip grows with load. Loaded tires peak later and respond softer, light tires sharper. 0 = off.")]
public float loadPeakSlipShift
Field Value
| Type | Description |
|---|---|
| float |
loadSensitivity
How grip scales with load, per axis. 1 = linear; below 1 gives diminishing returns with load (realistic).
Declaration
[Tooltip("How much friction increases with load. 1.0 = Linear. <1.0 = Diminishing returns (realistic).")]
public Vector2 loadSensitivity
Field Value
| Type | Description |
|---|---|
| Vector2 |
lowSpeedLateralGripFloor
Closes the static→dynamic lateral grip cliff: at low slide speed the lateral force is blended toward the slope-hold force (up to this fraction of available grip) immediately, instead of waiting for slip to build over the slide. 0 = off (original ramp). Fades out above the static-entry speed.
Declaration
[Range(0, 1)]
[Tooltip("At low slide speed, build lateral force toward the slope-hold force up to this fraction of grip immediately, instead of waiting for slip to develop. Closes the static->dynamic grip cliff. 0 = off.")]
public float lowSpeedLateralGripFloor
Field Value
| Type | Description |
|---|---|
| float |
lowSpeedLateralSlipAtPeak
At low slide speed, hold the lateral operating point at the Pacejka peak (clamp lateral slip to peak slip) instead of letting the slip-denominator floor push it onto the falling side. Fades out above the entry speed.
Declaration
[Tooltip("At low slide speed, keep lateral slip at the curve peak (max grip) instead of the falling side. Fades out above the static-entry speed.")]
public bool lowSpeedLateralSlipAtPeak
Field Value
| Type | Description |
|---|---|
| bool |
lowSpeedSlipMinScale
Minimum slip scale at the static/dynamic transition. Lower trims force there to damp oscillation.
Declaration
[Tooltip("Minimum slip scale at static/dynamic transition. Lower values reduce force at transition to prevent oscillation.")]
[Range(0, 1)]
public float lowSpeedSlipMinScale
Field Value
| Type | Description |
|---|---|
| float |
lowSpeedSlipRampEnd
Speed (m/s) at which slip scaling reaches full; below it slip is scaled down to cut low-speed sensitivity.
Declaration
[Tooltip("Speed (m/s) at which slip scaling reaches full (no reduction). Below this, slip is scaled down to reduce sensitivity.")]
[Range(0.5, 2)]
public float lowSpeedSlipRampEnd
Field Value
| Type | Description |
|---|---|
| float |
lowSpeedSurfaceThreshold
Tire-surface speed (m/s) below which the wheel is treated as rotationally stopped.
Declaration
[Tooltip("Linear velocity (m/s) at the tire surface below which the wheel is considered rotationally stopped.")]
public float lowSpeedSurfaceThreshold
Field Value
| Type | Description |
|---|---|
| float |
maxSolverIterations
Upper bound on Newton-Raphson iterations per solve.
Declaration
[Tooltip("Maximum Newton-Raphson iterations per frame.")]
[Range(1, 30)]
public int maxSolverIterations
Field Value
| Type | Description |
|---|---|
| int |
mechanicalTrailCoefficient
Mechanical (caster) trail as a fraction of wheel radius. Persists at high slip, keeping steering weight in slides.
Declaration
[Tooltip("Mechanical (caster) trail as fraction of wheel radius. Does not collapse at high slip, keeping steering weight in slides.")]
[Range(0, 0.15)]
public float mechanicalTrailCoefficient
Field Value
| Type | Description |
|---|---|
| float |
optimalCamber
Camber angle (deg) at which grip peaks. Typically 0 to -2.
Declaration
[Tooltip("Camber angle (deg) at which grip is highest. Usually 0 to -2.")]
public float optimalCamber
Field Value
| Type | Description |
|---|---|
| float |
pneumaticTrailCoefficient
Pneumatic trail as a fraction of wheel radius; sets the self-aligning torque arm.
Declaration
[Tooltip("Pneumatic trail coefficient as fraction of wheel radius.")]
[Range(0.02, 0.15)]
public float pneumaticTrailCoefficient
Field Value
| Type | Description |
|---|---|
| float |
relaxationLengthX
Longitudinal relaxation length (m): distance the tire must roll to build full longitudinal force. Smooths grip onset.
Declaration
[Tooltip("Longitudinal relaxation length (m). Distance tire must travel to fully develop longitudinal force. Smooths grip transitions.")]
[Range(0.01, 0.3)]
public float relaxationLengthX
Field Value
| Type | Description |
|---|---|
| float |
relaxationLengthY
Lateral relaxation length (m): distance the tire must roll to build full lateral force. Typically ~2x longitudinal.
Declaration
[Tooltip("Lateral relaxation length (m). Distance tire must travel to fully develop lateral force. Typically 2x longitudinal.")]
[Range(0.01, 0.6)]
public float relaxationLengthY
Field Value
| Type | Description |
|---|---|
| float |
slipDenominatorFloor
Regularization floor for the slip denominator (sqrt(v^2 + eps^2)); sets low-speed friction sensitivity.
Declaration
[Tooltip("Regularization epsilon for slip denominator. Controls low-speed friction sensitivity via sqrt(v^2 + eps^2).")]
[Range(0.1, 2)]
public float slipDenominatorFloor
Field Value
| Type | Description |
|---|---|
| float |
solverConvergenceThreshold
Newton-Raphson convergence tolerance for the friction solver.
Declaration
[Tooltip("Newton-Raphson convergence threshold for friction solver.")]
public float solverConvergenceThreshold
Field Value
| Type | Description |
|---|---|
| float |
staticBreakThreshold
Demand, as a multiple of available grip, needed to break static friction. Models static-over-kinetic stiction.
Declaration
[Range(1, 3)]
[Tooltip("The multiplier of max grip required to break static friction.")]
public float staticBreakThreshold
Field Value
| Type | Description |
|---|---|
| float |
staticDriveBreakMode
How drive input releases static friction. InputGated: any net drive breaks the hold (original). DemandGated: while the rig is at rest AND a brake/handbrake is applied, drive does NOT break static, so the vehicle (and unbraked driven wheels) hold still under handbrake+throttle on a slope. Releasing the brake or moving reverts to the input-gated break so the vehicle launches normally.
Declaration
[Tooltip("How throttle releases static friction. DemandGated keeps the hold while stationary AND braked (handbrake+throttle holds on a slope). InputGated = original behaviour (any drive breaks the hold).")]
public StaticDriveBreakMode staticDriveBreakMode
Field Value
| Type | Description |
|---|---|
| StaticDriveBreakMode |
staticFrictionAnchorRelaxRate
Declaration
[Range(0, 0.2)]
[Tooltip("Per-substep rate at which the static anchor relaxes toward the current tread position when the vehicle has settled on near-flat ground. Eliminates residual spring forces from initial settle-in where 4 wheel anchors were captured at slightly different poses. 0 disables. Active only when near-stationary AND slope-demand is small, so slope-holding is not compromised.")]
public float staticFrictionAnchorRelaxRate
Field Value
| Type | Description |
|---|---|
| float |
staticFrictionCooldownFrames
Substeps (not FixedUpdate frames) to wait before static friction may re-engage after it breaks.
Declaration
[Tooltip("Substeps (not FixedUpdate frames) to wait before static friction can re-engage. 1 FixedUpdate is typically 4-6 substeps at default WheelControllerManager rates.")]
public int staticFrictionCooldownFrames
Field Value
| Type | Description |
|---|---|
| int |
staticFrictionDamping
Static-anchor damping ratio. 1 = critical (no overshoot); lower if springy, higher if sluggish.
Declaration
[Range(0, 2)]
[Tooltip("Damping ratio. 1.0 = Critical Damping (No Overshoot). Lower <1.0 if slightly springy, Raise >1.0 if sluggish.")]
public float staticFrictionDamping
Field Value
| Type | Description |
|---|---|
| float |
staticFrictionEnabled
Master toggle for static friction. When off the holding force is bypassed and only dynamic friction is used (debug).
Declaration
[Tooltip("When disabled, static friction is bypassed and only dynamic friction is used. For debugging.")]
public bool staticFrictionEnabled
Field Value
| Type | Description |
|---|---|
| bool |
staticFrictionHysteresis
Hysteresis: multiplies the speed threshold for exiting static mode so entry and exit do not chatter.
Declaration
[Range(1, 3)]
[Tooltip("Multiplier for the speed threshold to EXIT static mode (Hysteresis).")]
public float staticFrictionHysteresis
Field Value
| Type | Description |
|---|---|
| float |
staticFrictionSpeedThreshold
Surface speed (m/s) below which the tire tries to enter static (holding) mode.
Declaration
[Range(0.05, 1)]
[Tooltip("Velocity (m/s) under which the tire attempts to enter 'Static' mode.")]
public float staticFrictionSpeedThreshold
Field Value
| Type | Description |
|---|---|
| float |
staticFrictionStrength
Master scale for the low-speed static holding force. 0 = off, 1 = full static friction.
Declaration
[Range(0, 1)]
[Tooltip("Master switch for the static holding force. 1.0 = Full Static Friction.")]
public float staticFrictionStrength
Field Value
| Type | Description |
|---|---|
| float |
staticLateralStiffness
Lateral (sidewall) static spring stiffness, as a multiple of the longitudinal stiffness.
Declaration
[Tooltip("Lateral Stiffness (Sidewall). Multiplier of Longitudinal.")]
[Range(0.1, 1)]
public float staticLateralStiffness
Field Value
| Type | Description |
|---|---|
| float |
staticLongitudinalStiffness
Longitudinal static spring stiffness (braking hold). Effective stiffness = vehicle mass * this.
Declaration
[Tooltip("Longitudinal Stiffness (Brakes). Stiffness = Mass * this.")]
public float staticLongitudinalStiffness
Field Value
| Type | Description |
|---|---|
| float |
stiffness
Per-axis slip stiffness (X = longitudinal, Y = lateral). Scales the slip input; higher = sharper, more responsive tire.
Declaration
[Tooltip("Multiplies the input slip (X-axis of curve). Higher values make tires more responsive/stiff.")]
public Vector2 stiffness
Field Value
| Type | Description |
|---|---|
| Vector2 |
unpoweredBreakThreshold
Demand (as a multiple of grip) needed to break static on an unpowered, unbraked wheel pushed by its neighbours (e.g. trailer wheels). Lower than the powered break threshold; raise toward it for stronger trailer/cross-slope hold.
Declaration
[Range(0.5, 3)]
[Tooltip("Demand multiplier to break static on an unpowered, unbraked wheel pushed by other wheels (e.g. a trailer). Raise toward Break Threshold for stronger trailer hold on slopes.")]
public float unpoweredBreakThreshold
Field Value
| Type | Description |
|---|---|
| float |
Methods
| Edit this page View SourceBreakStaticFriction(int, bool)
Forces the tire to exit static friction mode. Called by WheelControllerGroup when coordinating static friction break across all wheels on a vehicle.
Declaration
public override void BreakStaticFriction(int cooldownFrames = 0, bool clearFilterHistory = false)
Parameters
| Type | Name | Description |
|---|---|---|
| int | cooldownFrames | Substeps to wait before re-entry. 0 = use the friction implementation's configured cooldown (StandardFriction.staticFrictionCooldownFrames). |
| bool | clearFilterHistory | If true, also zero the relaxation-filter history so the next dynamic substep starts from a clean baseline. Use for external breaks (vehicle reset, teleport) where the prior _prev force values are no longer meaningful. Cascading breaks from CoordinateStaticFrictionBreak should keep the default (false) so the in-substep seeding done inside ProcessStaticFriction is preserved. |
Overrides
| Edit this page View SourceUpdateFriction(WheelController, float)
Calculates and updates tire friction forces based on current wheel slip and load conditions. Called every physics frame (FixedUpdate) to determine longitudinal and lateral tire forces. Implementation should update wheel.angularVelocity, frictionForceMagnitude, frictionSlip, and frictionForce.
Declaration
public override void UpdateFriction(WheelController wc, float deltaTime)
Parameters
| Type | Name | Description |
|---|---|---|
| WheelController | wc | WheelController instance containing current state: slip data, load, speed, and tire properties |
| float | deltaTime | Physics timestep duration in seconds (typically Time.fixedDeltaTime) |
Overrides
Remarks
The method should:
- Calculate longitudinal slip and forces (acceleration/braking)
- Update wheel.angularVelocity based on motor torque, brake torque, and friction
- Set wc.frictionForceMagnitude (X=longitudinal, Y=lateral) in Newtons
- Set wc.frictionSlip (X=longitudinal, Y=lateral) as normalized values
- Calculate wc.counterTorque for powertrain feedback
Access current state through:
- wc.frictionSpeed: Contact point velocity (X=forward, Y=sideways)
- wc.load: Current vertical tire load in Newtons
- wc.loadRating: Maximum rated tire load
- wc.activeFrictionPreset: Current friction curve parameters
- wc.motorTorque/brakeTorque: Applied torques
- wc.wheel.angularVelocity: Current wheel rotation speed