Low Poly Water with Proper Buoyancy

Hi all,

So first, let me start off by saying I’m super new to Unity. I have a background in video production and a specialization in After Effects with expressions, so I’m some what familiar with using code to relate objects.

As a first foray, I’m trying to make a low- poly duck float in low poly water.

I have found a shader online that is essentially this: http://www.battlemaze.com/?p=153 (I think in my hunt a found a newer version somewhere). From what I can tell, I guess it’s manipulating vertices to form the waves.

My question is how to make my duck float on the top of the waves. I’ve seen some people do something or another with rigid body wheels, but I’m unclear on how to even make the ducks gravity respect the waves so that it sits on top (or just a little bit under it).

Any help would be greatly appreciated!

Thanks!

George

Realistic buoyancy is quite difficult to simulate. Even more difficult if your water is based on a shader. Since you specifically mentioned a duck, here’s a talk about buoyancy using a duck as an example!

Ok, so after a bit I’ve developed the system I was talking about, so you should be able to test this on whatever setup you want.

The first script is for the actual water object. I’ve set it up with static variables, and as such it will only work with one water object in the scene. Basically, you attach this to, say, a plane or whatever water object you want and it will deform the mesh based on Unity’s Perlin Noise algorithm. I’d suggest removing the collider from the water object.

using UnityEngine;
using System.Collections;

public class WaterDeformation : MonoBehaviour 
{
	
	public static Mesh mesh;			//The water mesh
	public static Transform water;		//The water transform
	
	public float deformAmount = 1;		//Amount to deform the water
	public float scale = 2.5f;			//How fine the displacement is
	public float speed = 1;				//The speed of waves
	
	private Vector2 time = Vector2.zero;	//The actual speed offset
	
	// Use this for initialization
	void Start () 
	{
		//Set the water and mesh variables at start
		water = transform;
		mesh = GetComponent<MeshFilter>().mesh;
	}
	
	// Update is called once per frame
	void Update () 
	{
		time = new Vector2 (Time.time, Time.time) * speed;			//Set up speed offset for deformation
		
		Vector3[] vertices = mesh.vertices;				//Create a variable for the vertices beforehand
		
		for (int i = 0; i < vertices.Length; i++) {
			vertices _= Deform (vertices*);				//For every vertice, deform the Y position*_

* }*

* mesh.vertices = vertices; //Re-assign the vertices*
* mesh.RecalculateNormals (); //Recalculate the normals so the object doesn’t look flat*
* GetComponent().mesh = mesh; //Re-assign the mesh to the filter*
* }*

* Vector3 Deform (Vector3 v) //Takes a Vector3*
* {*
_ v.y = Mathf.PerlinNoise (v.x / scale + time.x, v.z / scale + time.y) * deformAmount; //Distort the vertice’s Y position based off its X and Z positions + time_
* return v; //Return the offset vertice position*
* }*
}
The second script you attach to any objects you want to have buoyancy. The thing about this is, I’ve never tried to calculate buoyancy myself, so instead what it does is it adds force upwards if the object is below the water at the nearest point.
using UnityEngine;
using System.Collections;

public class Buoyancy : MonoBehaviour
{

* public float buoyancy = 20; //Buoyancy force*
public float viscosity = 20; //How easily an object can move through the water

* private Rigidbody rb; //Rigidbody attached to this object*

* // Use this for initialization*
* void Start ()*
* {*
* rb = GetComponent(); //Set the rigidbody at startup*
* }*

* // Update is called once per frame*
* void FixedUpdate ()*
* {*
* Vector3[] vertices = WaterDeformation.mesh.vertices; //Find the water’s vertices*
* Vector3[] worldVerts = new Vector3[vertices.Length]; //Create a new array to store world space vertex positions*

* for (int i = 0; i < vertices.Length; i++) {*
worldVerts = WaterDeformation.water.TransformPoint (vertices*); //For every vertex, transform the position into world space*
* }*

* Vector3 nearestVert = NearestVertice (transform.position, worldVerts); //Find the nearest vertice to this object*

* if (transform.position.y < nearestVert.y) { //If this object is below the nearest vertice*
_ rb.AddForce (Vector3.up * buoyancy); //Apply force upwards_
rb.velocity /= ((viscosity / 100) + 1); //Slow the objects movements when in water
}
* }*

* Vector3 NearestVertice (Vector3 pos, Vector3[] verts) //Takes a position and a position array*
* {*
* Vector3 nearestVert = Vector3.zero; //Create the initial nearestVert variable and initialise it*
* float minDist = 100; //Declare the min dist (can be whatever you want, something large though)*

* for (int i = 0; i < verts.Length; i++) { //For every vertice*
_ if (Vector3.Distance (pos, verts*) < minDist) { //If the vertice is closer than the one before it*
nearestVert = verts*; //Set the nearest vertice variable*
minDist = Vector3.Distance (pos, verts*); //Update the minDist*
* }
}*_

* return nearestVert; //Return the nearest vertice*
* }*
}