Example #1
0
        /// <summary>
        /// Get the water height at the given world position
        /// </summary>
        /// <param name="worldPos">3D world position</param>
        /// <param name="minWaveLength">Optional: ignore wave lengths below this value; with ships use the ship width for this value</param>
        /// <returns>The height of the ocean at the given world position</returns>
        public static float SampleWaterHeight(Vector3 worldPos, float minWaveLength = 0f)
        {
            float height = 0f;

            SampleHeightHelper sampler = new SampleHeightHelper();

            sampler.Init(worldPos, minWaveLength);
            sampler.Sample(ref height);

            return(height);
        }
Example #2
0
    void Update()
    {
        // Assume a primitive like a sphere or box.
        var r = transform.lossyScale.magnitude;

        _sampleHeightHelper.Init(transform.position, 2f * r);

        if (_sampleHeightHelper.Sample(out var height))
        {
            var pos = transform.position;
            pos.y = height;
            transform.position = pos;
        }
    }
Example #3
0
    void Update()
    {
        if (OceanRenderer.Instance == null)
        {
            return;
        }

        _sampleHeightHelper.Init(transform.position, 0f);
        _sampleHeightHelper.Sample(out var h);

        var targetPos = _targetPos.position;

        targetPos.y = Mathf.Max(targetPos.y, h + _minHeightAboveWater);

        transform.position = Vector3.Lerp(transform.position, targetPos, _lerpAlpha * OceanRenderer.Instance.DeltaTime * 60f);
        transform.LookAt(_targetLookatPos.position + _lookatOffset * Vector3.up);
    }
Example #4
0
    /// <summary>
    /// Align to water normal. One normal by default, but can use a separate normal based on boat length vs width. This gives
    /// varying rotations based on boat dimensions.
    /// </summary>
    void FixedUpdateOrientation(ICollProvider collProvider, Vector3 normalSideways)
    {
        Vector3 normal = normalSideways, normalLongitudinal = Vector3.up;

        if (_useBoatLength)
        {
            _sampleHeightHelperLengthwise.Init(transform.position, _boatLength, true);
            var dummy = 0f;
            if (_sampleHeightHelperLengthwise.Sample(ref dummy, ref normalLongitudinal))
            {
                var F = transform.forward;
                F.y = 0f;
                F.Normalize();
                normal -= Vector3.Dot(F, normal) * F;

                var R = transform.right;
                R.y = 0f;
                R.Normalize();
                normalLongitudinal -= Vector3.Dot(R, normalLongitudinal) * R;
            }
        }

        if (_debugDraw)
        {
            Debug.DrawLine(transform.position, transform.position + 5f * normal, Color.green);
        }
        if (_debugDraw && _useBoatLength)
        {
            Debug.DrawLine(transform.position, transform.position + 5f * normalLongitudinal, Color.yellow);
        }

        var torqueWidth = Vector3.Cross(transform.up, normal);

        _rb.AddTorque(torqueWidth * _boyancyTorque, ForceMode.Acceleration);
        if (_useBoatLength)
        {
            var torqueLength = Vector3.Cross(transform.up, normalLongitudinal);
            _rb.AddTorque(torqueLength * _boyancyTorque, ForceMode.Acceleration);
        }
    }
Example #5
0
    void FixedUpdate()
    {
        if (OceanRenderer.Instance == null)
        {
            return;
        }

        UnityEngine.Profiling.Profiler.BeginSample("BoatAlignNormal.FixedUpdate");

        var collProvider = OceanRenderer.Instance.CollisionProvider;
        var position     = transform.position;

        _sampleHeightHelper.Init(transform.position, _boatWidth, true);
        var height          = OceanRenderer.Instance.SeaLevel;
        var disp            = Vector3.zero;
        var normal          = Vector3.up;
        var waterSurfaceVel = Vector3.zero;

        _sampleHeightHelper.Sample(ref disp, ref normal, ref waterSurfaceVel);

        // height = base sea level + surface displacement y
        height += disp.y;

        {
            _sampleFlowHelper.Init(transform.position, _boatWidth);

            Vector2 surfaceFlow = Vector2.zero;
            _sampleFlowHelper.Sample(ref surfaceFlow);
            waterSurfaceVel += new Vector3(surfaceFlow.x, 0, surfaceFlow.y);
        }

        // I could filter the surface vel as the min of the last 2 frames. theres a hard case where a wavelength is turned on/off
        // which generates single frame vel spikes - because the surface legitimately moves very fast.

        if (_debugDraw)
        {
            Debug.DrawLine(transform.position + 5f * Vector3.up, transform.position + 5f * Vector3.up + waterSurfaceVel,
                           new Color(1, 1, 1, 0.6f));
        }

        var velocityRelativeToWater = _rb.velocity - waterSurfaceVel;

        float bottomDepth = height - transform.position.y - _bottomH;

        _inWater = bottomDepth > 0f;
        if (!_inWater)
        {
            UnityEngine.Profiling.Profiler.EndSample();
            return;
        }

        var buoyancy = -Physics.gravity.normalized * _buoyancyCoeff * bottomDepth * bottomDepth * bottomDepth;

        _rb.AddForce(buoyancy, ForceMode.Acceleration);


        // apply drag relative to water
        var forcePosition = _rb.position + _forceHeightOffset * Vector3.up;

        _rb.AddForceAtPosition(Vector3.up * Vector3.Dot(Vector3.up, -velocityRelativeToWater) * _dragInWaterUp, forcePosition, ForceMode.Acceleration);
        _rb.AddForceAtPosition(transform.right * Vector3.Dot(transform.right, -velocityRelativeToWater) * _dragInWaterRight, forcePosition, ForceMode.Acceleration);
        _rb.AddForceAtPosition(transform.forward * Vector3.Dot(transform.forward, -velocityRelativeToWater) * _dragInWaterForward, forcePosition, ForceMode.Acceleration);

        float forward    = _throttleBias;
        float rawForward = Input.GetAxis("Vertical");

        if (_playerControlled)
        {
            forward += rawForward;
        }
        _rb.AddForceAtPosition(transform.forward * _enginePower * forward, forcePosition, ForceMode.Acceleration);

        float reverseMultiplier = (rawForward < 0f ? -1f : 1f);
        float sideways          = _steerBias;

        if (_playerControlled)
        {
            sideways +=
                (Input.GetKey(KeyCode.A) ? reverseMultiplier * -1f : 0f) +
                (Input.GetKey(KeyCode.D) ? reverseMultiplier * 1f : 0f);
        }
        _rb.AddTorque(transform.up * _turnPower * sideways, ForceMode.Acceleration);

        FixedUpdateOrientation(collProvider, normal);

        UnityEngine.Profiling.Profiler.EndSample();
    }
Example #6
0
    void FixedUpdate()
    {
        if (OceanRenderer.Instance == null)
        {
            return;
        }

        UnityEngine.Profiling.Profiler.BeginSample("BoatAlignNormal.FixedUpdate");

        _sampleHeightHelper.Init(transform.position, _boatWidth, true);
        var height = OceanRenderer.Instance.SeaLevel;

        _sampleHeightHelper.Sample(out Vector3 disp, out var normal, out var waterSurfaceVel);

        // height = base sea level + surface displacement y
        height += disp.y;

        {
            _sampleFlowHelper.Init(transform.position, _boatWidth);

            _sampleFlowHelper.Sample(out var surfaceFlow);
            waterSurfaceVel += new Vector3(surfaceFlow.x, 0, surfaceFlow.y);
        }

        // I could filter the surface vel as the min of the last 2 frames. theres a hard case where a wavelength is turned on/off
        // which generates single frame vel spikes - because the surface legitimately moves very fast.

        if (_debugDraw)
        {
            Debug.DrawLine(transform.position + 5f * Vector3.up, transform.position + 5f * Vector3.up + waterSurfaceVel,
                           new Color(1, 1, 1, 0.6f));
        }

        var velocityRelativeToWater = _rb.velocity - waterSurfaceVel;

        float bottomDepth = height - transform.position.y - _bottomH;

        _inWater = bottomDepth > 0f;
        if (!_inWater)
        {
            UnityEngine.Profiling.Profiler.EndSample();
            return;
        }

        var buoyancy = -Physics.gravity.normalized * _buoyancyCoeff * bottomDepth * bottomDepth * bottomDepth;

        _rb.AddForce(buoyancy, ForceMode.Acceleration);

        // Approximate hydrodynamics of sliding along water
        if (_accelerateDownhill > 0f)
        {
            _rb.AddForce(new Vector3(normal.x, 0f, normal.z) * -Physics.gravity.y * _accelerateDownhill, ForceMode.Acceleration);
        }

        // apply drag relative to water
        var forcePosition = _rb.position + _forceHeightOffset * Vector3.up;

        _rb.AddForceAtPosition(Vector3.up * Vector3.Dot(Vector3.up, -velocityRelativeToWater) * _dragInWaterUp, forcePosition, ForceMode.Acceleration);
        _rb.AddForceAtPosition(transform.right * Vector3.Dot(transform.right, -velocityRelativeToWater) * _dragInWaterRight, forcePosition, ForceMode.Acceleration);
        _rb.AddForceAtPosition(transform.forward * Vector3.Dot(transform.forward, -velocityRelativeToWater) * _dragInWaterForward, forcePosition, ForceMode.Acceleration);

        float forward = _throttleBias;

#if ENABLE_INPUT_SYSTEM
        float rawForward = (Keyboard.current.wKey.isPressed ? 1 : 0) + (Keyboard.current.sKey.isPressed ? -1 : 0);
#else
        float rawForward = Input.GetAxis("Vertical");
#endif
        if (_playerControlled)
        {
            forward += rawForward;
        }
        _rb.AddForceAtPosition(transform.forward * _enginePower * forward, forcePosition, ForceMode.Acceleration);

        float reverseMultiplier = (rawForward < 0f ? -1f : 1f);
        float sideways          = _steerBias;
        if (_playerControlled)
        {
            sideways +=
#if ENABLE_INPUT_SYSTEM
                (Keyboard.current.aKey.isPressed ? reverseMultiplier * -1f : 0f) +
                (Keyboard.current.dKey.isPressed ? reverseMultiplier * 1f : 0f);
        }
#else
                (Input.GetKey(KeyCode.A) ? reverseMultiplier * -1f : 0f) +
                (Input.GetKey(KeyCode.D) ? reverseMultiplier * 1f : 0f);
#endif
        _rb.AddTorque(transform.up * _turnPower * sideways, ForceMode.Acceleration);

        FixedUpdateOrientation(normal);

        UnityEngine.Profiling.Profiler.EndSample();
    }
Example #7
0
    void FixedUpdate()
    {
        if (OceanRenderer.Instance == null)
        {
            return;
        }

        UnityEngine.Profiling.Profiler.BeginSample("BoatAlignNormal.FixedUpdate");

        _sampleHeightHelper.Init(transform.position, _boatWidth, true);
        var height = OceanRenderer.Instance.SeaLevel;

        _sampleHeightHelper.Sample(out Vector3 disp, out var normal, out var waterSurfaceVel);

        // height = base sea level + surface displacement y
        height += disp.y;

        {
            _sampleFlowHelper.Init(transform.position, _boatWidth);

            _sampleFlowHelper.Sample(out var surfaceFlow);
            waterSurfaceVel += new Vector3(surfaceFlow.x, 0, surfaceFlow.y);
        }

        // I could filter the surface vel as the min of the last 2 frames. theres a hard case where a wavelength is turned on/off
        // which generates single frame vel spikes - because the surface legitimately moves very fast.

        if (_debugDraw)
        {
            Debug.DrawLine(transform.position + 5f * Vector3.up, transform.position + 5f * Vector3.up + waterSurfaceVel,
                           new Color(1, 1, 1, 0.6f));
        }

        var velocityRelativeToWater = _rb.velocity - waterSurfaceVel;

        float bottomDepth = height - transform.position.y - _bottomH;

        _inWater = bottomDepth > 0f;
        if (!_inWater)
        {
            UnityEngine.Profiling.Profiler.EndSample();
            return;
        }

        var buoyancy = -Physics.gravity.normalized * _buoyancyCoeff * bottomDepth * bottomDepth * bottomDepth;

        _rb.AddForce(buoyancy, ForceMode.Acceleration);

        // apply drag relative to water
        var forcePosition = _rb.position + _forceHeightOffset * Vector3.up;

        _rb.AddForceAtPosition(Vector3.up * Vector3.Dot(Vector3.up, -velocityRelativeToWater) * _dragInWaterUp, forcePosition, ForceMode.Acceleration);
        _rb.AddForceAtPosition(transform.right * Vector3.Dot(transform.right, -velocityRelativeToWater) * _dragInWaterRight, forcePosition, ForceMode.Acceleration);
        _rb.AddForceAtPosition(transform.forward * Vector3.Dot(transform.forward, -velocityRelativeToWater) * _dragInWaterForward, forcePosition, ForceMode.Acceleration);

        float rawForward = Input.GetAxis("Vertical");

        _submarineSpeed += rawForward * Time.deltaTime * 0.3f;
        _submarineSpeed  = Mathf.Clamp(_submarineSpeed, -0.25f, 1f);
        _rb.AddForceAtPosition(transform.forward * _enginePower * _submarineSpeed, forcePosition, ForceMode.Acceleration);

        float sideways = _steerBias;

        if (_playerControlled)
        {
            sideways +=
                (Input.GetKey(KeyCode.A) ? -1f : 0f) +
                (Input.GetKey(KeyCode.D) ? 1f : 0f);
        }
        _rb.AddTorque(transform.up * _turnPower * sideways, ForceMode.Acceleration);

        // up
        if (Input.GetKey(KeyCode.E) == true)
        {
            if (_buoyancyFactor < 1f)
            {
                _buoyancyFactor += Time.deltaTime * 0.1f;
                _buoyancyFactor  = Mathf.Clamp(_buoyancyFactor, 0f, 1f);
                _buoyancyCoeff   = _buoyancyCurveFactor.Evaluate(_buoyancyFactor);
            }

            _hullUpDown = Mathf.Lerp(_hullUpDown, -10f, Time.deltaTime * 1.15f);
            _tailUpDown = Mathf.Lerp(_tailUpDown, 30f, Time.deltaTime * 3);
        }

        // down
        if (Input.GetKey(KeyCode.Q) == true)
        {
            if (_buoyancyFactor > 0f)
            {
                _buoyancyFactor -= Time.deltaTime * 0.1f;
                _buoyancyFactor  = Mathf.Clamp(_buoyancyFactor, 0f, 1f);
                _buoyancyCoeff   = _buoyancyCurveFactor.Evaluate(_buoyancyFactor);
            }

            _hullUpDown = Mathf.Lerp(_hullUpDown, 10f, Time.deltaTime * 1.15f);
            _tailUpDown = Mathf.Lerp(_tailUpDown, -30f, Time.deltaTime * 3);
        }

        _hullUpDown = Mathf.Lerp(_hullUpDown, 0f, Time.deltaTime);
        _hullUpDown = Mathf.Clamp(_hullUpDown, -10f, 10f);

        _tailUpDown = Mathf.Lerp(_tailUpDown, 0f, Time.deltaTime);
        _tailUpDown = Mathf.Clamp(_tailUpDown, -30f, 30f);

        UpdateHull();
        UpdateTail();
        UpdatePropeller();

        FixedUpdateOrientation(normal);

        UnityEngine.Profiling.Profiler.EndSample();
    }