Пигмейный водный волновой эффект - PullRequest
33 голосов
/ 04 октября 2011

У меня есть Googled, но готовых скриптов нет - в отличие от того же эффекта на Flash. Я проверил алгоритм на The Water Effect Explained , а также протестировал реализацию Perlin Noise , которая обеспечивает хорошее моделирование конца волн на плоской поверхности. Я ищу ту же реализацию, найденную в нескольких эффектах Flash, основанную на действиях при наведении курсора мыши. Это нацелено на интерактивную напольную библиотеку, и я бы с удовольствием отошел от Flash по этому вопросу, особенно во избежание такого простого обратного проектирования кода - и да, я знаю, что он мог бы просто использовать некоторый готовый флэш-код, но я будет использовать это только в качестве крайней меры.

Кто-нибудь видел подходящую реализацию этого эффекта для Pygame (используя OpenGL или нет)?

РЕДАКТИРОВАТЬ: Может ли кто-нибудь предоставить подходящую реализацию этого эффекта с использованием OpenCV / OpenGL и Pygame?

Причиной здесь является (код) интерфейс для передачи списка значений, которые будут отправлены из внешнего интерпретатора (трекер, но не TUIO) через Python. Я пробовал несколько дней подряд, но Pygame не может генерировать что-либо так быстро, как чистый код C / C ++ (как используется для шейдеров в OpenGL), и мои знания C / C ++ нулевые. Поэтому цель состоит в том, чтобы, по крайней мере, получить это из кода Python.

Хороший пример, отличный от эффекта Flash, но все же хороший: Water Simulation с использованием Java-апплета .

(щедрость показывает, что в ответах недостаточно подробностей, поскольку это было ближе всего к «ОП не способен создать код, который ему нужен, так как ему не хватает фундаментальных навыков, и этот ответ, вероятно, пригодится нескольким людям»).

Ответы [ 2 ]

9 голосов
/ 27 октября 2011

После выполнения домашней работы (также известного как исследование) и попытки напрямую преобразовать ссылку на Java-код, размещенную по этому вопросу, в Python, и получить очень, очень печальный опыт при попытке Python / Numpy обновить огромный массив цветов пикселей на основе их позиции для волнового эффекта ряби (извините, мой родной язык не является английским), таким образом анализируя несколько (x, y) позиций для каждого прохода вычислений эффекта и перетаскивая их на отображаемую поверхность на экране (появляется прибой) ), Я пришел к выводу - что подтверждается другими комментаторами - что Pygame просто не будет достаточно мощным, чтобы фактически пересечь весь массив пикселей и применить результаты вычислений к каждому пикселю на экран с минимальной скоростью 24 кадра в секунду (для опыта ниже среднего).

Цитируя самого разработчика, стоящего за Last Light Productions и бывшего Project Geometrian , Ян Маллет:

PyGame не очень хорош для толчков пикселей. Ничего, кроме графического процессора.

Поиск тогда оказался поиском Alkahest - чего-то, что, как оказалось, никогда не будет найдено - и основано на той же идее, что и изображения, но на этот раз с помощью прозрачности для сквозь несколько слоев поверхностей Pygame, я разместил вопрос Круговая обрезка / маски Pygame на Gamedev. выбранный ответ на самом деле подтверждает тот факт, что я уже боялся, что Pygame никогда не будет достаточно мачо для работы.

Через день я вернулся к своим предыдущим идеям по разработке и наткнулся на Ogre3D . Оказывается, что (1) Ogre3D и образцы являются открытым исходным кодом, и (2) один из примеров - это трехмерная модель воды, которая взаимодействует с движущимся объектом, то же самое, что я пытался достичь в 2-D, но гораздо профессиональнее.

Поскольку мои знания C / C ++ равны нулю, я решил спросить о , как настроить демонстрацию воды Ogre3D , чтобы узнать, с чего начать, и один из ответов указал мне на программное обеспечение от Touchscape, где предоставляется SDK (см. этот ответ ).

Ogre3D в значительной степени обернул его. Эффект водной ряби, OpenGL (который может опционально использовать на основе аппаратного обеспечения), Game Engine и оболочки Python через Python-Ogre - так что мой ответ на мой собственный вопрос,

Может ли кто-нибудь предоставить подходящую реализацию этого эффекта, используя OpenCV / OpenGL и Pygame?

в основном

Да. Проверьте демонстрацию воды в Ogre3D, поставляемую с SDK, и подключите ее к Python через Python-Ogre .

5 голосов
/ 08 октября 2011

Следующее использование numpy поможет вам начать. Он должен быть достаточно быстрым, хотя он может быть намного быстрее даже в Python (посмотрите здесь, чтобы увидеть, как http://www.scipy.org/PerformancePython).

Кстати, у описанного метода есть несколько недостатков:

  1. вы не можете контролировать скорость пульсации - для этого вам нужно будет изменить уравнения, используемые в функции пульсации (если вы выясните, как она связана с волновым уравнением http://en.wikipedia.org/wiki/Wave_equation, то все готово)
  2. «глубина» «пула» фиксирована (и, вероятно, слишком мала). Я добавил параметр глубины, чтобы увеличить эффект
  3. статья читает смещения целочисленных пикселей - вы получите гораздо лучший результат с интерполированными значениями (я думаю, вы можете сделать это с помощью 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) # 
...