NWH Common
Search Results for

    Shifting Origin

    Support for large worlds by repositioning the world origin to prevent floating-point precision issues.

    Problem: Floating-Point Precision

    Unity uses 32-bit floating-point numbers for positions. At distances >1000m from origin (0,0,0), precision degrades causing:

    • Object jitter
    • Physics instability
    • Collision detection errors
    • Visual artifacts

    Solution: Shift the world origin to keep player near (0,0,0).

    How Shifting Origin Works

    Instead of moving the player far from origin, move the world around the player:

    Normal:           Shifting Origin:
    Player at 5000m   Player at 0m
    World at 0m       World at -5000m
    → Low precision   → High precision
    

    The player stays near origin, everything else moves.

    ShiftingOrigin Component

    Setup

    1. Create empty GameObject "ShiftingOrigin" at (0,0,0)
    2. Add ShiftingOrigin component
    3. Configure settings

    Inspector Fields

    • Shift Threshold - Distance from origin before shift occurs (default: 1000m)
    • Player Transform - Transform to keep centered (usually player/vehicle)
    • Shift On Startup - Shift immediately when scene loads
    • Debug Visualize - Show debug info in Scene view

    Basic Usage

    using NWH.Common.Utility;
    
    public class GameSetup : MonoBehaviour
    {
        public Transform player;
    
        void Start()
        {
            // Find or create ShiftingOrigin
            ShiftingOrigin shifter = FindObjectOfType<ShiftingOrigin>();
    
            if (shifter == null)
            {
                GameObject go = new GameObject("ShiftingOrigin");
                shifter = go.AddComponent<ShiftingOrigin>();
            }
    
            // Configure
            shifter.playerTransform = player;
            shifter.shiftThreshold = 1000f;
        }
    }
    

    What Gets Shifted

    ShiftingOrigin moves everything in the scene except:

    • The player/vehicle (stays at origin)
    • UI elements
    • Cameras (stay with player)

    Shifted Objects:

    • Terrain
    • Buildings
    • Vehicles (other than player)
    • Particles
    • Lights
    • All scene GameObjects

    Integration with NWH Assets

    Vehicle Physics 2

    Automatically supported:

    // No special setup needed
    // ShiftingOrigin works with all vehicles
    

    Dynamic Water Physics 2

    Water objects shift correctly:

    // Water surface shifts with origin
    // Buoyancy calculations remain accurate
    

    Aerodynamics

    Aircraft support large worlds:

    // Flying long distances works correctly
    // Wind system shifts with origin
    

    Advanced Configuration

    Custom Shift Handlers

    Register custom behavior when shift occurs:

    using NWH.Common.Utility;
    
    public class CustomShiftHandler : MonoBehaviour
    {
        void Start()
        {
            ShiftingOrigin shifter = FindObjectOfType<ShiftingOrigin>();
            shifter.onShift += OnOriginShift;
        }
    
        void OnOriginShift(Vector3 shiftAmount)
        {
            // Custom logic when origin shifts
            Debug.Log($"Origin shifted by {shiftAmount}");
    
            // Update custom systems
            UpdateCustomPositions(shiftAmount);
        }
    
        void UpdateCustomPositions(Vector3 shift)
        {
            // Adjust positions of custom objects
            myCustomObject.position -= shift;
        }
    }
    

    Excluding Objects

    Prevent specific objects from shifting:

    public class NonShiftingObject : MonoBehaviour
    {
        void Start()
        {
            ShiftingOrigin shifter = FindObjectOfType<ShiftingOrigin>();
            shifter.onShift += OnShift;
        }
    
        void OnShift(Vector3 shiftAmount)
        {
            // Counteract the shift for this object
            transform.position += shiftAmount;
        }
    }
    

    Large World Design

    Recommended Setup

    public class LargeWorldManager : MonoBehaviour
    {
        public Transform player;
        public float worldSize = 10000f;  // 10km x 10km
    
        void Start()
        {
            SetupShiftingOrigin();
            SetupStreamingSystem();
        }
    
        void SetupShiftingOrigin()
        {
            ShiftingOrigin shifter = gameObject.AddComponent<ShiftingOrigin>();
            shifter.playerTransform = player;
            shifter.shiftThreshold = 500f;  // Shift every 500m
            shifter.shiftOnStartup = true;
        }
    
        void SetupStreamingSystem()
        {
            // Implement object streaming
            // Load/unload objects based on distance
        }
    }
    

    Streaming Integration

    Combine with object streaming for massive worlds:

    public class ObjectStreamer : MonoBehaviour
    {
        public float streamDistance = 1000f;
        public Transform player;
    
        private ShiftingOrigin shifter;
    
        void Start()
        {
            shifter = FindObjectOfType<ShiftingOrigin>();
            shifter.onShift += OnOriginShift;
        }
    
        void Update()
        {
            StreamObjects();
        }
    
        void StreamObjects()
        {
            // Load objects near player
            // Unload objects far from player
        }
    
        void OnOriginShift(Vector3 shiftAmount)
        {
            // Update streaming system after shift
            RecalculateStreamingZones();
        }
    }
    

    Considerations

    Physics

    • Physics remains stable at any distance
    • Collisions work correctly after shift
    • Rigidbodies maintain momentum

    Particles

    • Active particles shift correctly
    • Long-lived particles may need special handling
    • Particle systems should be world-space, not local

    Networking

    For multiplayer games:

    // All clients must shift together
    public class NetworkedShiftingOrigin : MonoBehaviour
    {
        void Start()
        {
            ShiftingOrigin shifter = GetComponent<ShiftingOrigin>();
    
            if (IsServer())
            {
                shifter.onShift += BroadcastShift;
            }
            else
            {
                shifter.enabled = false;  // Only server initiates shifts
            }
        }
    
        void BroadcastShift(Vector3 shiftAmount)
        {
            // Send shift command to all clients
            SendShiftCommand(shiftAmount);
        }
    }
    

    Pathfinding

    Nav meshes need updating after shift:

    void OnOriginShift(Vector3 shiftAmount)
    {
        // Update AI waypoints
        foreach (var waypoint in aiWaypoints)
        {
            waypoint.position -= shiftAmount;
        }
    
        // Recalculate nav mesh if needed
        NavMeshSurface.UpdateNavMesh();
    }
    

    Performance

    Shift Cost:

    • Iterates through all scene GameObjects
    • Moves transforms
    • Typically <1ms for scenes with <1000 objects

    Optimization:

    // Shift less frequently for better performance
    shifter.shiftThreshold = 2000f;  // Shift every 2km instead of 1km
    
    // Or disable when player is stationary
    if (playerVelocity.magnitude < 0.1f)
    {
        shifter.enabled = false;
    }
    else
    {
        shifter.enabled = true;
    }
    

    Example: Open World Vehicle Game

    using UnityEngine;
    using NWH.Common.Utility;
    
    public class OpenWorldSetup : MonoBehaviour
    {
        public Transform playerVehicle;
        public float mapSize = 20000f;  // 20km x 20km
    
        void Start()
        {
            SetupShiftingOrigin();
            SetupTerrainStreaming();
            SetupObjectCulling();
        }
    
        void SetupShiftingOrigin()
        {
            GameObject shifterGO = new GameObject("ShiftingOrigin");
            ShiftingOrigin shifter = shifterGO.AddComponent<ShiftingOrigin>();
    
            shifter.playerTransform = playerVehicle;
            shifter.shiftThreshold = 1000f;
            shifter.shiftOnStartup = true;
            shifter.debugVisualize = true;
    
            shifter.onShift += OnWorldShift;
        }
    
        void OnWorldShift(Vector3 shiftAmount)
        {
            Debug.Log($"World origin shifted by {shiftAmount.magnitude:F1}m");
    
            // Update any custom systems
            UpdateMinimapPosition(shiftAmount);
            UpdateQuestMarkers(shiftAmount);
        }
    
        void SetupTerrainStreaming()
        {
            // Implement terrain streaming
        }
    
        void SetupObjectCulling()
        {
            // Implement object culling/LOD
        }
    
        void UpdateMinimapPosition(Vector3 shift)
        {
            // Adjust minimap to show correct position
        }
    
        void UpdateQuestMarkers(Vector3 shift)
        {
            // Shift quest marker positions
        }
    }
    

    Best Practices

    1. Always Use for Large Worlds - Any map >1km should use shifting origin
    2. Shift Threshold - 500-1000m is optimal balance
    3. Test at Distance - Test gameplay at >5km from origin
    4. UI Separation - Keep UI in separate camera/canvas
    5. World Space Particles - Use world space for particle systems
    6. Save/Load - Save player's world position, not local position
    7. Networking - Synchronize shifts across all clients

    Troubleshooting

    Objects jittering:

    • Increase shift threshold
    • Check Fixed Timestep in Project Settings
    • Verify objects are being shifted correctly

    Physics errors after shift:

    • Check Rigidbodies are awake after shift
    • Verify collision layers are correct
    • Test with simpler collision shapes

    Particles disappearing:

    • Use world space particle systems
    • Handle particle position updates in onShift

    Networking desync:

    • Ensure all clients shift simultaneously
    • Synchronize shift threshold across network

    API Reference

    Internal API:

    • ShiftingOrigin - Complete API reference available through the navigation menu

    Related Unity Documentation:

    • Unity Transform Documentation
    • Unity Floating-Point Precision Guide
    • Edit this page
    In this article
    Back to top Copyright © NWH - Vehicle Physics, Aerodynamics, Dynamic Water Physics