Floating objects

By Tein Schoemaker

Intro

One of the assignments we got this year for the Gameplay Engineering course was the creation and manipulation of shaders. I used this assignment to create a plane that simulated simple wave movements but in the end the waves only moved up and down and the end result was a bit basic. I wasn’t fully statisfied with the results. Instead I wanted to use this R&D project to expand on the core concept and not only create more visually impressive waves but also affecting objects on with these waves, using buoancy to let them flow up and down.

For my R&D project I go through different stages ranked by priority:

  1. Adding floatyness to objects (aka buoyancy)
  2. Creating good looking waves (visuals and animation)
  3. Implementing player input (gameplay in the shape of a boat
  4. Extra fluff (any extra features that I might have time for in the final week(s))

My end goal is a working scene where you can control a boat on realistic looking waves and trying to get the most accurate simulation of how that boat would react to the moving waves. For the waves I know I can use Shadergraph to get them visually to look good but as far as the wave movement, the object buoyancy and the boat movement I have no prior experience.

“Follow the law of buoyancy. Stay light and float.”

-Shrishtika Balamurugan

Buoyancy

I started by placing down the basic waving plane that I already had and placing objects on top of it. The first scientifical finding I had was that if you make the mesh of an object move then it doesn’t directly mean that the colliders of that object will move with it. Pretty logical if you think about it but seeing as my plane was already moving I had already sort of created the illusion for myself that any objects on top of it with a rigidbody would move with it too. I felt a bit foolish but it also inspired my sollution right away. The mesh doesnt have to directly affect the object as long as the object simply moves in the same way that the waves would so that it looks like they directly affect each other.

So to start my project off I simply created a piece of code that would give the object with the script attached an upward force whenever it went below the waterline.

Because I had no way to interact between my fake waves and the object yet the waterline was simply 0 on the y axis but this simple piece of code already gave me pretty accurate results. Dropping an object into the scene made it bob slightly up and down just like if you would drop a ball into a pool. Dragging the object downwards below the “waterline” and then releasing it even made the object shoot out of the water and land back down to still bob up and down slightly until it finally loses momentum. A pretty accurate result for a first attempt.

“Be brief, be buoyant and be brilliant.”

-Brander Matthews

Waves

For the waves I had my simple moving mesh at the start where every vertices in the mesh would slowly move up and down creating very linear and predictable waves. If you compared this to real life ocean waves they are nothing alike. Ocean waves bop up and down, they roll over each other, they feel alive.

Although all physics in Unity are done through math I still wanted to make my project look like there wasnt a simple algorithm to it, it needed a touch of randomness. When you look at waves in the ocean they are constantly being manipulated: There are wild winds, there’s constantly changing temperatures, and there are the gravitational forces of the moon. All these factors don’t have rules when it comes to interaction between each other but they all affect the ocean waters on earth.

In the simpelest terms: Waves are created by the energy moving through water.

To create the most accurate waves visually I was told it was easiest to use a shadergraph. Shadergraph is a tool that lets you visually edit shaders which should be an easier way than manually coding your shaders. Now personally I did not have any any prior experience using shadergraph but there are hundreds of tutorials online that show off accurately on how to create such realistic looking waves so I felt confident this was the right way to go about it.

A little intimidating but alright...
(A little intimidating but alright…)

Basically what’s happening in this shadergraph is the following:

In the bottom left of my shadergraph I take the height and the position of the uv’s on the wave plane and assign them a darker color the higher the wave gets.

Towards the middle the shadergraph we add the Fresnel effect which allows for reflectance of the surface color based on the angle that you’re looking at. (Think of a mirror that bends the light)

And lastly at the top the shadergraph takes the two colors, light and dark blue, and let’s them transition into each other instead of being two colors apart to give it a more natural feeling.

The colors might have been correct but the issue that still remained however was the movement. Although yes the waves where less straight and where now more rolling and curved like a real ocean wave would be, the waves where sadly still repeating and predictable, much unlike real ocean waves. What I needed where Gerstner waves.

Gerstner waves are a simple formula that simulate ocean waves quite accurately. Instead of a vertices only moving up and down to create a wave like effect I also move every vertices to the left and right while going up and down at the same time. With this simpe idea I can massively increase the natural feeling of the ocean waves because they dont just bob up and down, they roll over each other the same way you find waves washing up against the beach.

Then to add a touch more natural “randomness” I add multiple gerstner waves inside of each other. Allowing for personal customization inside of the inspector I can create the size and speed of my own waves and also add aditional elements which get put in a sort of queue, allowing my script to play each custom wave one after the other to make the ocean as a whole look more realistic.

Allowing me to play with the results like this:

“Succes comes in waves”

-Guy Pearce

Boat

Lastly I wanted some player interaction within my scene. Moving floating objects around in the editor shows the buoyancy quite well but actually being able to play something is much more interesting. In my opinion the most fun way we humans can interact with water, while also showing off my buoyancy, is with a boat.

My prototype floating boat consisted of a stretched out cube with a rudder in the back, nothing fancy but just perfect for experimentation.

This tiny little thing I assign a “motor” object to which is visualised by the rudder on the back of the boat. depending on which way the rudder is rotated the boat can is pushed of pulled forward and backward with a force positioned at the rudder, allowing it to traverse the waters just like a real life boat would.

Finally I also add my buoyancy script to the boat so it can also float just like the rest of the objects in the scene which paints for a pretty picture. The scene as a whole clearly does still need some brushing up.

“Ships don’t sink because the water around them; Ships sink because of the water that gets in them. Don’t let what’s happening around you get inside and weigh you down.”

-Unknown poet

Upgrades

The buoyancy was working but it was far from perfect. Although the objects with the script did move the same way that the waves did they did not look very smooth or graceful, instead stuttering because one side of the floating points might already be climbing up a wave while the other side was already sliding down. This made the movement a bit janky especially when the waves where turned up to a more wild setting.

Instead giving the object a constant upward force the movement should be smooth, it should be subtle, it should be Smooth Damped. Using Vector3.SmoothDamp in unity we can transitions from the one value to the other in a smooth and linear fashion. This is ideal for our floatyness because when you see boats floating on ocean waves the also dont quickly jump up and down to ride the wave but they gently slide over them, at least that’s how it looks like from a distance.

But from where to where do we need to be SmoothDampening? Our already well defined floating points are a good end point but from where do we start? At this point it no longer made sense to me to have a visual wave and a physical wave, or at the very least it didnt make sense to have them not influence each other. Instead I added a function in my wave generation that picks up the height of each vertices at all times and passes this on into my floaty script.

With this new water height aquired I can start creating two points: The floating points (green) & The water line points (red) are the two new values from which we can start to SmoothDamp. The floating points are manually assigned just like before but the WaterLinePoints are constantly being updated by the wave generation script. They move up and down based on the Y-position of the wave that is currently sharing the X-position of the FloatingPoint.

And as mentioned before the SmoothDamp is applied whenever one of the points is below the current water level.

“Upgrades people, upgrades!”

-Phineas T. Ratchet

Conclusion

In the end I tried to create an ocean with floating objects on top that look more realistic than the basic shader movements I had attempted before and I think to that extent I certainly succeeded.

The biggest contributors to this final result are the multiple Gerstner waves that create a wild and seemingly random natural ocean and of course the input of my own guild that inspired the smooth movement of the floating points.

In my original goal I intended to make the ocean an infinite plane this however did not end up happening in the final result. I had tried by attatching the ocean to the camera that would in turn follow the boat object and this did result in an “infinite” ocean but did not create any sense of movement. My second plan was to spawn a new plane in the direction that the boat would be moving so the ocean would always keep on going but this too caused issues because the random waves of 1 plane would not synchronize with a new plane which made it very clearly look like two different oceans next to each other.

What I could/should have done to still create a sense of an infinite ocean without having to re-write a big part of my code is have the uv’s of the ocean shader scroll based on player movement, this way I could have kept the height/movement of my gerstner waves but also have a sense of movement as it would have moved in the opposite direction than that the boat would have, still creating the illusion that my ocean was in fact infinite.

Sources