/// <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); }
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; } }
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); }
/// <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); } }
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(); }
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(); }
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(); }