python - Efecto de ondulación del agua Pygame
opengl image-processing (2)
Después de hacer los deberes (también conocido como investigación) e intentar convertir directamente la referencia de código Java publicada en la pregunta en Python, y tener una experiencia muy, muy triste al intentar que Python / Numpy actualice una enorme gama de colores de píxeles en función de sus posiciones para la ondulación del efecto dominó (lo siento, mi primer idioma no es el inglés), analizando varias posiciones (x, y) para cada paso de los cálculos del efecto y haciendo un blitting sobre la superficie mostrada en la pantalla (surja surfarray), He llegado a la conclusión, respaldada por otros comentaristas, de que Pygame simplemente no será lo suficientemente poderoso como para atravesar ese conjunto de píxeles y aplicar los resultados de los cálculos a cada píxel de la pantalla a una velocidad mínima de 24 fps. (para una experiencia inferior a la media).
Citando al propio desarrollador detrás de Last Light Productions y el ex Project Geometrian , Ian Mallet:
PyGame no es tan bueno para el empuje de píxeles. Nada es, aparte de la GPU.
La búsqueda resultó ser una búsqueda de Alkahest , algo que nunca se encontraría realmente, y basado en la misma idea de ondular imágenes, pero esta vez al usar transparencia para ver a través de varias capas de superficies de Pygame, publiqué la pregunta sobre el recorte circular / máscaras de Pygame en Gamedev. La respuesta elegida en realidad corrobora el hecho de que ya temía que Pygame nunca sería lo suficientemente macho para el trabajo.
Un día después volví a mis ideas anteriores sobre desarrollo y encontré Ogre3D . Resulta que (1) Ogre3D y las muestras son de código abierto y (2) uno de los ejemplos es un modelo de agua 3-D que interactúa con un objeto en movimiento, exactamente lo mismo que traté de lograr en 2-D, pero de una manera mucho más profesional.
Como mi conocimiento en C / C ++ es nulo, decidí preguntar cómo personalizar la demostración de agua de Ogre3D para tener una idea de dónde empezar a buscar, y una de las respuestas me indicó el software de Touchscape donde se proporciona un SDK (ver este respuesta ).
Ogre3D prácticamente lo envolvió. Efecto de onda de agua, OpenGL (que puede usar optionally basado en hardware), Game Engine y envoltorios de Python-Ogre través de Python-Ogre , así que mi respuesta a mi propia pregunta,
¿Alguien puede proporcionar una implementación adecuada de este efecto usando OpenCV / OpenGL y Pygame?
es básicamente
Sí. Verifique la demostración de agua de Ogre3D, incluida con el SDK, y conéctela a Python a través de Python-Ogre .
Busqué en Google, pero no hay scripts listos, a diferencia del mismo efecto en Flash. Revisé el algoritmo de The Water Effect Explained y también probé una implementación del Perlin Noise , que proporciona una buena simulación del final de las olas en una superficie plana. Estoy buscando la misma implementación que se encuentra en varios Efectos de Flash, en función de las acciones de mouseover / hover. Esto se dirige a una biblioteca de piso interactiva, y me gustaría alejarme de Flash para este asunto, particularmente para evitar una ingeniería inversa tan fácil del código, y sí, sé que podría usar un código de flash ya hecho, pero solo usaría eso como último recurso.
¿Alguien ha visto una implementación adecuada de este efecto para Pygame (usando OpenGL o no)?
EDITAR: ¿Alguien puede proporcionar una implementación adecuada de este efecto usando OpenCV / OpenGL y Pygame?
El culpable aquí es la interfaz (de código) para pasar una lista de valores que se enviarán desde un intérprete externo (rastreador, aunque no a TUIO) a través de Python. Lo he intentado durante algunos días seguidos, pero Pygame no puede generar nada tan rápido como el puro código C / C ++ (como se usa para los sombreadores en OpenGL), y mi conocimiento de C / C ++ es nulo. Entonces, el objetivo es tener al menos eso proveniente del código de Python.
Un buen ejemplo, diferente del efecto Flash, pero que aún es bueno, es Water Simulation usando el applet de Java .
(la recompensa muestra que las respuestas no tienen suficientes detalles ya que esto fue lo más cercano a ''el OP es incapaz de crear el código que desea ya que carece de habilidades fundamentales y esta respuesta probablemente sea útil para varias personas'').
El siguiente uso de numpy podría ayudarlo a comenzar. Debería ser lo suficientemente rápido, ya que aunque puedes obtener mucho más rápido incluso en Python (mira aquí para ver cómo http://www.scipy.org/PerformancePython ).
Por cierto, hay varios inconvenientes en el método descrito:
- no puedes controlar la velocidad de las ondas; para hacerlo, deberías modificar las ecuaciones usadas en la función de ondulación (si entiendes cómo se relaciona con la ecuación de onda http://en.wikipedia.org/wiki/Wave_equation estás listo)
- la "profundidad" del "grupo" es fija (y probablemente demasiado superficial). Agregué un parámetro de profundidad para magnificar el efecto
- el artículo lee compensaciones de píxeles enteros: obtendría un resultado mucho mejor con valores interpolados (supongo que puede hacerlo con OpenGL, pero mi conocimiento en esa área es nulo)
código:
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)
xey deben ser grids de una llamada numpy.meshgrid: aquí hay un ejemplo de uso:
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) #