I was hunting the Scripting forum and ran across a person asking how to do moving water… Which got me to thinking. Being a person who is still “learning” Unity. So I did some searches. They said “Oh, just apply this formula” which was basically a sine wave, and you will get moving waves. That is nice and all, but what happens when a person doesn’t really know where to start to begin with?
So what I did was to create a small script that handles the simplest part. Create a plane, make it move. Give some basic parameters for what we are doing and viola. Water…
Of course its all free to use, I don’t need credit. Its a learning tool… (give me credit all you want if everything goes great, if it doesn’t, don’t give me any credit… LOL)
Usage: Make a box, stretch it out… Apply a water material to it… drag the script below to it… Water… It even transforms the box into a trigger.
NOTE: The bigger you make your box… the more vertices that this thing eats up. (of course)
var vScale=0.025;
var speed1=0.007;
var speed2=0.001;
private var size;
private var doUpdate=false;
function Start () {
this.gameObject.name="Water";
//this.tag="Water";
this.collider.isTrigger=true;
// figure out what size the box is
size=this.transform.localScale;
size.x=Mathf.Abs(size.x);
size.y=Mathf.Abs(size.y);
size.z=Mathf.Abs(size.z);
if(size.x<5.0 || size.z<5.0)
return;
// figure out how many verts and triangles we need
var hCount=parseInt(size.x/2);
var vCount=parseInt(size.z/2);
var hCount2=hCount+1;
var vCount2=vCount+1;
var numTriangles = hCount * vCount * 6;
var numVertices = hCount2 * vCount2;
if(numVertices>64999){
print("Your water has too many vertices("+numVertices+" of 65000), make it smaller");
return;
}
doUpdate=true;
var newVertices : Vector3[]= new Vector3[numVertices];
var newUV : Vector2[]=new Vector2[numVertices];
var newTangents : Vector4[]=new Vector4[numVertices];
var newTriangles : int[]=new int[numTriangles];
var index=0;
var scale : float=(size.x + size.z)/5;
var uvx : float=1.0/hCount * scale;
var uvy : float=1.0/vCount * scale;
var scalex : float=1.0/hCount;
var scaley : float=1.0/vCount;
var x=0.0;
var y=0.0;
// make the verts
for(y=0; y<vCount2; y++){
for(x=0; x<hCount2; x++){
newVertices[index]=Vector3(-0.5+x*scalex, 0.5,-0.5+y*scaley);
newUV[index] = Vector2(x*uvx, y*uvy);
newTangents[index++]=Vector4(0,1,0,1);
}
}
// make the faces
index=0;
for(y=0; y<vCount; y++){
for(x=0; x<hCount; x++){
newTriangles[index] = (y * hCount2) + x;
newTriangles[index+1] = ((y+1) * hCount2) + x;
newTriangles[index+2] = (y * hCount2) + x + 1;
newTriangles[index+3] = ((y+1) * hCount2) + x;
newTriangles[index+4] = ((y+1) * hCount2) + x + 1;
newTriangles[index+5] = (y * hCount2) + x + 1;
index += 6;
}
}
// Clear the box, and replace it with the mesh
var mesh : Mesh = new Mesh ();
GetComponent(MeshFilter).mesh = mesh;
mesh.Clear();
mesh.vertices = newVertices;
mesh.uv = newUV;
mesh.triangles = newTriangles;
mesh.tangents= newTangents;
}
function Update () {
if(! doUpdate)
return;
var mesh : Mesh = GetComponent(MeshFilter).mesh;
var vertices = mesh.vertices;
var scale : float=(size.x + size.z)/2;
var offset : float=0.0;
for (var i=0; i<vertices.Length; i++)
{
offset=0.0;
//calculate waveform 1
offset +=Mathf.Sin(((Time.time*speed1 + (vertices[i].x + vertices[i].z)*0.5) % (3.14/2)) * scale);
//calculate waveform2
offset += Mathf.Sin((Time.time*speed2 + (vertices[i].z)) * scale);
vertices[i].y = 0.5 + offset * vScale;
//vertices[i].y += Random.Range(-0.01, 0.01);
}
mesh.vertices = vertices;
mesh.RecalculateNormals();
}
// do stuff when we are in the water
function OnTriggerEnter(other : Collider) {
print(other.gameObject.name + " has entered the water!");
}
function OnTriggerExit(other : Collider) {
print(other.gameObject.name + " has exited the water!");
}
what is the first error? looks like there is a problem setting up the arrays. Unfortunately I am not having the same issue. And what version are you running on? I need to add some indicators on how big the box can be. Seems that it cannot have more then 65000 vertices.
This script was running and served my needs well until I updated to Unity 3.3.
now it won’t compile due to two lines: 73 and 84.
Any ideas?
Lines 73 84:
GetComponent(MeshFilter).mesh = mesh;
var mesh : Mesh = GetComponent(MeshFilter).mesh;
The current code from BigMisterB:
var vScale=0.025;
var speed1=0.007;
var speed2=0.001;
private var size;
private var doUpdate=false;
function Start () {
this.gameObject.name="Water";
//this.tag="Water";
this.collider.isTrigger=true;
// figure out what size the box is
size=this.transform.localScale;
size.x=Mathf.Abs(size.x);
size.y=Mathf.Abs(size.y);
size.z=Mathf.Abs(size.z);
if(size.x<5.0 || size.z<5.0)
return;
// figure out how many verts and triangles we need
var hCount=parseInt(size.x/2);
var vCount=parseInt(size.z/2);
var hCount2=hCount+1;
var vCount2=vCount+1;
var numTriangles = hCount * vCount * 6;
var numVertices = hCount2 * vCount2;
if(numVertices>64999){
print("Your water has too many vertices("+numVertices+" of 65000), make it smaller");
return;
}
doUpdate=true;
var newVertices : Vector3[]= new Vector3[numVertices];
var newUV : Vector2[]=new Vector2[numVertices];
var newTangents : Vector4[]=new Vector4[numVertices];
var newTriangles : int[]=new int[numTriangles];
var index=0;
var scale : float=(size.x + size.z)/5;
var uvx : float=1.0/hCount * scale;
var uvy : float=1.0/vCount * scale;
var scalex : float=1.0/hCount;
var scaley : float=1.0/vCount;
var x=0.0;
var y=0.0;
// make the verts
for(y=0; y<vCount2; y++){
for(x=0; x<hCount2; x++){
newVertices[index]=Vector3(-0.5+x*scalex, 0.5,-0.5+y*scaley);
newUV[index] = Vector2(x*uvx, y*uvy);
newTangents[index++]=Vector4(0,1,0,1);
}
}
// make the faces
index=0;
for(y=0; y<vCount; y++){
for(x=0; x<hCount; x++){
newTriangles[index] = (y * hCount2) + x;
newTriangles[index+1] = ((y+1) * hCount2) + x;
newTriangles[index+2] = (y * hCount2) + x + 1;
newTriangles[index+3] = ((y+1) * hCount2) + x;
newTriangles[index+4] = ((y+1) * hCount2) + x + 1;
newTriangles[index+5] = (y * hCount2) + x + 1;
index += 6;
}
}
// Clear the box, and replace it with the mesh
var mesh : Mesh = new Mesh ();
GetComponent(MeshFilter).mesh = mesh;
mesh.Clear();
mesh.vertices = newVertices;
mesh.uv = newUV;
mesh.triangles = newTriangles;
mesh.tangents= newTangents;
}
function Update () {
if(! doUpdate)
return;
var mesh : Mesh = GetComponent(MeshFilter).mesh;
var vertices = mesh.vertices;
var scale : float=(size.x + size.z)/2;
var offset : float=0.0;
for (var i=0; i<vertices.Length; i++)
{
offset=0.0;
//calculate waveform 1
offset +=Mathf.Sin(((Time.time*speed1 + (vertices[i].x + vertices[i].z)*0.5) % (3.14/2)) * scale);
//calculate waveform2
offset += Mathf.Sin((Time.time*speed2 + (vertices[i].z)) * scale);
vertices[i].y = 0.5 + offset * vScale;
//vertices[i].y += Random.Range(-0.01, 0.01);
}
mesh.vertices = vertices;
mesh.RecalculateNormals();
}
// do stuff when we are in the water
function OnTriggerEnter(other : Collider) {
//print(other.gameObject.name + " has entered the water!");
}
function OnTriggerExit(other : Collider) {
//print(other.gameObject.name + " has exited the water!");
}
Thanks for you input Fishman92,
I tried commenting out, but it appears to require those lines to run correctly.
The script runs well in the editor, but will not allow Unity to build to iOS.
I just loaded this script back up into Unity 3.3 and had no problems. I dont know about iOS, but the web builder is correct. (I dont have Unity Pro, nor the iOS package so I can’t really support iOS)
var mesh : Mesh = (GetComponent(MeshFilter) as MeshFilter).mesh;
var vScale=0.025;
var speed1=0.007;
var speed2=0.001;
private var size;
private var doUpdate=false;
function Start () {
this.gameObject.name="Water";
//this.tag="Water";
this.collider.isTrigger=true;
// figure out what size the box is
size=this.transform.localScale;
size.x=Mathf.Abs(size.x);
size.y=Mathf.Abs(size.y);
size.z=Mathf.Abs(size.z);
if(size.x<5.0 || size.z<5.0)
return;
// figure out how many verts and triangles we need
var hCount=parseInt(size.x/2);
var vCount=parseInt(size.z/2);
var hCount2=hCount+1;
var vCount2=vCount+1;
var numTriangles = hCount * vCount * 6;
var numVertices = hCount2 * vCount2;
if(numVertices>64999){
print("Your water has too many vertices("+numVertices+" of 65000), make it smaller");
return;
}
doUpdate=true;
var newVertices : Vector3[]= new Vector3[numVertices];
var newUV : Vector2[]=new Vector2[numVertices];
var newTangents : Vector4[]=new Vector4[numVertices];
var newTriangles : int[]=new int[numTriangles];
var index=0;
var scale : float=(size.x + size.z)/5;
var uvx : float=1.0/hCount * scale;
var uvy : float=1.0/vCount * scale;
var scalex : float=1.0/hCount;
var scaley : float=1.0/vCount;
var x=0.0;
var y=0.0;
// make the verts
for(y=0; y<vCount2; y++){
for(x=0; x<hCount2; x++){
newVertices[index]=Vector3(-0.5+x*scalex, 0.5,-0.5+y*scaley);
newUV[index] = Vector2(x*uvx, y*uvy);
newTangents[index++]=Vector4(0,1,0,1);
}
}
// make the faces
index=0;
for(y=0; y<vCount; y++){
for(x=0; x<hCount; x++){
newTriangles[index] = (y * hCount2) + x;
newTriangles[index+1] = ((y+1) * hCount2) + x;
newTriangles[index+2] = (y * hCount2) + x + 1;
newTriangles[index+3] = ((y+1) * hCount2) + x;
newTriangles[index+4] = ((y+1) * hCount2) + x + 1;
newTriangles[index+5] = (y * hCount2) + x + 1;
index += 6;
}
}
// Clear the box, and replace it with the mesh
var mesh : Mesh = new Mesh ();
//if((GetComponent(MeshFilter) as MeshFilter).mesh == null)
//(GetComponent(MeshFilter) as MeshFilter).mesh = new Mesh();
(GetComponent(MeshFilter) as MeshFilter).mesh = mesh;
//GetComponent(MeshFilter).mesh = mesh;
mesh.Clear();
mesh.vertices = newVertices;
mesh.uv = newUV;
mesh.triangles = newTriangles;
mesh.tangents= newTangents;
}
function Update () {
if(! doUpdate)
return;
var mesh : Mesh = (GetComponent(MeshFilter) as MeshFilter).mesh;
//var mesh : Mesh = GetComponent(MeshFilter).mesh;
var vertices = mesh.vertices;
var scale : float=(size.x + size.z)/2;
var offset : float=0.0;
for (var i=0; i<vertices.Length; i++)
{
offset=0.0;
//calculate waveform 1
offset +=Mathf.Sin(((Time.time*speed1 + (vertices[i].x + vertices[i].z)*0.5) % (3.14/2)) * scale);
//calculate waveform2
offset += Mathf.Sin((Time.time*speed2 + (vertices[i].z)) * scale);
vertices[i].y = 0.5 + offset * vScale;
//vertices[i].y += Random.Range(-0.01, 0.01);
}
mesh.vertices = vertices;
mesh.RecalculateNormals();
}
// do stuff when we are in the water
function OnTriggerEnter(other : Collider) {
print(other.gameObject.name + " has entered the water!");
}
function OnTriggerExit(other : Collider) {
print(other.gameObject.name + " has exited the water!");
}
I used the following solution to correct for iOS deployment and it appears to work.
I replaced:
GetComponent(MeshFilter).mesh = mesh;
with:
(GetComponent(MeshFilter) as MeshFilter).mesh = mesh;
and:
var mesh : Mesh = GetComponent(MeshFilter).mesh;
with:
var mesh : Mesh = (GetComponent(MeshFilter) as MeshFilter).mesh;
Much thanks and praise to BigMisterB!!!
The below works for iOS:
var vScale=0.025;
var speed1=0.007;
var speed2=0.001;
private var size;
private var doUpdate=false;
function Start () {
this.gameObject.name="Water";
//this.tag="Water";
this.collider.isTrigger=true;
// figure out what size the box is
size=this.transform.localScale;
size.x=Mathf.Abs(size.x);
size.y=Mathf.Abs(size.y);
size.z=Mathf.Abs(size.z);
if(size.x<5.0 || size.z<5.0)
return;
// figure out how many verts and triangles we need
var hCount=parseInt(size.x/2);
var vCount=parseInt(size.z/2);
var hCount2=hCount+1;
var vCount2=vCount+1;
var numTriangles = hCount * vCount * 6;
var numVertices = hCount2 * vCount2;
if(numVertices>64999){
print("Your water has too many vertices("+numVertices+" of 65000), make it smaller");
return;
}
doUpdate=true;
var newVertices : Vector3[]= new Vector3[numVertices];
var newUV : Vector2[]=new Vector2[numVertices];
var newTangents : Vector4[]=new Vector4[numVertices];
var newTriangles : int[]=new int[numTriangles];
var index=0;
var scale : float=(size.x + size.z)/5;
var uvx : float=1.0/hCount * scale;
var uvy : float=1.0/vCount * scale;
var scalex : float=1.0/hCount;
var scaley : float=1.0/vCount;
var x=0.0;
var y=0.0;
// make the verts
for(y=0; y<vCount2; y++){
for(x=0; x<hCount2; x++){
newVertices[index]=Vector3(-0.5+x*scalex, 0.5,-0.5+y*scaley);
newUV[index] = Vector2(x*uvx, y*uvy);
newTangents[index++]=Vector4(0,1,0,1);
}
}
// make the faces
index=0;
for(y=0; y<vCount; y++){
for(x=0; x<hCount; x++){
newTriangles[index] = (y * hCount2) + x;
newTriangles[index+1] = ((y+1) * hCount2) + x;
newTriangles[index+2] = (y * hCount2) + x + 1;
newTriangles[index+3] = ((y+1) * hCount2) + x;
newTriangles[index+4] = ((y+1) * hCount2) + x + 1;
newTriangles[index+5] = (y * hCount2) + x + 1;
index += 6;
}
}
// Clear the box, and replace it with the mesh
var mesh : Mesh = new Mesh ();
//if((GetComponent(MeshFilter) as MeshFilter).mesh == null)
//(GetComponent(MeshFilter) as MeshFilter).mesh = new Mesh();
(GetComponent(MeshFilter) as MeshFilter).mesh = mesh;
//GetComponent(MeshFilter).mesh = mesh;
mesh.Clear();
mesh.vertices = newVertices;
mesh.uv = newUV;
mesh.triangles = newTriangles;
mesh.tangents= newTangents;
}
function Update () {
if(! doUpdate)
return;
var mesh : Mesh = (GetComponent(MeshFilter) as MeshFilter).mesh;
//var mesh : Mesh = GetComponent(MeshFilter).mesh;
var vertices = mesh.vertices;
var scale : float=(size.x + size.z)/2;
var offset : float=0.0;
for (var i=0; i<vertices.Length; i++)
{
offset=0.0;
//calculate waveform 1
offset +=Mathf.Sin(((Time.time*speed1 + (vertices[i].x + vertices[i].z)*0.5) % (3.14/2)) * scale);
//calculate waveform2
offset += Mathf.Sin((Time.time*speed2 + (vertices[i].z)) * scale);
vertices[i].y = 0.5 + offset * vScale;
//vertices[i].y += Random.Range(-0.01, 0.01);
}
mesh.vertices = vertices;
mesh.RecalculateNormals();
}
// do stuff when we are in the water
function OnTriggerEnter(other : Collider) {
print(other.gameObject.name + " has entered the water!");
}
function OnTriggerExit(other : Collider) {
print(other.gameObject.name + " has exited the water!");
}