Created
October 21, 2025 19:13
-
-
Save tombasche/5d96747be60b902b837b47ef4fb97fea to your computer and use it in GitHub Desktop.
Water buoyancy in Unity
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| Attach this to an object you want to "float" on a surface. | |
| For this component to work you need to supply an array of Transforms indicating the points | |
| on the object that will have the buoyancy applied to it. For instance, a cube may have points on each corner touching the surface. | |
| */ | |
| using UnityEngine; | |
| [RequireComponent(typeof(Rigidbody))] | |
| public class BuoyantObject : MonoBehaviour | |
| { | |
| private readonly Color red = new(0.92f, 0.25f, 0.2f); | |
| private readonly Color green = new(0.2f, 0.92f, 0.51f); | |
| private readonly Color blue = new(0.2f, 0.67f, 0.92f); | |
| private readonly Color orange = new(0.97f, 0.79f, 0.26f); | |
| [Header("Water")] | |
| [SerializeField] private float waterHeight = 0.0f; | |
| [Header("Waves")] | |
| [SerializeField] float steepness; | |
| [SerializeField] float wavelength; | |
| [SerializeField] float speed; | |
| [SerializeField] float[] directions = new float[4]; | |
| [Header("Buoyancy")] | |
| [Range(1, 5)] public float strength = 1f; | |
| [Range(0.2f, 5)] public float objectDepth = 1f; | |
| public float velocityDrag = 0.99f; | |
| public float angularDrag = 0.5f; | |
| [Header("Effectors")] | |
| public Transform[] effectors; | |
| private Rigidbody rb; | |
| private Vector3[] effectorProjections; | |
| private void Awake() | |
| { | |
| // Get rigidbody | |
| rb = GetComponent<Rigidbody>(); | |
| rb.useGravity = false; | |
| effectorProjections = new Vector3[effectors.Length]; | |
| for (var i = 0; i < effectors.Length; i++) effectorProjections[i] = effectors[i].position; | |
| } | |
| private void OnDisable() | |
| { | |
| rb.useGravity = true; | |
| } | |
| private void FixedUpdate() | |
| { | |
| var effectorAmount = effectors.Length; | |
| for (var i = 0; i < effectorAmount; i++) | |
| { | |
| var effectorPosition = effectors[i].position; | |
| effectorProjections[i] = effectorPosition; | |
| effectorProjections[i].y = waterHeight + GerstnerWaveDisplacement.GetWaveDisplacement(effectorPosition, steepness, wavelength, speed, directions).y; | |
| // gravity | |
| rb.AddForceAtPosition(Physics.gravity / effectorAmount, effectorPosition, ForceMode.Acceleration); | |
| var waveHeight = effectorProjections[i].y; | |
| var effectorHeight = effectorPosition.y; | |
| if (!(effectorHeight < waveHeight)) continue; // submerged | |
| var submersion = Mathf.Clamp01(waveHeight - effectorHeight) / objectDepth; | |
| var buoyancy = Mathf.Abs(Physics.gravity.y) * submersion * strength; | |
| // buoyancy | |
| rb.AddForceAtPosition(Vector3.up * buoyancy, effectorPosition, ForceMode.Acceleration); | |
| // drag | |
| rb.AddForce(-rb.linearVelocity * (velocityDrag * Time.fixedDeltaTime), ForceMode.VelocityChange); | |
| // torque | |
| rb.AddTorque(-rb.angularVelocity * (angularDrag * Time.fixedDeltaTime), ForceMode.Impulse); | |
| } | |
| } | |
| private void OnDrawGizmos() | |
| { | |
| if (effectors == null) return; | |
| for (var i = 0; i < effectors.Length; i++) | |
| { | |
| if (!Application.isPlaying && effectors[i] != null) | |
| { | |
| Gizmos.color = green; | |
| Gizmos.DrawSphere(effectors[i].position, 0.06f); | |
| } | |
| else | |
| { | |
| if (effectors[i] == null) return; | |
| Gizmos.color = effectors[i].position.y < effectorProjections[i].y ? red : green; // submerged | |
| Gizmos.DrawSphere(effectors[i].position, 0.06f); | |
| Gizmos.color = orange; | |
| Gizmos.DrawSphere(effectorProjections[i], 0.06f); | |
| Gizmos.color = blue; | |
| Gizmos.DrawLine(effectors[i].position, effectorProjections[i]); | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment