Controlando miles de peces con Partículas

El problema con MeshInstances es que resulta complicado actualizar su array de transformación. Es genial para colocar muchos objetos estáticos alrededor de la escena. Pero sigue siendo difícil mover los objetos alrededor de la escena.

Para hacer que cada instancia se mueva de forma interesante, usaremos un nodo Particles. Las partículas aprovechan la aceleración de la GPU calculando y configurando la información por instancia en un Shader.

Nota

Las partículas no están disponibles en GLES2, en su lugar usa CPUParticles, que hacen lo mismo que las partículas, pero no se benefician de la aceleración de la GPU.

Primero crea un nodo de Partículas. Luego, bajo "Draw Passes" establece el "Draw Pass 1" de la Partícula a tu Mesh. Luego en "Process Material" crea un nuevo ShaderMaterial.

Ponga el shader_type a particles.

shader_type particles

A continuación, añade dos funciones:

float rand_from_seed(in uint seed) {
  int k;
  int s = int(seed);
  if (s == 0)
    s = 305420679;
  k = s / 127773;
  s = 16807 * (s - k * 127773) - 2836 * k;
  if (s < 0)
    s += 2147483647;
  seed = uint(s);
  return float(seed % uint(65536)) / 65535.0;
}

uint hash(uint x) {
  x = ((x >> uint(16)) ^ x) * uint(73244475);
  x = ((x >> uint(16)) ^ x) * uint(73244475);
  x = (x >> uint(16)) ^ x;
  return x;
}

Estas funciones vienen por defecto ParticlesMaterial. Se usan para generar un número aleatorio para RANDOM_SEED de partícula.

Una cosa única de los shaders de partículas es que algunas variables incorporadas se guardan a través de los fotogramas. TRANSFORM, COLOR, y CUSTOM pueden ser accedidas en al Spatial shader de la malla, y también en el shader de partículas la próxima vez que se ejecuta.

A continuación, configura tu función vertex. Los shaders de partículas sólo contienen una función de vértice y ninguna otra.

Primero distinguiremos entre el código que necesita ser ejecutado sólo cuando el sistema de partículas se inicia y el código que siempre debe ejecutarse. Queremos darle a cada pez una posición aleatoria y un desplazamiento de animación aleatorio cuando el sistema se ejecuta por primera vez. Para ello, envolvemos ese código en una declaración if que comprueba la variable incorporada RESTART que se convierte en true para un fotograma cuando el sistema de partículas es reiniciado.

Desde un alto nivel, esto parece:

void vertex() {
  if (RESTART) {
    //Initialization code goes here
  } else {
    //per-frame code goes here
  }
}

A continuación, necesitamos generar 4 números al azar: 3 para crear una posición aleatoria y uno para el desplazamiento aleatorio del ciclo de natación.

Primero, genera 4 semillas dentro del bloque RESTART usando la función hash proporcionada arriba:

uint alt_seed1 = hash(NUMBER + uint(1) + RANDOM_SEED);
uint alt_seed2 = hash(NUMBER + uint(27) + RANDOM_SEED);
uint alt_seed3 = hash(NUMBER + uint(43) + RANDOM_SEED);
uint alt_seed4 = hash(NUMBER + uint(111) + RANDOM_SEED);

Luego, usa esas semillas para generar números aleatorios usando rand_from_seed:

CUSTOM.x = rand_from_seed(alt_seed1);
vec3 position = vec3(rand_from_seed(alt_seed2) * 2.0 - 1.0,
                     rand_from_seed(alt_seed3) * 2.0 - 1.0,
                     rand_from_seed(alt_seed4) * 2.0 - 1.0);

Finalmente, asigna la position a TRANSFORM[3].xyz`, que es la parte de la transformación que contiene la información de la posición.

TRANSFORM[3].xyz = position * 20.0;

Recuerda, todo este código hasta ahora va dentro del bloque RESTART.

El shader de vértices para su malla puede permanecer exactamente igual que en el tutorial anterior.

Ahora puedes mover cada pez individualmente en cada fotograma, ya sea agregando a la TRANSFORM directamente o escribiendo VELOCITY.

Transformemos a los peces estableciendo su VELOCITY.

VELOCITY.z = 10.0;

Esta es la forma más básica de establecer la VELOCITY, cada partícula (o pez) tendrá la misma velocidad.

Con sólo con poner VELOCITY puedes hacer que los peces naden como tú quieras. Por ejemplo, intenta el código inferior.

VELOCITY.z = cos(TIME + CUSTOM.x * 6.28) * 4.0 + 6.0;

Esto le dará a cada pez una velocidad única entre 2 y 10.

Si usaste CUSTOM.y en el último tutorial, también puedes ajustar la velocidad de la animación de natación basada en la VELOCITY. Sólo usa CUSTOM.y.

CUSTOM.y = VELOCITY.z * 0.1;

Este código proporciona el siguiente comportamiento:

../../../_images/scene.gif

Usando un ParticlesMaterial puedes hacer que el comportamiento de los peces sea tan simple o complejo como quieras. En este tutorial sólo establecemos la Velocidad, pero en tus propios shaders también puedes establecer el COLOR, la rotación, la escala (a través de TRANSFORM). Por favor, consulta la Particles Shader Reference para más información sobre los shaders de partículas.