Пигмейный водный волновой эффект

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

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

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

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

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

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

2 ответа

Решение

После выполнения домашней работы (или исследования) и попытки напрямую преобразовать ссылку на 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.

Следующее использование 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) # 
Другие вопросы по тегам