Pygame 水波纹效果
Posted
技术标签:
【中文标题】Pygame 水波纹效果【英文标题】:Pygame water ripple effect 【发布时间】:2011-11-30 16:12:55 【问题描述】:我在 Google 上搜索过,但没有现成的脚本 - 与 Flash 上的效果相反。我检查了The Water Effect Explained 上的算法,还测试了Perlin Noise 的实现,它可以很好地模拟平面上的波的末端。我正在寻找基于鼠标悬停/悬停动作的几个 Flash 效果的相同实现。这是针对交互式地板库的,我很乐意在这件事上远离 Flash,特别是为了避免对代码进行如此简单的逆向工程——是的,我知道它可以只使用一些现成的 Flash 代码,但我只会将其用作最后的手段。
有没有人看到 Pygame 的这种效果的合适实现(使用或不使用 OpenGL)?
编辑: 任何人都可以使用 OpenCV/OpenGL 和 Pygame 提供此效果的合适实现吗?
这里的罪魁祸首是(代码)接口,用于传递将通过 Python 从外部解释器(跟踪器 - 虽然不是 TUIO)发送的值列表。我已经尝试了几天,但 Pygame 无法像纯粹的 C/C++ 代码(用于 OpenGL 中的着色器)那样快速生成任何东西,而且我对 C/C++ 的了解是空的。所以目标是至少有来自 Python 代码的内容。
一个很好的例子,与 Flash 效果不同但仍然很好是Water Simulation using Java applet。
(赏金显示答案没有足够的细节,因为这是最接近“OP 无法创建他想要的代码,因为他缺乏基本技能,这个答案可能对几个人有用”)。
【问题讨论】:
这是您希望它的工作方式吗? flash-effects.com/tutorial-create-a-water-ripple-mouse-follow 可能还想试试 gamedev.stackexchange.com,那里的运气可能更好。 我很无聊,并使用 C++ 和 OpenCV 从您的第一个链接实现了算法(我还没有尝试过 pygame)。 github.com/mpenkov/sandpit/tree/master/***。实现起来并不难,但它看起来不如我上面链接中的 Flash 版本。我还是不知道为什么。 @misha,我设法在我的 Ubuntu VM 上运行了你放在一起的代码。太棒了。 @misha,我认为 Pygame 比纯粹的 C++ 代码要慢。稍后我将尝试将您的实现移植到纯 Pygame,然后是 Pygame + OpenGL 并在此处发布结果和/或源代码。应该花我一到三天的时间。 【参考方案1】:在完成作业(又名研究)并尝试将发布在问题上的 Java 代码参考直接转换为 Python 之后,在尝试让 Python/Numpy 更新基于它们用于涟漪效应的位置(对不起,我的第一语言不是英语),因此每次通过效果计算解析几个 (x,y) 位置并将其传送到屏幕上显示的表面上(随后出现 surfarray ),我得出的结论——得到了其他评论者的支持——Pygame 根本 不会 强大到足以真正遍历整个像素数组并将计算结果应用于每个像素以最低 24 fps 的速度在屏幕上显示(以获得低于平均水平的体验)。
引用 Last Light Productions 和前 Project Geometrian 背后的开发者 Ian Mallet:
PyGame 不太适合像素推送。除了 GPU,什么都没有。
然后搜索结果是搜索Alkahest - 结果永远不会真正找到 - 并且基于波纹图像的相同想法,但这次使用透明度看穿 几层 Pygame 表面,我在 Gamedev 上发布了问题Pygame circular cropping/masks。 chosen answer 实际上证实了我已经担心 Pygame 永远不会macho足以胜任这项工作的事实。
一天后,我回到我之前的开发想法,遇到了Ogre3D。事实证明,(1)Ogre3D 和示例是开源的,(2)其中一个示例是与移动物体交互的 3-D 水模型,这与我尝试在 2-D 中实现的完全一样,但是以更专业的方式。
由于我对 C/C++ 的了解为零,因此我决定询问 how to customize the Ogre3D water demo 以了解从哪里开始寻找,其中一个答案将我指向提供 SDK 的 Touchscape 软件(请参阅 @987654328 @)。
Ogre3D 几乎把它包起来了。水波纹效果、OpenGL(它可能 optionally 基于硬件使用)、游戏引擎和 Python 包装器通过 Python-Ogre - 所以我对自己问题的回答,
任何人都可以使用 OpenCV/OpenGL 和 Pygame 提供此效果的合适实现吗?
基本上是
是的。查看 SDK 提供的 Ogre3D 的水演示 - 并通过 Python-Ogre 将其插入 Python。
【讨论】:
【参考方案2】:以下使用 numpy 的内容可能会让您入门。它应该足够快,尽管即使在 python 中你也可以变得更快(看看这里看看http://www.scipy.org/PerformancePython)。
顺便说一下,所描述的方法有几个缺点:
-
您无法控制波纹的速度 - 为此,您必须修改波纹函数中使用的方程(如果您弄清楚它与波动方程 http://en.wikipedia.org/wiki/Wave_equation 的关系,那么您就完成了)
“池”的“深度”是固定的(可能太浅了)。我添加了一个深度参数来放大效果
这篇文章读取整数像素偏移 - 使用插值会得到更好的结果(我猜你可以使用 opengl 做到这一点,但我在这方面的知识为零)
代码:
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 和 y 应该是来自 numpy.meshgrid 调用的网格:这是一个示例用法:
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) #
【讨论】:
以上是关于Pygame 水波纹效果的主要内容,如果未能解决你的问题,请参考以下文章