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…

http://www.youtube.com/watch?v=F4YYTO5atkA&sns=em


-- 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 :wink:

Looks great, I love procedural effects like this.

Some optimizations…

http://www.youtube.com/watch?v=q6mNAuWgH8E&sns=em

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 :stuck_out_tongue:

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 :wink:

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