water ripples

I’ve developed some code that tracks mouse clicks and dragging and then is suppose to create ripples or waves on a 2d image. The best approach that I’ve had so far has been working with these two examples as my basis: http://freespace.virgin.net/hugo.elias/graphics/x-water.htm and http://www.gamedev.net/reference/articles/article915.asp

My problem is that the waves do not degrade… meaning they continue to form over and over on top of each other and eventually cause the program to freeze. Does anyone have any ideas on what I should be doing differently. Below is my header file and code.

Thanks for any help.

Header:

  
  
#include "ofxOpenCv.h"  
  
//#define _USE_LIVE_VIDEO		// uncomment this to use a live camera  
								// otherwise, we'll use a movie file  
  
  
class testApp : public ofBaseApp{  
  
	public:  
  
		void setup();  
		void update();  
		void draw();  
  
		void keyPressed  (int key);  
		void mouseMoved(int x, int y );  
		void mouseDragged(int x, int y, int button);  
		void mousePressed(int x, int y, int button);  
		void mouseReleased(int x, int y, int button);  
		void windowResized(int w, int h);  
  
        //others needed by me  
        int scnWidth;  
        int scnHeight;  
        ofImage bckgImg;  
  
        //ripple code  
        void addDrop(int x, int y);  
        void rippleEffect();  
        long int * buffer1;  
        long int * buffer2;  
        unsigned char * waveData;  
        unsigned char * imgBuffer;  
        ofTexture waveImg;  
  
  
  
};  
  
#endif  
  

Code:

  
  
#include "testApp.h"  
#include "time.h"  
  
  
//--------------------------------------------------------------  
void testApp::setup(){  
    scnWidth=900;  
    scnHeight=600;  
  
    bckgImg.loadImage("playa.jpg");  
    bckgImg.resize(scnWidth, scnHeight);  
  
    //build buffers  
    buffer1 = new long int [scnWidth * scnHeight * 3];  
    buffer2 = new long int [scnWidth * scnHeight * 3];  
  
    //wave image data  
    imgBuffer = new unsigned char [scnWidth * scnHeight * 3];  
    waveData = new unsigned char [scnWidth * scnHeight * 3];  
    waveImg.allocate(scnWidth, scnHeight, GL_RGB);  
  
}  
  
void testApp::draw(){  
  
    Sleep(33);  
    rippleEffect();  
  
}  
  
void testApp::addDrop(int x, int y){  
  
    buffer1[ (y * scnWidth) + x ] = -100;  
  
}  
  
void testApp::rippleEffect(){  
  
    //reload the background image into the image buffer  
    imgBuffer = bckgImg.getPixels();  
  
    //main loop cycle  
    for (int y = 1; y < scnHeight - 1; y++){  
        for (int x = 1; x < scnWidth - 1; x++){  
  
            //pixel number  
            int pixNum = (y * scnWidth) + x;  
  
            //set RGB pixel data count  
            int pixR = (y * scnWidth * 3) + (x*3);  
            int pixG = (y * scnWidth * 3) + (x*3) + 1;  
            int pixB = (y * scnWidth * 3) + (x*3) + 2;  
  
            //calculate pixel height  
            buffer2[pixNum] = ( buffer1[pixNum - 1] +  
                                buffer1[pixNum + 1] +  
                                buffer1[pixNum + scnWidth] +  
                                buffer1[pixNum - scnWidth] )  
                                / 2 -  
                                buffer2[pixNum];  
            buffer2[pixNum] -= buffer2[pixNum]/32;  
  
/*  
            if(abs(buffer2[pixNum]) >= 10 && abs(buffer1[pixNum]) > 0){  
                buffer2[pixNum] = abs(buffer2[pixNum] - 10) * (buffer2[pixNum]/abs(buffer2[pixNum]));  
            }  
            else{  
                if( abs(buffer2[pixNum]) < 10 && abs(buffer1[pixNum]) > 0){  
                    buffer2[pixNum] = 0;  
                }  
            }  
*/  
  
            //calculate pixel offset, refraction, and shading  
            int Xoffset = buffer2[pixNum - 1] - buffer2[pixNum + 1];  
            int Yoffset = buffer2[pixNum - scnWidth] - buffer2[pixNum +scnWidth];  
  
  
            //bounds check  
            if( Xoffset >= scnWidth){Xoffset = scnWidth-1;}  
            if( Xoffset < 0){Xoffset = 0;}  
            if( Yoffset >= scnHeight){Yoffset = scnHeight-1;}  
            if( Yoffset < 0){Yoffset = 0;}  
  
            //refraction  
            waveData[pixR] = imgBuffer[pixR + Xoffset + (scnWidth * Yoffset)];  
            waveData[pixG] = imgBuffer[pixG + Xoffset + (scnWidth * Yoffset)];  
            waveData[pixB] = imgBuffer[pixB + Xoffset + (scnWidth * Yoffset)];  
  
            //shading  
            //int shading = Xoffset;  
            //waveData[pixR] -= Xoffset;  
            //waveData[pixG] -= Xoffset;  
            //waveData[pixB] -= Xoffset;  
  
        }  
    }  
  
    //display waves  
    waveImg.loadData(waveData, scnWidth, scnHeight, GL_RGB);  
    waveImg.draw(0, 0, scnWidth, scnHeight);  
  
    //reset data to current state  
    long int * temp = new long int [scnWidth * scnHeight * 3];  
    temp = buffer1;  
    buffer1 = buffer2;  
    buffer2 = temp;  
}  
  
  

i don’t know how the algorithm works, and looking through your code it’s not very clear, but you’ll need somehow to reduce the effect over time. for each wave, every frame, subtract a small amount from its effect multiplier, and when this number gets to 0 you throw the wave away.

i suggest you email the author of the webpage where you got the example code from and ask them for help…

I would like to ask skankest:
I’m getting weird color variations and it locks up anyways. Did you ever get it to run?

and about your question. I think the code is supposed to have a damping value.
=D

I am also looking in to water ripple generation.

My final goal is to read out the height of the “water” in specific spots inside the “pool” and use those to move linear actuators (motors) up and down.
I am hoping to be able to control size of the original displacement, the amplitude, frequency, and speed of propagation.
I was not yet able to get anything going that gives me all of those controls.

My research so far has made me look at ofxFX ripple example by @patricio: https://github.com/patriciogonzalezvivo/ofxFX/tree/master/example-waterRipples

ofxWaterRipple by @antoniomechas:

Both use shaders that are based more or less on the code linked above by @skankest.
But controlling speed, frequency and amplitude are hard. Also the waves bounce of the edge of the “pool” and i am not able to prevent it.

I was able to implement this 1D line wave code (behave like linked springs) i found on jsfiddle, which gives me more control of the wave form.
http://jsfiddle.net/phil_mcc/sXmpD/8/#run
Here a nice explanation:

But to expand this in to 2D plane has not worked so far.

Then there is the height field approach with sample code by @roxlu:
http://www.roxlu.com/2013/024/height-field-simulation-on-gpu

and a simulation by skeelogy:
http://skeelogy.github.io/skunami.js/examples/skunami_waterTypes.html

All very nice but again so far i have not be able to make this happen in OF.

One last idea was to us an ofxBullet cloth to make a spring mash as asked in this post:

Still lots to learn until i get this working.