Class FrictionPreset
ScriptableObject containing tire friction characteristics for specific surface types. Defines the friction curve that determines how tire grip varies with slip for different surfaces. Create different presets for asphalt, gravel, ice, mud, or custom surface conditions.
Namespace: NWH.Common.Vehicles
Assembly: NWH.WheelController.dll
Syntax
[Serializable]
[CreateAssetMenu(fileName = "NWH Vehicle Physics 2", menuName = "NWH/Vehicle Physics 2/Friction Preset", order = 1)]
public class FrictionPreset : ScriptableObject
Remarks
FrictionPreset stores friction curve data using the Pacejka Magic Formula, a widely-used tire model in vehicle simulation. The curve is defined by BCDE parameters and can be visualized as an AnimationCurve. The curve maps slip ratio (0-1) to friction coefficient.
The friction curve typically:
- Starts at zero (no slip = no friction force)
- Rises quickly to a peak (optimal slip for maximum grip, usually 0.1-0.2)
- Gradually falls off (tire sliding, reduced grip)
Common surface characteristics:
- Dry Asphalt: Peak ~1.0-1.2 at slip 0.12-0.18, sharp rise, gradual falloff
- Wet Asphalt: Peak ~0.7-0.9 at slip 0.15-0.25, smoother curve
- Gravel: Peak ~0.6-0.8 at slip 0.2-0.3, very gradual falloff
- Ice: Peak ~0.1-0.3 at slip 0.3-0.5, very smooth curve
- Mud/Sand: Peak ~0.4-0.6 at slip 0.25-0.35, flat falloff
Assign FrictionPreset to WheelController.activeFrictionPreset or change dynamically based on surface detection for realistic multi-surface behavior. When used with NVP2 this is done through GroundDetection.
Fields
| Edit this page View SourceBCDE
Pacejka Magic Formula parameters (B, C, D, E) defining the tire friction curve. These parameters mathematically describe how friction varies with slip.
Declaration
[Tooltip("B, C, D and E parameters of short version of Pacejka's magic formula.")]
public Vector4 BCDE
Field Value
| Type | Description |
|---|---|
| Vector4 |
Remarks
Parameter meanings:
- B (Stiffness Factor): Controls initial slope and response (10-20 typical)
- C (Shape Factor): Defines curve shape (1.3-1.8 typical)
- D (Peak Value): Maximum friction coefficient (0.8-1.2 typical)
- E (Curvature Factor): Controls falloff shape (0.9-1.0 typical)
Effects of parameter changes:
- Higher B: More responsive, sharper peak (sports tires)
- Lower B: Softer response, wider peak (comfort tires)
- Higher D: More overall grip (racing slicks)
- Lower D: Less grip (wet/ice conditions)
- Higher C: Taller, narrower peak
- E near 1.0: Gradual falloff; E below 1.0: Sharper falloff
Example presets:
- Dry Tarmac: (10, 1.6, 1.0, 0.98) - Default, balanced grip
- Race Slick: (15, 1.8, 1.3, 0.95) - High grip, sharp response
- Wet Road: (8, 1.5, 0.75, 1.0) - Reduced grip, softer response
- Ice: (5, 1.3, 0.2, 1.0) - Very low grip, very soft
BCDELateral
Lateral BCDE parameters for separate lateral friction curve. If zero vector, uses longitudinal BCDE for both directions (backward compatible). On loose surfaces (gravel, sand), lateral grip typically peaks earlier and falls off faster.
Declaration
[Tooltip("Lateral BCDE. If zero, uses longitudinal curve for both directions.")]
public Vector4 BCDELateral
Field Value
| Type | Description |
|---|---|
| Vector4 |
LUT_MAX_SLIP
Max slip covered by the LUT. Covers high-stiffness presets and combined high-slip without clamping at the edge.
Declaration
public const float LUT_MAX_SLIP = 2
Field Value
| Type | Description |
|---|---|
| float |
LUT_SCALE
Scale factor for LUT indexing: (LUT_SIZE - 1) / LUT_MAX_SLIP.
Declaration
public const float LUT_SCALE = 63.5
Field Value
| Type | Description |
|---|---|
| float |
LUT_SIZE
LUT sample count. 128 gives ~0.8% precision.
Declaration
public const int LUT_SIZE = 128
Field Value
| Type | Description |
|---|---|
| int |
curve
AnimationCurve visualization of the Pacejka friction formula. X-axis represents slip (0-1), Y-axis represents friction coefficient. Generated from BCDE parameters via UpdateFrictionCurve(). Manually editing the curve will be overwritten when parameters change.
Declaration
public AnimationCurve curve
Field Value
| Type | Description |
|---|---|
| AnimationCurve |
Remarks
The curve is automatically generated when BCDE parameters change. StandardFriction uses this curve directly for performance. The curve provides faster lookups than calculating the Pacejka formula each frame. Curve is sampled more densely near the peak (where slip typically occurs) and more sparsely at high slip values for memory efficiency.
curveLUT
Pre-sampled friction curve lookup table for fast evaluation. Generated from Pacejka formula at runtime to avoid AnimationCurve overhead.
Declaration
[NonSerialized]
public float[] curveLUT
Field Value
| Type | Description |
|---|---|
| float[] |
curveLateral
Lateral friction curve generated from BCDELateral. Used for cornering forces. If BCDELateral is zero, StandardFriction uses the main curve.
Declaration
public AnimationCurve curveLateral
Field Value
| Type | Description |
|---|---|
| AnimationCurve |
curveLateralLUT
Pre-sampled lateral friction curve lookup table. Null when HasSeparateLateralCurve is false (falls back to longitudinal LUT).
Declaration
[NonSerialized]
public float[] curveLateralLUT
Field Value
| Type | Description |
|---|---|
| float[] |
derivativeLUT
Pre-sampled derivative lookup table for Newton-Raphson Jacobian calculation. Eliminates the need to call EstimateCurveDerivative() at runtime.
Declaration
[NonSerialized]
public float[] derivativeLUT
Field Value
| Type | Description |
|---|---|
| float[] |
derivativeLateralLUT
Pre-sampled lateral derivative lookup table. Null when HasSeparateLateralCurve is false (falls back to longitudinal LUT).
Declaration
[NonSerialized]
public float[] derivativeLateralLUT
Field Value
| Type | Description |
|---|---|
| float[] |
gripNoiseAmplitude
Peak-to-peak grip variation from surface patchiness, as a fraction of nominal grip. Sampled from deterministic spatial noise at the contact point; average grip is unchanged. ~0.1-0.2 loose surfaces, ~0.03 worn tarmac, 0 disables.
Declaration
[Range(0, 0.5)]
[Tooltip("Peak-to-peak grip variation from surface patchiness. ~0.1-0.2 loose surfaces, ~0.03 tarmac, 0 = off.")]
public float gripNoiseAmplitude
Field Value
| Type | Description |
|---|---|
| float |
gripNoiseScale
Size of a grip noise patch in meters.
Declaration
[Range(0.1, 10)]
[Tooltip("Grip noise patch size (m).")]
public float gripNoiseScale
Field Value
| Type | Description |
|---|---|
| float |
lateralPlow
Lateral plow resistance as a fraction of wheel load, opposing sideways sliding on soft surfaces (bulldozed material builds up against the tire). Not friction-limited. 0 for firm surfaces.
Declaration
[Range(0, 0.5)]
[Tooltip("Lateral plow resistance as a fraction of wheel load, opposing sideways slides. 0 = firm surface.")]
public float lateralPlow
Field Value
| Type | Description |
|---|---|
| float |
peakSlip
Slip value where the friction curve reaches its maximum (peak grip). Automatically calculated from the friction curve. Typical values: 0.10-0.15 for asphalt, 0.20-0.30 for gravel, 0.30-0.50 for ice.
Declaration
[Tooltip("Slip at which the friction preset has highest friction.")]
public float peakSlip
Field Value
| Type | Description |
|---|---|
| float |
Remarks
This value is informational and used for display/analysis purposes. The actual peak is determined by the curve itself. Lower peak slip values indicate more responsive tires that reach maximum grip quickly. Higher values indicate tires that need more slip to develop grip.
peakSlipLateral
Peak slip for lateral direction. Calculated from curveLateral.
Declaration
[Tooltip("Slip at which lateral friction is highest.")]
public float peakSlipLateral
Field Value
| Type | Description |
|---|---|
| float |
peakValue
Actual maximum of the longitudinal friction curve. Equals BCDE.z for typical shape factors (1 < C < 2) but sits below it when C <= 1. 0 until LUTs are generated.
Declaration
[NonSerialized]
public float peakValue
Field Value
| Type | Description |
|---|---|
| float |
peakValueLateral
Actual maximum of the lateral friction curve. Equals peakValue when no separate lateral curve is set.
Declaration
[NonSerialized]
public float peakValueLateral
Field Value
| Type | Description |
|---|---|
| float |
slideGripFalloff
Fraction of grip lost when the contact patch slides at or above slideGripFalloffSpeed. Rubber friction decays with sliding velocity: ~0.2 dry asphalt, ~0.05 loose surfaces, 0 disables.
Declaration
[Range(0, 1)]
[Tooltip("Fraction of grip lost at/above Slide Grip Falloff Speed. ~0.2 dry asphalt, ~0.05 loose surfaces, 0 = off.")]
public float slideGripFalloff
Field Value
| Type | Description |
|---|---|
| float |
slideGripFalloffSpeed
Slide speed (m/s) at which the full slideGripFalloff is reached. Falloff ramps linearly up to it.
Declaration
[Range(1, 60)]
[Tooltip("Slide speed (m/s) at which the full grip falloff is reached.")]
public float slideGripFalloffSpeed
Field Value
| Type | Description |
|---|---|
| float |
surfaceDrag
Longitudinal sinkage drag as a fraction of wheel load. Models soft-material displacement (gravel, sand, snow). Applied as a body force that fades to zero at standstill. 0 for firm surfaces.
Declaration
[Range(0, 0.5)]
[Tooltip("Longitudinal sinkage drag as a fraction of wheel load. 0 = firm surface.")]
public float surfaceDrag
Field Value
| Type | Description |
|---|---|
| float |
Properties
| Edit this page View SourceHasSeparateLateralCurve
Returns true if this preset has separate lateral friction parameters.
Declaration
public bool HasSeparateLateralCurve { get; }
Property Value
| Type | Description |
|---|---|
| bool |
Remarks
Requires B, C and D together. The magic formula is Dsin(Catan(...)), so a partially filled BCDELateral - the state after dragging one of the four independent lateral sliders - evaluates to exactly zero at every slip. Arming the lateral curve on that would leave the tire with no cornering force at all.
Methods
| Edit this page View SourceEvaluate(float)
Calculates friction coefficient for a given slip value using the Pacejka Magic Formula. Returns the Y value (friction coefficient) for a given X value (slip) on the friction curve.
Declaration
public float Evaluate(float slip)
Parameters
| Type | Name | Description |
|---|---|---|
| float | slip | Slip ratio (0-1) where 0=no slip, 1=full slide |
Returns
| Type | Description |
|---|---|
| float | Friction coefficient multiplier |
EvaluateDerivativeLUT(float)
Fast derivative evaluation using pre-sampled lookup table with linear interpolation. Used by Newton-Raphson solver for Jacobian calculation.
Declaration
public float EvaluateDerivativeLUT(float slip)
Parameters
| Type | Name | Description |
|---|---|---|
| float | slip | Slip ratio (0 to LUT_MAX_SLIP) |
Returns
| Type | Description |
|---|---|
| float | Derivative of friction coefficient with respect to slip |
EvaluateDerivativeLateralLUT(float)
Fast lateral derivative evaluation using lateral derivative LUT. Falls back to longitudinal EvaluateDerivativeLUT when no separate lateral curve exists.
Declaration
public float EvaluateDerivativeLateralLUT(float slip)
Parameters
| Type | Name | Description |
|---|---|---|
| float | slip |
Returns
| Type | Description |
|---|---|
| float |
EvaluateLUT(float)
Fast friction curve evaluation using pre-sampled lookup table with linear interpolation. Falls back to Pacejka formula if LUT not generated.
Declaration
public float EvaluateLUT(float slip)
Parameters
| Type | Name | Description |
|---|---|---|
| float | slip | Slip ratio (0 to LUT_MAX_SLIP) |
Returns
| Type | Description |
|---|---|
| float | Friction coefficient |
EvaluateLateral(float)
Calculates lateral friction coefficient using BCDELateral parameters. Falls back to longitudinal Evaluate if no lateral parameters set.
Declaration
public float EvaluateLateral(float slip)
Parameters
| Type | Name | Description |
|---|---|---|
| float | slip |
Returns
| Type | Description |
|---|---|
| float |
EvaluateLateralLUT(float)
Fast lateral friction curve evaluation using lateral LUT. Falls back to longitudinal EvaluateLUT when no separate lateral curve exists.
Declaration
public float EvaluateLateralLUT(float slip)
Parameters
| Type | Name | Description |
|---|---|---|
| float | slip |
Returns
| Type | Description |
|---|---|
| float |
GenerateLUT()
Generates lookup tables for fast friction curve evaluation. Creates both the friction value LUT and its derivative LUT for Newton-Raphson solver. Called automatically by UpdateFrictionCurve() and OnEnable().
Declaration
public void GenerateLUT()
GetPeakSlip()
Finds and returns the slip value where the friction curve reaches its maximum value. Samples the Pacejka formula at regular intervals to locate the peak friction point.
Declaration
public float GetPeakSlip()
Returns
| Type | Description |
|---|---|
| float | Slip value (0 to LUT_MAX_SLIP) where friction coefficient is highest |
UpdateAllCurves()
Updates both longitudinal and lateral curves from their BCDE parameters.
Declaration
public void UpdateAllCurves()
UpdateFrictionCurve(int, float)
Generates the AnimationCurve from Pacejka BCDE parameters using the Magic Formula. Creates keyframes with higher density near the peak for accuracy where it matters most. Call this after modifying BCDE parameters to update the visual curve representation.
Declaration
public void UpdateFrictionCurve(int keyframeCount = 20, float detailedRegionRatio = 0.5)
Parameters
| Type | Name | Description |
|---|---|---|
| int | keyframeCount | Total number of curve keyframes (default 20 for good balance of accuracy and memory) |
| float | detailedRegionRatio | Fraction of keyframes to use in the critical low-slip region (default 0.5) |
UpdateLateralFrictionCurve(int, float)
Generates the lateral AnimationCurve from BCDELateral parameters. Call after modifying BCDELateral to update the curve.
Declaration
public void UpdateLateralFrictionCurve(int keyframeCount = 20, float detailedRegionRatio = 0.5)
Parameters
| Type | Name | Description |
|---|---|---|
| int | keyframeCount | |
| float | detailedRegionRatio |