Ripple Hack on Large Grids

Started by
3 comments, last by serumas 11 years, 9 months ago
Hi,

Problem is: objects fall into a 2D tank, leaving 1D ripples.

I have implemented techniques similar to the technique best described here: http://freespace.virgin.net/hugo.elias/graphics/x_water.htm. Unfortunately, these quickly result in high frequency noise because of the initial discontinuity of perturbing a single particle. However, though the particles are oscillating, I can make out slow-moving waves. It's these slow-moving waves that I want!

Basically, I'm looking for a hackish algorithm that can generate plausible-looking waves on the surface of a 1D grid, using any detail level of grid.

I present the following Python code as a demonstration of the algorithm's faults, and as a testbed for new algorithms:[source lang="python"]import pygame
from pygame.locals import *
import sys, os, traceback
if sys.platform == 'win32' or sys.platform == 'win64':
os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.display.init()
pygame.font.init()
screen_size = [1200,200]
icon = pygame.Surface((1,1)); icon.set_alpha(0); pygame.display.set_icon(icon)
pygame.display.set_caption("1D Surface Test - Ian Mallett - v.1 - 2012")
surface = pygame.display.set_mode(screen_size)
num = 300
#====================================METHOD 1====================================
###My feeble algorithm
##class particle:
## def __init__(self):
## self.height = 0
## self.speed = 0
## self.force = 0
## def apply(self,force):
## self.force += 10*force
##def update():
## particles[0].force += -0.1*(particles[0].height-0.0)
## for i in xrange(1,num,1):
## particles.force += -0.1*(particles.height-particles[i-1].height)
##
## for i in xrange(0,num-1,1):
## particles.force += -0.1*(particles.height-particles[i+1].height)
## particles[-1].force += -0.1*(particles[-1].height-0.0)
##
## for i in xrange(0,num,1):
## particles.force += -0.1*(particles.height-0.0)
##
## for i in xrange(0,num,1):
## particles.speed += particles.force
## particles.speed *= 0.9999
## particles.height += particles.speed
## particles.force = 0
#====================================METHOD 2====================================
#Method after http://freespace.virgin.net/hugo.elias/graphics/x_water.htm
class particle:
def __init__(self):
self.buffer1 = 0.0
self.buffer2 = 0.0
self.height = 0.0
def apply(self,force):
self.buffer1 += 10*force
def update():
## kernel = 1
for i in xrange(1,num-1,1):
particles.buffer2 = (
particles[i-1].buffer1+
particles[i+1].buffer1
)/2.0 - particles.buffer2
## last = particles.buffer2
## particles.buffer2 = 0.0
## max_sum = 0.0
## for x in xrange(-kernel,kernel+1,1):
## index = i + x
## if index < 0: continue
## if index >= num: continue
## particles.buffer2 += particles[index].buffer1
## max_sum += 1.0
## particles.buffer2 /= max_sum
## particles.buffer2 -= last

particles.buffer2 *= 0.99999
particles.height = particles.buffer2
for i in xrange(0,num,1):
temp = particles.buffer2
particles.buffer2 = particles.buffer1
particles.buffer1 = temp
#====================================END METHODS====================================
def setup():
global particles, paused
particles = [particle() for x in xrange(num)]
paused = False
def get_input():
global paused
key = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == QUIT: return False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE: return False
elif event.key == K_UP: particles[150].apply(10)
elif event.key == K_DOWN: particles[150].apply(-10)
elif event.key == K_p: paused = not paused
elif event.key == K_LEFT: update()
elif event.key == K_r: setup()
return True
def draw():
surface.fill((0,0,0))
points = []
x = 0
for particle in particles:
x += 4
points.append((x,particle.height+100))
pygame.draw.aalines(surface,(50,50,50),False,points)
i = 0
for point in points:
color = [(255,0,0),(0,255,0)][i%10==0]
pygame.draw.circle(surface,color,point,2,0)
i += 1

pygame.display.flip()
def main():
setup()
clock = pygame.time.Clock()
while True:
if not get_input(): break
if not paused: update()
draw()
clock.tick(60)
pygame.quit(); sys.exit()
if __name__ == '__main__':
try:
main()
except Exception, e:
tb = sys.exc_info()[2]
traceback.print_exception(e.__class__, e, tb)
pygame.quit()
raw_input()
sys.exit()[/source]After a few waves hit the tank, you get:
highfreq.png

So, can anyone suggest an algorithm? Or maybe some gaping flaw in my implementation?

Thanks!
Ian

[size="1"]And a Unix user said rm -rf *.* and all was null and void...|There's no place like 127.0.0.1|The Application "Programmer" has unexpectedly quit. An error of type A.M. has occurred.
[size="2"]

Advertisement
For 2d and 3d cases, solving the actual wave equation with the euler method isn't fast enough, but it might be for 1d! It's not hard to implement if you're familiar with the math.
I've made a quick implementation with unity here and I didn't like it.. very hard to find the a suitable set or parameters to make the simulation behave properly. It's preytty fast though! My line has 50 points and it runs with more than a thousand fps. I used a damped wave equation and euler method. If you're interested I can give you the code.
in first place in this method you must limit fps inside your game loop for example if game runs 60-1000 fps water algorithm must run on 40 fps , to fast fps can generate to fast waves = as you say noise.
theres game atempt to use water waves
http://serumas.gamedev.lt/index.php?id=bakterijos1
page not in english but it contains video of game
in first place in this method you must limit fps inside your game loop for example if game runs 60-1000 fps water algorithm must run on 40 fps , to fast fps can generate to fast waves = as you say noise.
theres game atempt to use water waves
http://serumas.gamedev.lt/index.php?id=bakterijos1
page not in english but it contains video of game

This topic is closed to new replies.

Advertisement