Pygame water ripple effect

前端 未结 2 587
死守一世寂寞
死守一世寂寞 2021-02-01 14:48

I have Googled for it but there are no ready scripts - as opposed to the same effect on Flash. I have checked the algorithm on The Water Effect Explained and also tested an imp

2条回答
  •  南方客
    南方客 (楼主)
    2021-02-01 15:24

    The following using numpy might get you started. It should be fast enough as it is though you could get much faster even in python (have a look here to see how http://www.scipy.org/PerformancePython).

    By the way there are several drawbacks in the method described :

    1. you cannot control the speed of the ripples - to do that you would have to modify the equations used in the ripple function (if you figure out how it relates to the wave equation http://en.wikipedia.org/wiki/Wave_equation then you are done)
    2. the "depth" of the "pool" is fixed (and probably too shallow). I added a depth parameter to magnify the effect
    3. the article reads integer pixel offsets - you would get a much nicer result with interpolated values (i guess you can do that with opengl, but my knowledge in that area is nil)

    code:

    import numpy
    
    def ripple(w1, w2, damp, n = 1):
        for _ in xrange(n):
            w2 *= -2
            w2[1:-1,1:-1] += w1[0:-2, 1: -1]
            w2[1:-1,1:-1] += w1[2:  , 1: -1]
            w2[1:-1,1:-1] += w1[1:-1, 0: -2]
            w2[1:-1,1:-1] += w1[1:-1, 2:   ]
            w2 *= .5 * (1. - 1./damp)
            w1, w2 = w2, w1
    
    def refract(x, y, w, rindex, depth = 10):
        sx = x[0,1] - x[0,0]
        sy = y[1,0] - y[0,0]
    
        dw_dx = (w[2: ,1:-1] - w[:-2,1:-1]) / sx * .5
        dw_dy = (w[1:-1,2: ] - w[1:-1,:-2]) / sy * .5
    
        xang = numpy.arctan(dw_dx)
        xrefract = numpy.arcsin(sin(xang) / rindex)
        dx = numpy.tan(xrefract) * dw_dx * depth
    
        yang = numpy.arctan(dw_dy)
        yrefract = numpy.arcsin(sin(yang) / rindex)
        dy = numpy.tan(yrefract) * dw_dy * depth
    
        dx *= numpy.sign(dw_dx)
        dy *= numpy.sign(dw_dy)
    
        xmin = x[0,0]
        xmax = x[0,-1]
        x[1:-1,1:-1] += dx
        x[:,:] = numpy.where(x < xmin, xmin, x)
        x[:,:] = numpy.where(x > xmax, xmax, x)
    
        ymin = y[0,0]
        ymax = y[-1,0]
        y[1:-1,1:-1] += dy
        y[:,:] = numpy.where(y < ymin, ymin, y)
        y[:,:] = numpy.where(y > ymax, ymax, y)
    

    x and y should be grids from a numpy.meshgrid call : here's a sample usage:

        x,y = meshgrid(x,y)
        w = 10 * exp(- (x*x + y*y))
        w1 = w.copy()
        x1,y1 = meshgrid(r_[0:len(x):1.0], r_[0:len(y):1.0])
        ripple(w, w1, 16) # w1 will be modified
        refract(x1, y1, w1, rindex=2, depth=10) # x1 and y1 will be modified
        numpy.around(x1, out=x1) # but you will get better results with interpolate
        numpy.around(y1, out=y1) # 
    

提交回复
热议问题