## News:

*NEW* Current Version on STEAM16.793

Webchat:
Visit the chat

## Simple ocean / water surface / waves

#### FutureCow

After searching the web I found it very difficult to find a basic simulation of the oceans  surface / waves - there's plenty of complex fluid simulations, but what I wanted was effectively just a 3D sine wave. After a bit more searching for 3D sine wave algorithms and a bit of experimentation I've ended up with a modified series of a hyperbolic paraboloid (also known as a saddle surface - http://en.wikipedia.org/wiki/Paraboloid).

Forgive my code if there's a lot better / more efficient way to create/animate the 3D surface, I'm extremely new to 3D coding.

Changes to the code you may want to make :

* You can get slightly different wave shapes by changing the "-" in the formula to either a "+" or a "*"
* The higher the wave frequency variable the shorter the period of the sine wave shape.  Suggested figures 18,36,72. If you change to other numbers you will have to change the AnimationFrameMax variable as the start and end frames wont line up any more.
* The lower the SizeFactor variable the higher the amplitude of the sine wave.
* Comment out the "DRAWRECT" lines creating the water "texture" and use the LOADSPRITE instead to make it look a lot prettier.
* use some "X_MOVEMENT" and "X_DRAWOBJ" commands to increase the size of the ocean

I haven't gotten around to working out how to change the direction the waves are moving, but I'll leave that as an exercise for the reader
Code (glbasic) Select
`// Project: Ocean Surface// Start: Monday, November 23, 2009// IDE Version: 7.177// Written by Shane HockingsCONSTANT WaveAnimationFrameMax%=20                        // How many frames before we return to the start frameCONSTANT GridSizeX%=40CONSTANT GridSizeZ%=40CONSTANT SizeFactor%=3                              // A lower number = higher sine wave amplitudeCONSTANT WaveFrequency%=36                        // Higher number = shorter sine wave periodGLOBAL HeightMap#[]                              // The array storing the heights for each square in our water surfaceDIM HeightMap#[GridSizeX%][GridSizeZ%]GLOBAL WaterTexture                              // Sprite for the textureGLOBAL GlobalTimer// ------------------------------------------------------------- //// ---  MAIN  ---// ------------------------------------------------------------- //WaterTexture=GENSPRITE()                  // Reserve the sprite for the water textureGOSUB CreateWaterTexture                  // Create/load the water textureWHILE TRUE    X_MAKE3D 1, 600, 45                     // Make 3D window    X_CAMERA 0,10,-10, 10, 0, 10            // Set up the camera    X_AMBIENT_LT 0, RGB(255,255,255)   //timer = 100 ms    UpdateGrid(200)                     // Create the waves      X_SETTEXTURE WaterTexture,-1            // Give them texture    X_DRAWOBJ 1,0    //need this for right time, must be with showscreen GlobalTimer=GETTIMER() SHOWSCREEN                           // Display them on the screenWEND// ------------------------------------------------------------- //// ---  UPDATEGRID  ---// ------------------------------------------------------------- //FUNCTION UpdateGrid: Timer_ms   // These values are defined LOCAL:// Counter%   STATIC WaveTimer   STATIC WaveAnimationFrame   WaveTimer=WaveTimer+GlobalTimer   IF WaveTimer>=Timer_ms THEN WaveTimer = 0   IF WaveTimer<>0 THEN RETURN 0 //not ready to render yet=0    WaveAnimationFrame=WaveAnimationFrame+1                 // Due to earlier return, this only executes when the timer >= Timer_ms    IF WaveAnimationFrame=WaveAnimationFrameMax% THEN WaveAnimationFrame=0            // Reset animation    LOCAL X, Z    FOR Z=0 TO GridSizeZ-1                                             // For each grid location        FOR X=0 TO GridSizeX-1            HeightMap[X][Z]=(SIN((X+WaveAnimationFrame)*36)-SIN((Z+WaveAnimationFrame)*36))/SizeFactor                                                                  // Formula for saddle surface : Z = x^2 - y^2                                                                    // X and Z are points on a sine curve        NEXT    NEXT    X_OBJSTART 1                                                   // Create 3D object number 1    FOR Z=0 TO GridSizeZ-2        X_OBJNEWGROUP                                                // Create a new group of polygons every row        FOR X=0 TO (GridSizeX/2)-1                                       // As a trangle is drawn between column [X] and column [X+1] (ie. 2 columns)                                                                 // we only need to loop through half of them      X_OBJADDVERTEX   X,   HeightMap[X][Z+1],  Z+1,  0,0, RGB(0,0,255)         // Create quad        X_OBJADDVERTEX   X,   HeightMap[X][Z],      Z,  0,1, RGB(0,0,255)        X_OBJADDVERTEX   X+1, HeightMap[X+1][Z+1], Z+1, 1,0, RGB(0,0,255)        X_OBJADDVERTEX   X+1, HeightMap[X+1][Z],    Z,  1,1, RGB(0,0,255)        NEXT    NEXT    X_OBJEND                                                      // Finished 3D object number 1   RETURN 1 //an object was built =1ENDFUNCTION // UPDATEGRID// ------------------------------------------------------------- //// ---  CREATEWATERTEXTURE  ---// ------------------------------------------------------------- //SUB CreateWaterTexture:      // Either create a texture that's a white box with blue outline      DRAWRECT 0,0,32,32,RGB(0,0,255)                        // Create a filled blue box   DRAWRECT 1,1,30,30,RGB(255,255,255)                     // Create a filled white box just inside it   GRABSPRITE WaterTexture,0,0,32,32                     // Grab the boxes into sprite "WaterTexture"   // OR load a texture instead      //LOADSPRITE "Water.png", WaterTexture                  // Load a texture for the waterENDSUB // CREATEWATERTEXTURE`

Modified to include changes from Hemlos

#### Hemlos

#1
AnimationFramea
caused error...needs to be AnimationFrame

That is really cool stuff man.

I altered your code so that the program can run full speed.
The difference is, i stored gettimer() value to time the ocean.
To use gettimer, you must have the gettimer right before showscreen,
AND sleep 1, MUST be right after showscreen.
If you dont take these steps, then the ocean will "jitter", as gettimer has some bug if you dont sleep 1 millisecond after showscreen.
I use the gettimer value inside the update function.
A second parameter to the function is added to set the milliseconds per frame.
This allows you to set the time for only the ocean, while the whole program can run max speed.

Code (glbasic) Select
`// Project: Ocean Surface// Start: Monday, November 23, 2009// IDE Version: 7.177// Written by Shane HockingsGLOBAL GridSizeX%=40GLOBAL GridSizeZ%=40GLOBAL SizeFactor%=3 // A lower number = higher sine wave amplitudeGLOBAL WaveFrequency%=36 // Higher number = shorter sine wave periodGLOBAL AnimationFrameMax%=20 // How many frames before we return to the start frameGLOBAL HeightMap#[] // The array storing the heights for each square in our water surfaceDIM HeightMap#[GridSizeX%][GridSizeZ%]GLOBAL WaterTexture // Sprite for the texture// ------------------------------------------------------------- //// ---  MAIN  ---// ------------------------------------------------------------- //LOCAL AnimationFrame = -1 // Initialise wave animation frame counterWaterTexture=GENSPRITE() // Reserve the sprite for the water textureGOSUB CreateWaterTexture // Create/load the water textureWHILE TRUE    AnimationFrame=AnimationFrame+1    IF AnimationFrame=AnimationFrameMax% THEN AnimationFrame=0 // Reset animation     X_MAKE3D 1, 600, 45 // Make 3D window    X_CAMERA 0,10,-10, 10, 0, 10 // Set up the camera    X_AMBIENT_LT 0, RGB(255,255,255) //timer = 100 ms    UpdateGrid(AnimationFrame, 200) // Create the waves X_SETTEXTURE WaterTexture,-1 // Give them texture    X_DRAWOBJ 1,0 //need this for right time, must be with showscreen gTIMER=GETTIMER()    SHOWSCREEN // Display them on the screen        //i removed this:  SLEEP 200    // must have sleep 1 for gettimer to work        SLEEP 1 // Pace the animationWEND// ------------------------------------------------------------- //// ---  UPDATEGRID  ---// ------------------------------------------------------------- //FUNCTION UpdateGrid: AnimationFrame, Timer_ms // These values are defined LOCAL:// Counter% STATIC timer timer=timer+gTIMER IF timer>=Timer_ms THEN timer = 0 IF timer<>0 THEN RETURN 0 //not ready to render yet=0    LOCAL X, Z    FOR Z=0 TO GridSizeZ-1 // For each grid location        FOR X=0 TO GridSizeX-1            HeightMap[X][Z]=(SIN((X+AnimationFrame)*36)-SIN((Z+AnimationFrame)*36))/SizeFactor            // Formula for saddle surface : Z = x^2 - y^2             // X and Z are points on a sine curve        NEXT    NEXT    X_OBJSTART 1 // Create 3D object number 1    FOR Z=0 TO GridSizeZ-2        X_OBJNEWGROUP // Create a new group of polygons every row        FOR X=0 TO (GridSizeX/2)-1 // As a trangle is drawn between column [X] and column [X+1] (ie. 2 columns)        // we only need to loop through half of them X_OBJADDVERTEX   X,   HeightMap[X][Z+1],  Z+1,  0,0, RGB(0,0,255) // Create quad        X_OBJADDVERTEX   X,   HeightMap[X][Z],      Z,  0,1, RGB(0,0,255)        X_OBJADDVERTEX   X+1, HeightMap[X+1][Z+1], Z+1, 1,0, RGB(0,0,255)        X_OBJADDVERTEX   X+1, HeightMap[X+1][Z],    Z,  1,1, RGB(0,0,255)        NEXT    NEXT    X_OBJEND // Finished 3D object number 1    RETURN 1 //an object was built =1ENDFUNCTION // UPDATEGRID// ------------------------------------------------------------- //// ---  CREATEWATERTEXTURE  ---// ------------------------------------------------------------- //SUB CreateWaterTexture: // Either create a texture that's a white box with blue outline DRAWRECT 0,0,32,32,RGB(0,0,255) // Create a filled blue box DRAWRECT 1,1,30,30,RGB(255,255,255) // Create a filled white box just inside it GRABSPRITE WaterTexture,0,0,32,32 // Grab the boxes into sprite "WaterTexture" // OR load a texture instead //LOADSPRITE "Water.png", WaterTexture // Load a texture for the waterENDSUB // CREATEWATERTEXTURE`
Bing ChatGpt is pretty smart

#### FutureCow

Awesome, thanks Hemlos. I changed the variable name in the post to make the code more readable - I obviously didn't try compiling it again after the change
I like your changes too - good work!

#### Hemlos

I added a grid function, in that other thread you started.
Bing ChatGpt is pretty smart

#### FutureCow

#4
Cheers buddy! I fixed that typo in the original post too just in case someone copies it rather than yours.

#### FutureCow

Hemlos, I've updated my code to reflect your changes and fix a small bug yours had. You were updating the animation frame once every game loop, but only drawing whatever frame was current after the timer delay (which meant frames were getting missed). I've fixed it so AnimationFrame only advances when the timer delay has passed (ie. when timer=0 from your code)

#### Hemlos

#6
Ahh cool, glad you caught that, it is your baby afterall
A shot in the dark here.....the twitching error i noticed was due to this which i missed.

Great work man, it works really good.

I assume we can remove SLEEP 1.....which is good because it will go from 60 fps up to 4000 fps.

When i said sleep 1 makes it run full speed, i was wrong, i noticed an error with glbasic and this.

So lets try to see what happens without it....
Bing ChatGpt is pretty smart

#### Hemlos

#7
Success, i got it to run full speed now....3300 FPS woo!
REMOVE from your main code SLEEP 1.

Also dont forget to move your globals and local global from the main code, into the function as locals instead.

GLOBAL AnimationFrameMax%=20
LOCAL AnimationFrame% = -1

These should be added to the function STATIC
STATIC AnimationFrameMax,AnimationFrame
Bing ChatGpt is pretty smart

#### Qedo

I am trying the Ocean Surface and am getting only 4 FPS (in the best condition).
I read in the topic of 3300 FPS!!!!
Is there something wrong on my computer or 3300 is exhausted?
I miss something?
Someone can try?
Thank you