End Result
Here's what we're going to end up with. You'll need the Unity browser plugin to try it out.
![]() |
In his tutorial, Michael Hoffman demonstrated how we can model the surface of water with a row of springs.
We're going to render the top of our water using one of Unity's line renderers, and use so many nodes that it appears as a continuous wave.
We'll have to keep track of the positions, velocities and accelerations of every node, though. To do that, we're going to use arrays. So at the top of our class we'll add these variables:
- float[] xpositions;
- float[] ypositions;
- float[] velocities;
- float[] accelerations;
- LineRenderer Body;
- GameObject[] meshobjects;
- Mesh[] meshes;
- GameObject[] colliders;
- const float springconstant = 0.02f;
- const float damping = 0.04f;
- const float spread = 0.05f;
- const float z = -1f;
Next, we're going to hold onto some values:
- float baseheight;
- float left;
- float bottom;
We're going to need some public variables we can set in the editor, too. First, the particle system we're going to use for our splashes:
- public GameObject splash:
- public Material mat:
- public GameObject watermesh:
We want a game object that can hold all of this data, act as a manager, and spawn our body of water ingame to specification. To do that, we'll write a function called SpawnWater().
This function will take inputs of the left side, the width, the top, and the bottom of the body of water.
- public void SpawnWater(float Left, float Width, float Top, float Bottom)
- {
Creating the Nodes
Now we're going to find out how many nodes we need:
- int edgecount = Mathf.RoundToInt(Width) * 5;
- int nodecount = edgecount + 1;
The first thing we're going to do is render our body of water with the LineRenderer component:
- Body = gameObject.AddComponent<LineRenderer>();
- Body.material = mat;
- Body.material.renderQueue = 1000;
- Body.SetVertexCount(nodecount);
- Body.SetWidth(0.1f, 0.1f);
You can vary this depending on how thick you want your line. You may have noticed that SetWidth() takes two parameters; these are the width at the start and the end of the line. We want that width to be constant.
Now that we've made our nodes, we'll initialise all our top variables:
- xpositions = new float[nodecount];
- ypositions = new float[nodecount];
- velocities = new float[nodecount];
- accelerations = new float[nodecount];
- meshobjects = new GameObject[edgecount];
- meshes = new Mesh[edgecount];
- colliders = new GameObject[edgecount];
- baseheight = Top;
- bottom = Bottom;
- left = Left;
Now to actually set the values of our arrays. We'll start with the nodes:
- for (int i = 0; i < nodecount; i++)
- {
- ypositions[i] = Top;
- xpositions[i] = Left + Width * i / edgecount;
- accelerations[i] = 0;
- velocities[i] = 0;
- Body.SetPosition(i, new Vector3(xpositions[i], ypositions[i], z));
- }
We finish the loop by setting each node in our LineRenderer (Body) to their correct position.
Creating the Meshes
Here's where it gets tricky.
We have our line, but we don't have the water itself. And the way we can make this is using Meshes. We'll start off by creating these:
- for (int i = 0; i < edgecount; i++)
- {
- meshes[i] = new Mesh();
![]() |
- Vector3[] Vertices = new Vector3[4];
- Vertices[0] = new Vector3(xpositions[i], ypositions[i], z);
- Vertices[1] = new Vector3(xpositions[i + 1], ypositions[i + 1], z);
- Vertices[2] = new Vector3(xpositions[i], bottom, z);
- Vertices[3] = new Vector3(xpositions[i+1], bottom, z);
The second property that meshes need is UVs. Meshes have textures, and the UVs choose which part of the textures we want to grab. In this case, we just want the top-left, top-right, bottom-left, and bottom-right corners of our texture.
- Vector2[] UVs = new Vector2[4];
- UVs[0] = new Vector2(0, 1);
- UVs[1] = new Vector2(1, 1);
- UVs[2] = new Vector2(0, 0);
- UVs[3] = new Vector2(1, 0);
![]() |
- int[] tris = new int[6] { 0, 1, 3, 3, 2, 0 };
- meshes[i].vertices = Vertices;
- meshes[i].uv = UVs;
- meshes[i].triangles = tris;
- meshobjects[i] = Instantiate(watermesh,Vector3.zero,Quaternion.identity) as GameObject;
- meshobjects[i].GetComponent<MeshFilter>().mesh = meshes[i];
- meshobjects[i].transform.parent = transform;
Written by Alex Rose
If you found this post interesting, follow and support us.
Suggest for you:
Make VR Games in Unity with C# - Cardboard, Gear VR, Oculus
Learn to Code by Making Games - The Complete Unity Developer
Make a Multiplayer Shooter in Unity
Unity 5 Host Your Game Server Online like a PRO
Start Learning Unity3d by Making 5 Games from Scratch



No comments:
Post a Comment