# Water Effect

i tried to mix up a few example codes, so here it is… noise + 3d/mesh…

it’s not so fast and im not so good at optimizing, but here it is…

``````
-- Water Test

function setup()

local vertices = {}

resolution = 19 -- decrease for more fps, increase for slowlyness :D

displayMode(FULLSCREEN)
t=0

Size=150

parameter("Speed",0,5,1.5)
parameter("CamHeight", -1000, 1000, 19.5)
parameter("Angle",-360, 360, -30)
parameter("FieldOfView", 10, 140, 90)

parameter("NoiseScale", 0,1,0.23)
parameter("Scale2", 1,100,15)
the3DViewMatrix = viewMatrix()

watch ("fps")
fpscount=0
fpsamount = 0

for i=1,resolution do
vertices[i] ={}
for j=1,resolution do
vertices[i][j] = vec3(-75 +i*Size/resolution,0,-75+j*Size/resolution)
end
end

cubeverts = {}
for i=1,(resolution-1) do
for j=1,(resolution-1) do
table.insert(cubeverts, vertices[i][j])
table.insert(cubeverts, vertices[i+1][j])
table.insert(cubeverts, vertices[i][j+1])
table.insert(cubeverts, vertices[i+1][j])
table.insert(cubeverts, vertices[i][j+1])
table.insert(cubeverts, vertices[i+1][j+1])
end
end

ms = mesh()
ms.vertices = cubeverts

print("Using "..table.maxn(cubeverts).." vertices")

-- init colortable
triCol = {}
for i=1,((resolution-1)*(resolution-1)*6) do
tst = math.random(0,255)
table.insert(triCol, i, color(tst, tst, 255, 255) )

end
ms.colors = triCol

end

function draw()

perspective(FieldOfView, WIDTH/HEIGHT)

-- Position the camera up and back, look at origin
camera(0,CamHeight,-10, 10,0,10, 0,1,0)
-- This sets a dark background color
background(40, 40, 50)
translate(50,-Size/2,70)
rotate(Angle,0,1,0)

counter = 0

for i=1,(resolution-1) do

for j=1,(resolution-1) do

counter = counter + 1
if counter > 2 and j> 1 and i>1 then
ms:vertex(counter, ms:vertex(counter).x, ms:vertex(counter-2).y, ms:vertex(counter).z)
else
ms:vertex(counter, ms:vertex(counter).x,noise((i+t)*NoiseScale,(j+t)*NoiseScale)*Scale2, ms:vertex(counter).z)
end
if counter > 2 then
newcol = (ms:vertex(counter).y)*10
ms:color(counter, color(newcol, newcol, 255+newcol))
end

counter = counter + 1

if counter > 2 and j> 1 and i>1 then
ms:vertex(counter, ms:vertex(counter).x, ms:vertex(counter-2).y, ms:vertex(counter).z)
else
ms:vertex(counter, ms:vertex(counter).x,noise((i+t+1)*NoiseScale,(j+t)*NoiseScale)*Scale2, ms:vertex(counter).z)
end
newcol = (ms:vertex(counter).y)*10
ms:color(counter, color(newcol, newcol, 255+newcol))

counter = counter + 1

ms:vertex(counter, ms:vertex(counter).x,noise((i+t)*NoiseScale,(j+t+1)*NoiseScale)*Scale2, ms:vertex(counter).z)

newcol = (ms:vertex(counter).y)*10
ms:color(counter, color(newcol, newcol, 255+newcol))

counter = counter + 1
if counter > 2 and j> 1 and i>1  then
ms:vertex(counter, ms:vertex(counter).x, ms:vertex(counter-2).y, ms:vertex(counter).z)
else
ms:vertex(counter, ms:vertex(counter).x,noise((i+t+1)*NoiseScale,(j+t)*NoiseScale)*Scale2, ms:vertex(counter).z)
end
newcol = (ms:vertex(counter).y)*10
ms:color(counter, color(newcol, newcol, 255+newcol))

counter = counter + 1
ms:vertex(counter, ms:vertex(counter).x,noise((i+t)*NoiseScale,(j+t+1)*NoiseScale)*Scale2, ms:vertex(counter).z)
newcol = (ms:vertex(counter).y)*10
ms:color(counter, color(newcol, newcol, 255+newcol))

counter = counter + 1
ms:vertex(counter, ms:vertex(counter).x,noise((i+t+1)*NoiseScale,(j+t+1)*NoiseScale)*Scale2, ms:vertex(counter).z)
newcol = (ms:vertex(counter).y)*10
ms:color(counter, color(newcol, newcol, 255+newcol))

end
end

ms:draw()

t = t + (DeltaTime*Speed)

fpscount = fpscount + 1
fpsamount = fpsamount + DeltaTime

if fpscount == 10 then
fps = fpsamount /10
fps = 1/fps
fpsamount =0
fpscount=0
end

end

function touched()
if CurrentTouch.state==BEGAN then
if displayMode() == FULLSCREEN then
displayMode(STANDARD)
else
displayMode(FULLSCREEN)
end
end
end

``````

Wow, impressive

Oh this is very cool, I did something similar, only I was only using the noise to generate terrain dynamically.

Looks very nice, nice work !

Xavier

thank you, but in this state, it couldn’t really be used in a game etc. because it’s too slow…
in the video, i used a 19x19 grid, that looked good and was fast enough, but i think theres not enough power for something else on the screen

Looks great, I love procedural effects like this.

Some optimizations…

Good work, what did you do in the inner loop that made the most difference?

interestingly it was not the noise calculations for every vertex, but the accessing of the ms:vertex(id).x and .y values…

before the changes, i calculated the values when i drew them
but so i replaced this:

``````        if counter > 2 and j> 1 and i>1 then
ms:vertex(counter, ms:vertex(counter).x, ms:vertex(counter-2).y, ms:vertex(counter).z)
else
ms:vertex(counter, ms:vertex(counter).x,noise((i+t)*NoiseScale,(j+t)*NoiseScale)*Scale2, ms:vertex(counter).z)
end
if counter > 2 then
newcol = (ms:vertex(counter).y)*10
ms:color(counter, color(newcol, newcol, 255+newcol))
``````

with

``````ms:vertex(counter, tempx[i][j], templ[i][j], tempy[i][j])
newcol = templ[i][j]*10
``````

tempx is the x position of the grid
tempy is the y position of the grid

and templ is created every draw, but just once…
so i did nearly 6 times the calculating i had to i think, but that made not so much difference, the slow part seems to be the accessing of the mesh vertex position and the change of it…

oh, and i just saw, it’s 37 fps , just the recording took something…

is there another way to set my vertex.y value than ms:vertex()?

heres the code:

``````
--# Main
-- Water Test

function setup()

local vertices = {}
tempx  ={}
tempy = {}
resolution = 19
noSmooth()
noStroke()

--   backingMode(RETAINED)
displayMode(FULLSCREEN)
t=0

Size=150

fps=0
parameter("Speed",0,5,1.5)
parameter("CamHeight", -1000, 1000, 19.5)
parameter("Angle",-360, 360, -30)
parameter("FieldOfView", 10, 140, 90)

parameter("NoiseScale", 0,1,0.23)
parameter("Scale2", 1,100,15)
the3DViewMatrix = viewMatrix()

watch ("fps")
fpscount=0
fpsamount = 0

for i=1,resolution do
vertices[i] ={}
tempx[i]={}
tempy[i]={}
for j=1,resolution do
vertices[i][j] = vec3(-75 +i*Size/resolution,0,-75+j*Size/resolution)
tempx[i][j] = -75 +i*Size/resolution
tempy[i][j] = -75 +j*Size/resolution
end
end

cubeverts = {}
for i=1,(resolution-1) do
for j=1,(resolution-1) do
table.insert(cubeverts, vertices[i][j])
table.insert(cubeverts, vertices[i+1][j])
table.insert(cubeverts, vertices[i][j+1])
table.insert(cubeverts, vertices[i+1][j])
table.insert(cubeverts, vertices[i][j+1])
table.insert(cubeverts, vertices[i+1][j+1])
end
end

ms = mesh()
ms.vertices = cubeverts

print("Using "..table.maxn(cubeverts).." vertices")

-- init colortable
triCol = {}
for i=1,((resolution-1)*(resolution-1)*6) do
tst = math.random(0,255)
table.insert(triCol, i, color(tst, tst, 255, 255) )

end
ms.colors = triCol

templ = {}
for i=1, resolution do
templ[i] ={}
for j=1, resolution do
templ[i][j] = 0
end
end

end

function draw()

perspective(FieldOfView, WIDTH/HEIGHT)

-- Position the camera up and back, look at origin
camera(0,CamHeight,-10, 10,0,10, 0,1,0)
-- This sets a dark background color
background(40, 40, 50)
translate(50,-100,70)
rotate(Angle,0,1,0)

counter = 0

--templ = {}
for i=1, resolution do
-- templ[i] ={}
for j=1, resolution do
templ[i][j]=noise((i+t)*NoiseScale, (j+t)*NoiseScale)*Scale2
end
end

for i=1,(resolution-1) do

for j=1,(resolution-1) do

counter = counter + 1
ms:vertex(counter, tempx[i][j], templ[i][j], tempy[i][j])
newcol = templ[i][j]*10
ms:color(counter, color(newcol, newcol, 255+newcol))

counter = counter + 1
ms:vertex(counter, tempx[i+1][j], templ[i+1][j], tempy[i+1][j])
newcol = templ[i+1][j]*10
ms:color(counter, color(newcol, newcol, 255+newcol))

counter = counter + 1
ms:vertex(counter, tempx[i][j+1], templ[i][j+1], tempy[i][j+1])
newcol =templ[i][j+1]*10
ms:color(counter, color(newcol, newcol, 255+newcol))

counter = counter + 1
ms:vertex(counter, tempx[i+1][j], templ[i+1][j], tempy[i+1][j])
newcol =templ[i+1][j] *10
ms:color(counter, color(newcol, newcol, 255+newcol))

counter = counter + 1
ms:vertex(counter, tempx[i][j+1], templ[i][j+1], tempy[i][j+1])
newcol =templ[i][j+1] *10
ms:color(counter, color(newcol, newcol, 255+newcol))

counter = counter + 1
ms:vertex(counter, tempx[i+1][j+1], templ[i+1][j+1], tempy[i+1][j+1])
newcol =templ[i+1][j+1]*10
ms:color(counter, color(newcol, newcol, 255+newcol))

end
end

ms:draw()

t = t + (DeltaTime*Speed)

fpscount = fpscount + 1
fpsamount = fpsamount + DeltaTime

if fpscount == 10 then
fps = fpsamount /10
fps =math.floor( 1/fps)

fpsamount =0
fpscount=0
end
rotate(-Angle-122,0,1,0)
text("Res ("..resolution..") Fps: "..fps, 30, 100)

end

function touched()
if CurrentTouch.state==BEGAN then
if CurrentTouch.tapCount == 2 then
if displayMode() == FULLSCREEN then
displayMode(STANDARD)
else
displayMode(FULLSCREEN)
end
end
end

if CurrentTouch.state == MOVING then
Angle = Angle + CurrentTouch.deltaX
end

end

``````

Wonderful effect, @Inviso!!!

@Inviso - Sup, took the liberty to optimize the code a little.
The latest version was originally it was running at 20 fps on my iPad1, currently at 30fps.

Just received new iPad though, so will get back to it asap then post latest code

Cheers

Xavier

You could probably speed it up a little more using 1D arrays i think, but didn’t want to change the code too much

37fps to 56 on new iPad

There you go:

``````

--# Main
-- Water Test

function setup()

vertices = {}

resolution = 19

--   backingMode(RETAINED)
displayMode(FULLSCREEN)
t=0

Size=150

fps=0
parameter("Speed",0,5,1.5)
parameter("CamHeight", -1000, 1000, 19.5)
parameter("Angle",-360, 360, -30)
parameter("FieldOfView", 10, 140, 90)

parameter("NoiseScale", 0,1,0.23)
parameter("Scale2", 1,100,15)
the3DViewMatrix = viewMatrix()

watch ("fps")
fpscount=0
fpsamount = 0

for i=1,resolution do
vertices[i] ={}
for j=1,resolution do
vertices[i][j] = Vertex(-75 +i*Size/resolution,0,-75+j*Size/resolution, color(0, 0, 255))
end
end

cubeverts = {}
for i=1,(resolution-1) do
for j=1,(resolution-1) do
table.insert(cubeverts, vec3(vertices[i][j]:get()))
table.insert(cubeverts, vec3(vertices[i+1][j]:get()))
table.insert(cubeverts, vec3(vertices[i][j+1]:get()))
table.insert(cubeverts, vec3(vertices[i+1][j]:get()))
table.insert(cubeverts, vec3(vertices[i][j+1]:get()))
table.insert(cubeverts, vec3(vertices[i+1][j+1]:get()))
end
end

ms = mesh()
ms.vertices = cubeverts

print("Using "..table.maxn(cubeverts).." vertices")

-- init colortable
triCol = {}
for i=1,((resolution-1)*(resolution-1)*6) do
tst = math.random(0,255)
table.insert(triCol, i, color(tst, tst, 255, 255) )
end
ms.colors = triCol

end

function draw()

perspective(FieldOfView, WIDTH/HEIGHT)

-- Position the camera up and back, look at origin
camera(0,CamHeight,-10, 10,0,10, 0,1,0)
-- This sets a dark background color
background(40, 40, 50)
translate(50,-100,70)
rotate(Angle,0,1,0)

local ms = ms
local counter = 0
local vertices = vertices
local a, b, c, d
local col

for i=1, resolution do
for j=1, resolution do
col = noise((i+t)*NoiseScale, (j+t)*NoiseScale)*Scale2
vertices[i][j].y = col
vertices[i][j].c.b = 255+col*10
end
end

for i=1,(resolution-1) do
for j=1,(resolution-1) do
a = vertices[i][j]
b = vertices[i+1][j]
c = vertices[i][j+1]
d = vertices[i+1][j+1]

counter = counter + 1
ms:vertex(counter, a:get())
ms:color(counter, a:col())

counter = counter + 1
ms:vertex(counter, b:get())
ms:color(counter, b:col())

counter = counter + 1
ms:vertex(counter, c:get())
ms:color(counter, c:col())

counter = counter + 1
ms:vertex(counter, b:get())
ms:color(counter, b:col())

counter = counter + 1
ms:vertex(counter, c:get())
ms:color(counter, c:col())

counter = counter + 1
ms:vertex(counter, d:get())
ms:color(counter, d:col())

end
end

ms:draw()

t = t + (DeltaTime*Speed)

fpscount = fpscount + 1
fpsamount = fpsamount + DeltaTime

if fpscount == 10 then
fps = fpsamount /10
fps =math.floor( 1/fps)

fpsamount =0
fpscount=0
end
rotate(-Angle-122,0,1,0)
text("Res ("..resolution..") Fps: "..fps, 30, 100)

end

function touched()
if CurrentTouch.state==BEGAN then
if CurrentTouch.tapCount == 2 then
if displayMode() == FULLSCREEN then
displayMode(STANDARD)
else
displayMode(FULLSCREEN)
end
end
end

if CurrentTouch.state == MOVING then
Angle = Angle + CurrentTouch.deltaX
end

end

Vertex = class()

function Vertex:init(x,y,z,c)
self.x = x
self.y = y
self.z = z
self.c = c
end

function Vertex:get()
return self.x, self.y, self.z
end

function Vertex:col()
return self.c
end
``````

Cheers,

Xavier

Wow, awesome!!! Thanks, i think i understand what makes this fast…
as i understand now, its better to use local variables, because they are faster… good to know, i asked myself already why one should use local

you changed the coloring, when i change it back to a value that goes to white, it looses a few frames, but it’s very very fast…

what do you mean by 1D Arrays? and could it save a frame or two if we do not assign a-b-c-d? or is the slow part at this specific operation accessing the 2Dimensional array? Is that what you mean, if one could get this straigt it would work faster? i’ll try that

Yeah using local variables makes it much faster (went from 20fps on ipad1 to 25 just by using local variables when I started adding them :P)

I’m positive it can be fine tuned some more, maybe only by restructuring the code though.
Assigning a,b,c and d do speed things up, since you don’t have the redundant calls to lookup vertices[][] multiple times.
However, I believe 1D array would only be (very) slightly faster, since there is one less table lookup, but the really slow function was the color one (nothing you can do about ms:vertex() and ms:color() unfortunately).
Also, accessing vec3 x,y and z values (and r, g, b, a of color) is very slow in their respective Codea implementations, so when you don’t need special functions like vec2:dist() etc and just want to store data, it’s faster to build a class.

Cheers