NWH Vehicle Physics 2
Search Results for

    Show / Hide Table of Contents

    Architecture Overview

    NWH Vehicle Physics 2 divides vehicle simulation into components coordinated by VehicleController.


    Component Hierarchy

    The components are arranged as follows:

    VehicleController (Main Hub)
    ├── Powertrain
    │   ├── EngineComponent (power generation)
    │   ├── ClutchComponent (power transfer control)
    │   ├── TransmissionComponent (gear ratios)
    │   ├── DifferentialComponent(s) (torque distribution)
    │   └── WheelComponent(s) (power sinks → WheelController)
    ├── Steering (angle calculations, speed-dependent reduction)
    ├── Brakes (torque application, brake distribution)
    ├── Input
    │   └── VehicleInputHandler
    │       ├── InputSystemVehicleInputProvider
    │       ├── InputManagerVehicleInputProvider
    │       └── MobileVehicleInputProvider
    ├── EffectManager
    │   ├── LightsManager (headlights, brake, indicators)
    │   ├── SkidmarkManager (tire marks)
    │   ├── SurfaceParticleManager (dust, dirt, spray)
    │   └── Exhausts (smoke, flash)
    ├── SoundManager
    │   ├── EngineRunningComponent
    │   ├── EngineStartStopComponent
    │   ├── TransmissionWhineComponent
    │   ├── WheelSkidComponent
    │   ├── WheelTireNoiseComponent
    │   └── [other sound components]
    ├── GroundDetection (surface type identification)
    ├── DamageHandler (collision damage)
    └── ModuleManager
        ├── ABSModule
        ├── TCSModule
        ├── ESCModule
        ├── CruiseControlModule
        ├── ArcadeModule
        ├── MotorcycleModule
        ├── TrailerModule / TrailerHitchModule
        ├── AerodynamicsModule
        ├── NOSModule
        └── [15+ optional modules]
    

    VehicleComponent Lifecycle

    All vehicle systems share the lifecycle defined by VehicleComponent. The VC_ method prefix avoids conflicts with Unity callbacks.

    Lifecycle Stages

                        ┌─────────────────────────────────────┐
                        │         INITIALIZATION              │
                        └─────────────────────────────────────┘
                                        │
                        VC_Initialize(VehicleController vc)
                               Sets parent reference
                                        │
                               VC_Initialize()
                          Component-specific setup
                                        │
                         VC_LoadStateFromStateSettings()
                        Apply LOD-based initial state
                                        │
                        ┌─────────────────────────────────────┐
                        │          RUNTIME LOOP               │
                        └─────────────────────────────────────┘
                                        │
                        ┌───────────────┴───────────────┐
                        │                               │
                  VC_Enable()                    VC_Disable()
               Component active              Component inactive
                        │                               │
                        ├───────────────────────────────┤
                        │                               │
              VC_FixedUpdate(dt)                       │
               Physics updates                         │
                        │                               │
               VC_Update(dt)                           │
               Visual updates                          │
                        │                               │
                        └───────────────────────────────┘
    

    Lifecycle Methods

    Method When Called Purpose
    VC_Initialize(vc) Once on startup Sets VehicleController reference
    VC_Initialize() Once on startup Component-specific initialization
    VC_SetDefaults() On first setup Apply default configuration values
    VC_Validate(VehicleController vc) Editor/runtime Validate component configuration
    VC_LoadStateFromStateSettings() On state change Apply LOD-based state
    VC_Enable() When enabled Activate component
    VC_Disable() When disabled Deactivate component
    VC_FixedUpdate(dt) Each FixedUpdate Physics calculations
    VC_Update(dt) Each Update Visual/audio updates

    Example Implementation

    using NWH.VehiclePhysics2;
    
    public class CustomComponent : VehicleComponent
    {
        protected override void VC_Initialize()
        {
            base.VC_Initialize();
            // Setup code here
        }
    
        public override bool VC_Enable(bool calledByParent)
        {
            base.VC_Enable(calledByParent);
            // Called when component becomes active
            return true;
        }
    
        public override void VC_FixedUpdate(float dt)
        {
            base.VC_FixedUpdate(dt);
            if (!IsActive) return;
    
            // Physics calculations here
        }
    
        public override void VC_Update(float dt)
        {
            base.VC_Update(dt);
            if (!IsActive) return;
    
            // Visual updates here
        }
    }
    

    Update Order

    Execution-order attributes

    The current runtime uses these Unity execution-order attributes:

    Order Type Current responsibility
    90 VehicleController Dispatch vehicle component updates and attach the powertrain callback
    100 WheelController Register wheel instances before manager processing
    110 WheelControllerManager Run the grouped wheel substep loop

    Physics flow

    VehicleController.FixedUpdate() iterates its cached Components list and calls VC_FixedUpdate(fixedDeltaTime) on each active component in list order. It does not expose a fixed category sequence such as ground detection, input, powertrain, steering, and brakes.

    Powertrain integration occurs through VehicleController.OnBeforeSubstep(), which the WheelControllerManager invokes before each wheel substep for that Rigidbody group. The manager then advances ground detection, suspension, friction, static-friction coordination, and final Rigidbody state for the group. See the Wheel Controller manager guide for that current pipeline.

    Render and LOD flow

    VehicleController.Update() iterates the same active component list and calls VC_Update(deltaTime). VehicleController has no LateUpdate() lifecycle stage. LOD distance checks run separately in LODCheckCoroutine() at approximately 0.2-second intervals.


    Physics Substepping

    The powertrain and wheel physics run at a higher frequency than Unity's FixedUpdate through the substepping system.

    How Substepping Works

    Unity FixedUpdate (60Hz / 0.01667s)
    │
    └── WheelControllerManager
        ├── Substep 0 (0.00417s)
        │   ├── Powertrain calculates torques
        │   └── Wheel calculates forces
        │
        ├── Substep 1 (0.00417s)
        │   ├── Powertrain responds to wheel state
        │   └── Wheel recalculates with new torque
        │
        ├── Substep 2 (0.00417s)
        │   └── ...
        │
        └── Substep 3 (0.00417s)
            └── Final forces applied to Rigidbody
    

    Configuration

    The effective physics rate is calculated as:

    Effective Rate = (1 / fixedDeltaTime) * substepCount
    
    Example:
    - Fixed Timestep: 0.01667s (60Hz desktop, recommended)
    - Substeps: 4
    - Effective Rate: 60 * 4 = 240Hz
    

    See WheelControllerManager in the WheelController3D documentation for more on substepping.


    State System (LOD)

    StateSettings enables or disables components by distance to reduce simulation cost.

    LOD Levels

    Level Distance Description
    LOD 0 Close Full simulation, all effects/sounds
    LOD 1 Medium Reduced quality, simplified physics
    LOD 2 Far Minimal simulation, no effects
    LOD 3 Very Far Component sleeping, minimal overhead

    State Transitions

    Distance increases →
    ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐
    │  LOD 0  │ → │  LOD 1  │ → │  LOD 2  │ → │  LOD 3  │
    │  Full   │    │ Reduced │    │ Minimal │    │  Sleep  │
    └─────────┘    └─────────┘    └─────────┘    └─────────┘
    ← Distance decreases
    

    Per-Component State

    Each VehicleComponent has a StateDefinition controlling its enabled state and LOD index. These are configured through the StateSettings ScriptableObject.

    See StateSettings and LOD for configuration details.


    Input System Architecture

    The input system uses a shared registry with separate provider families for vehicle controls and scene controls.

    Input Flow

    Hardware Input
          │
          ├──────────────── vehicle branch ────────────────┐
          │                                                ▼
          │   VehicleInputProviderBase instance(s) -> VehicleInputHandler
          │   ├── InputSystemVehicleInputProvider             │
          │   ├── InputManagerVehicleInputProvider             ▼
          │   ├── MobileVehicleInputProvider            VehicleInputStates
          │   └── FFBInputProvider (optional sample)    ├── throttle (0-1)
          │                                             ├── brakes (0-1)
          │                                             ├── steering (-1 to 1)
          │                                             ├── clutch (0-1)
          │                                             ├── handbrake (0-1)
          │                                             ├── shiftUp/shiftDown (bool)
          │                                             └── other vehicle inputs
          │
          └───────────────── scene branch ──────────────────────┐
                                                               ▼
              SceneInputProviderBase instance(s) -> camera, UI, and vehicle switching
              ├── InputSystemSceneInputProvider
              ├── InputManagerSceneInputProvider
              └── MobileSceneInputProvider
    

    Input Provider Types

    Provider family Shipped implementations Consumer
    VehicleInputProviderBase InputSystemVehicleInputProvider, InputManagerVehicleInputProvider, MobileVehicleInputProvider Per-vehicle VehicleInputHandler
    SceneInputProviderBase InputSystemSceneInputProvider, InputManagerSceneInputProvider, MobileSceneInputProvider Scene camera, UI, and vehicle-switching systems
    VehicleInputProviderBase sample FFBInputProvider in the optional DirectInput FFB sample Per-vehicle VehicleInputHandler

    Module System

    Modules are optional vehicle features that can be added, removed, or configured independently.

    Module Categories

    Driver Assistance:

    • ABSModule - Anti-lock Braking System
    • TCSModule - Traction Control System
    • ESCModule - Electronic Stability Control
    • CruiseControlModule - Speed maintenance
    • SpeedLimiterModule - Maximum speed enforcement

    Vehicle Types:

    • MotorcycleModule - Lean physics
    • ArcadeModule - Simplified physics

    Features:

    • TrailerModule / TrailerHitchModule - Towing
    • AerodynamicsModule - Downforce
    • NOSModule - Nitrous boost
    • FuelModule - Fuel consumption
    • FlipOverModule - Auto-recovery
    • MetricsModule - Performance tracking
    • RiggingModule - Visual bone animation
    • AirSteerModule - In-air steering

    Module Lifecycle

    Modules follow the same VehicleComponent lifecycle but are managed through ModuleManager:

    Partial example (assumes an existing VehicleController vc reference):

    // Access module through wrapper component
    var absWrapper = vc.GetComponent<ABSModuleWrapper>();
    if (absWrapper != null)
    {
        ABSModule absModule = absWrapper.module;
        absModule.VC_Enable(false);   // Enable module
        absModule.VC_Disable(false);  // Disable module
        bool isActive = absModule.IsActive;
    }
    

    Design Patterns Used

    Component Pattern

    All vehicle systems inherit from VehicleComponent for consistent lifecycle management.

    Provider Pattern

    Input providers can be swapped to support different platforms.

    Manager Pattern

    Each manager coordinates a group of related components:

    • ModuleManager - Optional modules
    • SoundManager - Audio playback
    • EffectManager - Visual effects
    • WheelControllerManager - Physics substepping

    Observer Pattern

    These events report state changes:

    • onLODChanged - LOD level transitions (on VehicleController)
    • onVehicleChanged - Active vehicle switching (on VehicleChanger, in NWH.Common)
    • onActiveVehicleChanged - Global vehicle tracking (static, on Vehicle base class in NWH.Common)

    State Pattern

    LOD system manages component states based on distance.


    Best Practices

    Initialization

    1. Use VC_Initialize() for setup, not Unity's Awake() or Start()
    2. Access other components only after initialization
    3. Use VC_SetDefaults() for default values, not field initializers

    Updates

    1. Physics calculations go in VC_FixedUpdate(dt)
    2. Visual updates go in VC_Update(dt)
    3. Always check if (!IsActive) return; at the start

    Performance

    1. Enable LOD system for multiple vehicles
    2. Disable unused modules
    3. Use appropriate substep count for platform
    4. Pool custom effects where appropriate. The built-in skidmark generator creates its own GameObjects and meshes rather than using an object pool.

    Debugging

    1. Enable gizmos to visualize wheel positions and forces
    2. Inspect runtime wheel values in the WheelController Debug tab; the Base Sample also includes its own telemetry UI
    3. Check Unity Profiler for bottlenecks
    4. Recommended Fixed Timestep: 0.01667s (60Hz) desktop, 0.0333s (30Hz) mobile

    Related Documentation

    • VehicleController - Main controller component
    • VehicleComponent - Base component class
    • Powertrain - Powertrain system
    • WheelControllerManager (WheelController3D package) - Physics substepping
    • StateSettings - LOD configuration
    • ModuleManager - Module system
    In this article
    Back to top Copyright © NWH - Vehicle Physics, Aerodynamics, Dynamic Water Physics