Water ripple effect - help with speed optimisation

I’ve implemented a water ripple effect based on the algorithm from here
http://freespace.virgin.net/hugo.elias/graphics/x_water.htm

Though it works, I’m finding it runs very slowly. I’m guessing the get and set with images isn’t the fastest, so is there an alternative (or is there something amiss with my code)?

Many thanks in advance


-- WaterRipple
-- Using http://freespace.virgin.net/hugo.elias/graphics/x_water.htm as a starting point
-- Use this function to perform your initial setup
function setup()
    waterimg=readImage("Cargo Bot:Icon")
    waterimg2=readImage("Cargo Bot:Icon")

--damping = some non-integer between 0 and 1
damping=0.95
xsize=110
ysize=110
counter=0
buffer1={}
buffer2={}
buffertemp={}
   for x=1,xsize do
    buffer1[x]={}
    buffer2[x]={}
    buffertemp[x]={}
        for y=1,ysize do
            buffer1[x][y]=0
            buffer2[x][y]=0
            buffertemp[x][y]=0
        end
    end
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)
    counter = counter + 1
    if counter>50 then
        --creater a disturbance in the heightmap
        buffer1[50][50]=1
        counter=0
    end
    --display the counter
    text(counter,400,460)
    --  begin loop 

    for x=2,xsize-1 do
        for y=2,ysize-1 do
            --calculate the "height map"
            buffer2[x][y] =(buffer1[x+1][y]+buffer1[x-1][y]+buffer1[x][y+1]+buffer1[x][y-1])/2-buffer2[x][y]
            buffer2[x][y] = buffer2[x][y] * damping
            --calculate the shift
            xoffset=buffer2[x-1][y]-buffer2[x+1][y]
            yoffset=buffer2[x][y-1]-buffer2[x][y+1]
            shading = xoffset
            local rt,gt,bt,at=waterimg:get(x+xoffset,y+yoffset)
            rt=rt+xoffset
            gt=gt+xoffset
            bt=bt+xoffset
            at=at+xoffset
            waterimg2:set(x,y,color(rt,gt,bt,at))
        end 
    end
    sprite(waterimg2,400,400)   
    buffertemp=buffer2
    buffer2=buffer1
    buffer1=buffertemp    
end

Hello West. I’ve tried your code but i don’t understand what i should see: there is only a small icon (100x100?) in the middle of the screen, a counting above, and some very small variations on the image. Is it what i should see?

Yes, that’s right. a ripple water effect, but a very slow one. The counter should be incrementing faster

Sorry West, i don’t think it can real time with the way it is coded. I think it should be rewriten using meshes and some trick with scale/rotate/translate if you want a real time effect. I don’t even see any ‘‘watering’’ effect occuring here. Maybe a video would show what you want to achive?

(Further update) With some limited success, I tried replacing the image with a mesh and waterimg with a linear array, and caching the function setRectColor() in a local variable. That increases the speed by a factor of about three.


--
-- WaterRipple with mesh
--
-- Using http://freespace.virgin.net/hugo.elias/graphics/x_water.htm
-- as a starting point
supportedOrientations(LANDSCAPE_ANY)
function setup()
    local waterimg2 = readImage("Cargo Bot:Icon")
    waterimg = {}
    m = mesh()
    damping = 32
    xsize = waterimg2.width
    ysize = waterimg2.height
    print("No. of cells: ", xsize * ysize)
    dim = math.min(WIDTH, HEIGHT) / math.max(xsize, ysize)
    dim = math.floor(dim)
    local xm, ym = (WIDTH - xsize * dim) / 2, (HEIGHT - ysize * dim) / 2
    counter = 0
    buffer1 = {}
    buffer2 = {}
    for x=1, xsize do
        for y=1, ysize do
            local i = (x - 1) * ysize + y
            buffer1[i] = 0
            buffer2[i] = 0
            waterimg[i] = color(waterimg2:get(x, y))
            local idx = m:addRect(x * dim + xm, y * dim + xm, dim, dim)
            m:setRectColor(idx, waterimg[i])
        end
    end
end

function draw()
    background(0)
    --display the counter
    text(counter, WIDTH - 20, 460)
    text(1/DeltaTime, WIDTH - 20, 420)
    if counter % 50 == 0 then
        --creater a disturbance in the heightmap
        buffer1[54 * ysize + 55] = 1
    end
    counter = counter + 1
    --  begin loop 
    for i = ysize + 2, (xsize - 1) * ysize - 1 do
            local ixp1 = i + ysize
            local ixm1 = i - ysize
            buffer2[i] = (buffer1[ixp1] + buffer1[ixm1]
                + buffer1[i + 1] + buffer1[i - 1])/2 - buffer2[i]
            buffer2[i] = buffer2[i] - buffer2[i] / damping
    end
    local src = m.setRectColor
    for i = ysize + 2, (xsize - 1) * ysize - 1 do
            local ixp1 = i + ysize
            local ixm1 = i - ysize
            local xoffset = math.floor(buffer2[ixm1] - buffer2[ixp1])
            local yoffset = math.floor(buffer2[i - 1] - buffer2[i + 1])
            local io = i + xoffset * ysize + yoffset
            local col = waterimg[io]
            src(m, i, col)
    end
    m:draw()
    buffer2, buffer1 = buffer1, buffer2
end

I also made the first perturbation occur at counter = 0, removed the redundant (I think) ripple in the alpha channel, buffertemp and (update) addition of xoffset to the colour channels. Looking at the original algorithm, I also moved the offset calculation for rendering into a separate loop to the update of the buffer.

Recently, I have been having problems with re-editing edited posts on the forum. I find myself editing the original post again, not re-editing the edit. My attempts to update the post above has suffered from that.

.@mpilgrem I’ve noticed the same thing, for perhaps the last 2 weeks or so.

.@mpilgrim many thanks for the response, I had tried meshes but didn’t get as far as you

I was looking towards this http://media.chikuyonok.ru/ripple/ implemented in JavaScript which was nice and smooth, and had assumed that this sort of performance would therefore be achievable here. :-/

.@West this is the sort of thing shaders will be very good at achieving in the next update.

.@mpilgrem @toadkick sorry about the editing bug. Sounds like it might be a vanilla forums issue. I’ll have a look at updating to the latest version.

.@Simeon OK, I’ll park this until the next update

omg, i lost something, there will be shaders in Codea? : ))

Check the @codeacommits twitter page…:slight_smile:

.@simeon i’m starting to work on shadows and reflection on my planets, but if shaders are coming soon i should not invest too much there. Could you give me an idea of what ‘‘soon’’ means? Like: 1week, 1month, 1trimester, 1 year? And could you give me a link to a ‘‘beta doc’’ so i have a better idea (even rought) of what shaders in codea will be able do? (i’ve no idea on how shaders work). Thanks.