void Update()
    {
        if (OceanRenderer.Instance == null)
        {
            return;
        }

        if (_animate)
        {
            float t = OceanRenderer.Instance.CurrentTime;
            if (t < _warmUp)
            {
                return;
            }
            t            -= _warmUp;
            t             = Mathf.Repeat(t, _period);
            _rdwi.enabled = t < _onTime;
        }

        // which lod is this object in (roughly)?
        Rect thisRect = new Rect(new Vector2(transform.position.x, transform.position.z), Vector3.zero);
        int  minLod   = LodDataMgrAnimWaves.SuggestDataLOD(thisRect);

        if (minLod == -1)
        {
            // outside all lods, nothing to update!
            return;
        }

        // how many active wave sims currently apply to this object - ideally this would eliminate sims that are too
        // low res, by providing a max grid size param
        int simsPresent, simsActive;

        LodDataMgrDynWaves.CountWaveSims(minLod, out simsPresent, out simsActive);
        if (simsPresent == 0)
        {
            enabled = false;
            return;
        }

        float dt; int steps;

        OceanRenderer.Instance._lodDataDynWaves.GetSimSubstepData(OceanRenderer.Instance.DeltaTimeDynamics, out steps, out dt);

        _rend.GetPropertyBlock(_mpb);

        _mpb.SetFloat("_SimCount", simsActive);
        _mpb.SetFloat("_SimDeltaTime", dt);

        _rend.SetPropertyBlock(_mpb);
    }
    void LateUpdate()
    {
        // which lod is this object in (roughly)?
        var thisRect = new Rect(new Vector2(transform.position.x, transform.position.z), Vector3.zero);
        var minLod   = LodDataMgrAnimWaves.SuggestDataLOD(thisRect);

        if (minLod == -1)
        {
            // outside all lods, nothing to update!
            return;
        }

        // how many active wave sims currently apply to this object - ideally this would eliminate sims that are too
        // low res, by providing a max grid size param
        int simsPresent, simsActive;

        LodDataMgrDynWaves.CountWaveSims(minLod, out simsPresent, out simsActive);

        // counting non-existent sims is expensive - stop updating if none found
        if (simsPresent == 0)
        {
            enabled = false;
            return;
        }

        // no sims running - abort. don't bother switching off renderer - camera wont be active
        if (simsActive == 0)
        {
            return;
        }

        var disp = _boat.DisplacementToBoat;

        transform.position = transform.parent.TransformPoint(_localOffset) - disp + _velocityPositionOffset * _boat.RB.velocity;

        var rnd = 1f + _noiseAmp * (2f * Mathf.PerlinNoise(_noiseFreq * OceanRenderer.Instance.CurrentTime, 0.5f) - 1f);
        // feed in water velocity
        var vel = (transform.position - _posLast) / Time.deltaTime;

        if (OceanRenderer.Instance._simSettingsFlow != null &&
            OceanRenderer.Instance._simSettingsFlow._readbackData &&
            GPUReadbackFlow.Instance)
        {
            var position     = transform.position;
            var samplingArea = new Rect(position.x, position.z, 0f, 0f);
            GPUReadbackFlow.Instance.GetSamplingData(ref samplingArea, _boat.BoatWidth, _samplingDataFlow);

            Vector2 surfaceFlow;
            GPUReadbackFlow.Instance.SampleFlow(ref position, _samplingDataFlow, out surfaceFlow);

            vel -= new Vector3(surfaceFlow.x, 0, surfaceFlow.y);

            GPUReadbackFlow.Instance.ReturnSamplingData(_samplingDataFlow);
        }
        vel.y *= _weightUpDownMul;

        var speedKmh = vel.magnitude * 3.6f;

        if (speedKmh > _teleportSpeed)
        {
            // teleport detected
            vel *= 0f;

            if (_warnOnTeleport)
            {
                Debug.LogWarning("Teleport detected (speed = " + speedKmh.ToString() + "), velocity discarded.", this);
            }
        }
        else if (speedKmh > _maxSpeed)
        {
            // limit speed to max
            vel *= _maxSpeed / speedKmh;

            if (_warnOnSpeedClamp)
            {
                Debug.LogWarning("Speed (" + speedKmh.ToString() + ") exceeded max limited, clamped.", this);
            }
        }

        _mat.SetVector("_Velocity", rnd * vel);
        _posLast = transform.position;

        _mat.SetFloat("_Weight", _boat.InWater ? _weight / simsActive : 0f);

        float dt; int steps;

        OceanRenderer.Instance._lodDataDynWaves.GetSimSubstepData(Time.deltaTime, out steps, out dt);
        _mat.SetFloat("_SimDeltaTime", dt);
    }