¿Cómo animar la textura abstracta del agua de arriba hacia abajo en 2D?

24

Actualmente implemento un juego con una vista de arriba hacia abajo del océano. Yo uso lo siguiente, una pequeña textura abstracta:ingrese la descripción de la imagen aquí

La textura real es transparente, agregué el color verde para mayor claridad.

El problema que tengo ahora es que no sé cómo animar esta textura para que el agua se vea bien. Traté de mover la textura con una ola pecado texture.y += sin(angle). Por supuesto, ahora toda la textura se está moviendo, lo que parece poco realista. Lo siguiente que intenté es agregar otra capa e implementar un efecto de paralaje. De modo que los reflejos debajo de la superficie del agua también se moverían, pero mucho más lentamente. Se ve un poco mejor pero aún no ... lo suficientemente agradable.

Creo que la mejor animación sería, si las celdas individuales se expandieran y contrajeran, como una telaraña o tela. Imagínese si alguien tirara levemente de un vértice de estas celdas y la celda vecina se expandiera y la celda que yo jale hacia (o empuje) se contraiga. Algo así como una red de resortes (?). Pero no tengo idea de cómo implementar algo como esto:

  • ¿Cuál es el modelo matemático para esto? Algo con resortes, donde las fuerzas empujan / tiran?
  • Y si es así, ¿cómo mapeo este modelo a la textura dada? Manteniendo todas las curvas y lo que no ...

(También estoy abierto a diferentes ideas / respuestas sobre cómo animar la textura dada. El realismo no es el punto aquí, solo algunos movimientos agradables como el agua ...)

Solución de DMGregory

Publiqué un ejemplo de libgdx en esta publicación: la animación de agua 2d es irregular y no es uniforme (vea la respuesta sobre el filtrado de texturas)

morfeo05
fuente

Respuestas:

41

Una forma común de hacerlo es mediante una búsqueda indirecta de textura en el sombreador para distorsionar la textura de la pantalla:

Gif animado que muestra animación de agua

Aquí estoy usando una textura con un poco de ruido de color de baja frecuencia (mosaicos suaves de colores aleatorios) y desplazándola a través de la geometría de la pantalla con el tiempo.

ingrese la descripción de la imagen aquí

En lugar de dibujar los colores de esta textura, tomo los canales rojo y verde y los resto 0.5fpara convertirlos en un vector 2D pseudoaleatorio que cambia suavemente con el tiempo y el espacio.

Luego puedo agregar un pequeño múltiplo de este vector a mis coordenadas UV, antes de tomar muestras de la textura principal del agua. Esto cambia la parte de la textura que estamos leyendo y mostrando, deformando.

Al promediar dos muestras de este ruido, desplazándonos en direcciones opuestas, podemos ocultar la dirección del movimiento para que parezca un chapoteo sin rumbo.

En Unity, el sombreador se vería así: debería ser lo suficientemente simple como para traducirlo al idioma del sombreador que elija:

fixed4 frag (v2f i) : SV_Target
{               
    float2 waveUV = i.uv * _NoiseScale;
    float2 travel = _NoiseScrollVelocity * _Time.x;

    float2 uv = i.uv;
    uv += _Distortion * (tex2D(_Noise, waveUV + travel).rg - 0.5f);
    waveUV += 0.2f; // Force an offset between the two samples.
    uv += _Distortion * (tex2D(_Noise, waveUV - travel).rg - 0.5f);

    // Sample the main texture from the distorted UV coordinates.
    fixed4 col = tex2D(_MainTex, uv);

    return col;
}
DMGregory
fuente
1
Esto se ve muy bien. No estoy seguro de entender todos los atributos: _NoseScale = escalar para escalar el "mapa de ruido". _NoiseScrollVelocity = Vector2 a qué velocidad nos movemos a través del mapa de ruido. _ Ruido =?. _Distortion = Escalar que elijo como factor de distorsión? v2f = Vértice determinamos el color. i =?
morpheus05
_Noisees [una muestra de textura que lee] la pequeña textura aleatoria de arriba. v2f ison los datos interpolados del sombreador de vértices; los usamos principalmente para obtener las coordenadas de textura para el píxel que estamos dibujando i.uv. Y tienes toda la razón sobre todo lo demás.
DMGregory
Implementé el sombreador y de alguna manera no funciona (no se mueve o la distorsión es demasiado grande), supongo que no configuré los valores correctamente. tiempo = la diferencia desde el último cuadro en ms. noise_scale = 1 (uso su textura, repetición del modo de ajuste) noise_scroll_velocity = [0.01, 0.01] distorsión = 0.02
morpheus05
Tenga en cuenta que la variable se llama Tiempo, no DeltaTime. Si usa una diferencia de tiempo y su velocidad de fotogramas es consistente, siempre obtendrá el mismo número y volverá a ejecutar el sombreador con las mismas entradas, obteniendo la misma salida (nada se mueve). Peor aún, si su velocidad de fotogramas es inconsistente, obtendrá vibraciones de ida y vuelta. Desea que transcurra el tiempo total, no el tiempo delta.
DMGregory
Apenas presiono enviar me di cuenta de eso y ahora casi funciona. La animación parece encauzar las olas desde la esquina inferior derecha y después de unos 10 segundos se desvanece, como olas que se detienen. ¿Cuál podría ser la razón de ésto?
morpheus05
6

Esto se denomina efecto cáustico, y generar estos efectos en tiempo de ejecución consume bastante tiempo, por lo que esto se hace tradicionalmente con animación pre-renderizada cuadro por cuadro. Existen herramientas que generarán cuadros de animación cáusticos para usted, como Caustics Generator , que tiene una versión gratuita para uso no comercial. También hay algunos prefabricados que puede comprar por un precio significativamente más barato que la versión profesional de la herramienta que mencioné.

Tenga en cuenta que los efectos cáusticos también suelen ser un efecto aplicado como una galleta ligera en un terreno submarino o en la superficie submarina. Es decir, ponerlo en la superficie del agua mientras se mira hacia abajo no suele ser el aspecto del agua.

Ed Marty
fuente
Eso es muy interesante, también echaré un vistazo a este generador (sin embargo, probaré la variante de sombreador si lo entiendo ...)
morpheus05
4

Esto parece una textura que podría generar a partir de un gráfico voronoi, por ejemplo:

ingrese la descripción de la imagen aquí

Puede hacer ajustes pequeños y suaves en el gráfico moviendo los puntos; volver a dibujar el gráfico en cada cuadro sería bastante costoso, por lo que es probable que desee renderizar previamente la animación.

FacticiusVir
fuente
44
De hecho, he hecho cáusticos de esta manera en un sombreador en el pasado. No es necesariamente tan costoso como podría pensar ( aquí hay un ejemplo que muestra los bordes de Voronoi en tiempo real en un sombreador WebGL ), aunque obtener la forma suave correcta en los bordes, en lugar de polígonos puntiagudos, puede ser un desafío.
DMGregory
Ooo, eso es muy lindo; Tengo algunos generadores de terreno para los que sería muy útil.
FacticiusVir
0

Hay un método de la vieja escuela, que implica una capa de textura inferior y dos texturas medio transparentes para la reflexión en la parte superior.

Si desea llegar hasta el final y desea que el agua no se vea llena de olas clonadas o mapas de flujo de sopa azul samish, debe llegar al objetivo.

https://steamcdn-a.akamaihd.net/apps/valve/2010/siggraph2010_vlachos_waterflow.pdf

Pica
fuente
3
Aunque los enlaces pueden ayudar, nunca dan buenas respuestas. ¿Podrías ampliar ambos métodos de tesis? ¿Cómo se implementaría?
Vaillancourt
El primer método es básicamente un método muy antiguo utilizado para animar el agua: se toma una textura de agua de capa base cuyas coordenadas UVW se desplazan en la dirección que usted elija. Ahora aplica además un mapa / mapa de relieve normal que cambia en otra dirección; si se hace bien, esto parece convincente para ríos pequeños. Sin embargo, es muy limitado para grandes cuerpos de agua, ya que cualquier cosa que reensamble las olas tendrá efecto muaré. El enlace explica el uso de mapas de flujo mucho más lejos de lo que podría.
Pica
Utilice la función de edición para mejorar la pregunta con lo que agregó aquí :) Las personas están acostumbradas a buscar respuestas en la publicación, no en los comentarios.
Vaillancourt