Dragones y Niagaras

En este tutorial vamos a recrear el efecto del dragón del siguiente video:

Usaremos materiales y el nuevo sistema de partículas de UE4: Niagara.

Puedes descargar el proyecto completo en el siguiente enlace (exclusivo para miembros). También hay programado un livestream para hacer el efecto en directo.

Setup de la escena

Vamos a empezar con un proyecto vacío. Llama al proyecto DragonWorkshop.

Descarga los siguientes assets que incluyen la geometría del dragon y el suelo:

https://drive.google.com/open?id=1a3YW-NAzq4-hTwyY3lBkjAaIMXejrigg

Es buena idea tener organizado el proyecto:

  1. Crea una carpeta en el Content Browser. Llámala Dragon.
  2. Crea una subcarpeta dentro de Dragon y llámala Models.
  3. Crea una subcarpeta dentro de Dragon y llámala Maps.
  4. Pulsa el botón Import para importar dentro de la carpeta Models los tres assets que has descargado.

Aquí los settings para importar:

Settings para importar los assets

Nota como he desactivado generar colisiones y crear nuevos materiales. Las colisiones no la usaremos y vamos a crear manualmente los materiales.

Por último crea un nuevo nivel vacío: File > New Level > Empty Level.

Guarda el nivel (Ctrl+S) en la carpeta Dragon/Maps y llámalo MainMap.

Arrastra el asset SM_Backdrop y SM_Dragon, ambos en la posición (0, 0, 0).

Colocar meshes en la escena

En este proyecto no necesitamos sombras de alta calidad ni tampoco GI.

¿No sabes que es GI? En este proyecto no lo usaremos pero si sientes curiosidad aquí un post sobre iluminación.

Así que podemos obviar el bakeo de luces y utilizar luces y sombras dinámicas.

Primero, selecciona el actor SM_Backdrop y SM_Dragon y establece su Mobility en Movable.

Lo siguiente es el setup de luces.

Voy a usar una luz principal (key light) en la cabeza, una luz de soporte (support light) en la cola y una luz de contorno en la parte posterior (rim light).

También usaremos una luz ambiental para suavizar sombras y como iluminación global.

En concreto, coloca las siguientes luces (todas en Movable):

  • una luz Point Light en la posición (-60, 70, 140) con intensidad 2.0 cd, renómbrala a Key_PointLight.
  • una luz Point Light en la posición (260, 170, 190) con intensidad 8.0 cd, renómbrala a Support_PointLight.
  • una luz Directional Light con rotación (12, -40, 90) e intensidad 10 lux, renómbrala a Rim_DirectionalLight.
  • por último añade un SkyLight para tener una luz ambiental y suavizar las sombras.  Indica en Source Type que quieres un Specified Cubemap, y en Cubemap busca y slecciona GrayLightTextureCube (deberas indicar Show Engine Content para ver la textura). Baja la intensidad a 0.75 cd/m2.

El resultado del setup de luces:

Setup de luces

Vamos con la primera parte realmente interesante, los materiales.

Material wireframe

Vamos a crear el siguiente material:

Material wireframe

Dentro de la carpeta Models, pulsa el botón Add New y selecciona Material.

Renombra el material a M_Dragon_Wireframe. Haz doble click para entrar en el editor de materiales.

Nuestro material es 100% emisivo, esto es, no tiene propiedades físicas como el roughness, metallic, normal, etc., podemos advertir al engine de esta peculiaridad para que se ahorre multitud de cálculos referentes a la luz.

Para indicarle al engine que nuestro material es 100% emisivo, en el panel de detalles del material, selecciona Unlit como valor para la propiedad Shading Model:

Seleccionar Unlit

También nos gustaría ver una preview del material aplicado al modelo del dragón, en vez de usar un cubo como previa. Para ello, selecciona el asset SM_Dragon_Wireframe en el content browser y pulsa el botón en forma de tetera en la vista previa:

Vista preview del modelo

Un material en UE4 es un shader. Un shader dibuja fragmentos (pixeles). Los fragmentos son extraidos en una etapa de la GPU llamada Rasterización. Podemos indicarle que en vez de extraer fragmentos completos, pinte únicamente las aristas del mesh.

Busca el atributo Wireframe en el panel de detalles del material y márcalo. Usa el buscador para mayor comodidad.

Crea un color manteniendo pulsada la tecla 3 del teclado y haciendo click en cualquier area vacía del editor de materiales. Cambia el color a (0, 18, 20). Conecta el color al canal emisivo.

Color emisivo

Vamos ahora con la animación.

Para animar vértices debes conectar el desplazamiento de dicho vértice en World Position Offset.

Por ejemplo, prueba con crear un vector (de nuevo, manteniendo la tecla 3 y haciendo click). Setea el vector a (0, 0, 200) y conéctalo a World Position Offset.

Desplazamiento de vértices

¡Haz desplazado cada uno de los vértices 200 unidades en el eje Z!

Vamos a hacer que en vez de desplazarse en un solo eje, se desplace siguiendo la normal del vértice.

Desplazamiento siguiendo la normal

Prueba a cambiar el factor de 1.5 a otro para medir el efecto.

Para hacerlo más interesante, en vez de que todos los vértices se desplacen la misma cantidad vamos a usar un nodo de ruido que module el desplazamiento:

Con un módulo de ruido

Prueba a cambiar algunos parámetro del ruido.

Si tienes curiosidad de que significa cada parámetro a fondo, incluso implementar tus propias funciones de ruido tienes más info aquí.

Vamos a animar el desplazamiento.

El nodo de ruido tiene como parámetro una posición. Por defecto está usando la posición del pixel. En concreto, está usando por defecto la posición que devuelve el nodo Absolute World Position (aunque no veas éste nodo conectado al pin Position).

Vamos a tomar la posición que devuelve Absolute World Position, la vamos a descomponer en sus tres componentes X, Y, Z y vamos a animar la Z añadiéndole el tiempo transcurrido:

Ruido con animación

Y con esto tenemos el ruido animado:

Wireframe animado

Backdrop y wireframe en escena

Vamos a crear un nuevo material para el backdrop.

Crea un nuevo material llamado M_Backdrop del siguiente modo:

Material para el backdrop

Las texturas usadas son Grid y Grid_N, ambas en /Engine/EngineMaterials, necesitaras activar Show Engine Contents para verlas.

El nodo TexCoord está seteado con un tiling de 10x10.

En el World Outliner de la escena, seleciona SM_Backdrop y setea el material a M_Backdrop recién creado.

Coloca en la escena el asset SM_Dragon_Wireframe y setea su material a M_Wireframe.

Escena con backdrop y wireframe

Material base del Dragon

Vamos a hacer el material base del Dragon:

Material del dragon

Nuestro material intenta aproximar la piel del dragón. La piel es un tipo de material especial llamado subsurface. Como su propio nombre indica, los materiales subsurface son aquellos que poseen unas propiedades diferentes "por debajo" de su superficie.

Estas propiedades diferentes se hacen notorias cuando el material está a contraluz.

Por ejemplo, en la piel tienes una serie de propiedades en la "superficie" mientras que "por debajo" hay otras, en concreto "sangre". Si pones según que partes del cuerpo (sobre todo las partes cartilaginosas como la oreja) a contraluz, verás el efecto subsurface del que hablamos.

Estos materiales son costosos por lo que, por defecto, no están activados. Para activarlos ve al panel de detalles del material y selecciona Subsurface en Shading Model.

Activar subsurface

Notarás como en el material se han activado dos pines extras: Opacity y Subsurface Color.

El canal Opacity sirve para modular la intensidad del efecto. Cuanto menos Opacity más se notará el Subsurface Color.

Subsurface color

Dónde el nodo Noise está configurado tal que así (te invito a probar otros parámetros):

Settings para el nodo Noise conectado a Opacity

Vamos a usar otro nodo Noise para hacer las líneas emisivas. Recuerda que siempre puedes pulsar con el botón derecho del ratón sobre cualquier nodo y hacer click en "Start Previewing Node" para ver qué está haciendo.

Nodo Noise para el emisivo

Si te fijas en la imagen, tenemos un ruido que va de 0 (negro) a 1 (blanco). Nosotros solo queremos los valores inferiores a cierto umbral y con eso conseguimos líneas bien definidas:

Líneas bien definidas usando un IF

Si te fijas en la imagen estamos diciendo si el ruido es inferior a 0.02 entonces el nodo IF devuelve 1 (blanco), si no devuelve 0 (negro).

Ahora podemos multiplicar esta máscara por un color y conectarlo al emisivo.

Conectado al emisivo

Vuelve a la escena y asigna este material a SM_Dragon.

Mezclar ambos materiales

Ahora nos queda hacer la animación final.

Parte superior con Wireframe, parte inferior con material Base.

Definimos una variable escalar que actúa como umbral. El material base pintará todos los pixeles cuya posición Z sea inferior al umbral. El material wireframe pintará los píxeles cuya posición Z sea superior al umbral. Lo que no se pinte se descarta.

Para poder descartar píxeles (y no pintarlos) hay que indicarlo en el panel de detalles del material.

Ve al material M_Dragon y M_Dragon_Wireframe y setea Blend Mode a Masked.

Setear Masked como Blend Mode

Con esto activarás un nuevo pin en el material: Opacity Mask. Si el valor es 0 se descarta el pixel.

Prueba a colocar la siguiente lógica:

Lógica básica para Opacity Mask

Esta lógica dice que si la posición Z del pixel es superior a 70 entonces conecta 0 a Opacity Mask (es decir, descarta el pixel) en caso contrario conecta 1 (pinta el pixel).

Si vas al material M_Dragon_Wireframe y haces la lógica inversa:

Opacity Mask para M_Dragon_Wireframe

Obtendrás el material partido justo en la altura 70 (prueba a cambiar el valor):

Material partido

Si las caras posteriores no son visibles marca Two Sided en el panel de detalles del material M_Dragon.

El siguiente paso lógico sería controlar el valor de corte desde fuera. Pero antes de eso vamos a normalizarlo. Es decir, en vez de hablar de "cortar" por la altura 70, 50, 40 o la que sea, mejor hablar en porcentajes: 0.5 es cortar por la mitad, 0.0 es completamente wireframe y 1.0 es completamente piel.

Para ello, cambiemos la lógica anterior por:

Normalizar la altura

Al dividir la componente Z por la altura (en este caso, la altura es de 134) obtenemos 1 cuando Z es 134 (la altura del dragon), 0.5 cuando Z es 67 (justo la mitad del dragon), etc., hemos normalizado el valor.

Recuerda actualizar ámbos materiales.

Franja central

Vamos a dibujar la franja central que hace justo en el corte.

¿Cómo detectamos que pixeles forman la franja central? Es decir, ¿cómo construimos una máscara tal que así?

Máscara indicando la franja

Si somos capaces de construir esta máscara, bastaría con multiplicarla por algún color y añadirla al emisivo.

Si te fijas, ya hemos construido una máscara parecida, ¡la de Opacity Mask!

Opacity Mask pintaba de negro los pixeles cuya posición era superior a un umbral y de blanco los inferiores. Aquí queremos justo lo contrario, de negro los inferiores y de blanco los superiores.

Además, no queremos usar justo el umbral de corte, si no que es ligeramente inferior al umbral de corte, ¿cuánto de inferior? Justo el ancho de la franja.

La máscara quedaría así:

Cálculo de la máscara de la franja

¿Cómo lo combinamos con el emisivo?

Tenemos una máscara (negra-blanca) original del emisivo y otra máscara (negra-blanca) indicando la franja. La manera de combinarla es usando el nodo Max. De esta forma, cuando cualquiera de las dos máscaras sea blanca, el resultado será blanco.

Combinar emisivo original con la franja

Resultado:

Emisivo con la franja añadida

Animación

Vamos a sustituir el valor umbral de corte que estamos usando por un parámetro.

Primeramente crea en la carpeta Models un nuevo asset de tipo Material Parameter Collection.

Nuevo material parameter collection

Llámalo MC_Dragon_Params, añade un nuevo escalar, llámalo HeighThreshold y asígnale un valor por defecto, por ejemplo 0.4.

Párametro HeightThreshold

Ahora sustituye el valor fijo que usamos en los materiales por una referencia a dicho parámetro.

Utiliza el nodo CollectionParameter para referenciarlo.

Uso de CollectionParameter dentro del material

Recuerda usarlo en ambos materiales: M_Dragon y M_Dragon_Wireframe.

Fíjate como a partir de ahora al usar el valor declarado en MC_Dragon_Params  afecta a ambos materiales:

Usando el parámetro HeightThreshold desde MC_Dragon_Params

Para animarlo automáticamente podemos proceder de muchas formas. Desde usar sequencer para cinemáticas a controlarlo vía BP.

Vamos a hacerlo por BP. Abre el BP del mapa:

Open Level Blueprint

Y en el nodo BeginPlay añade un nodo Timeline:

Nodo Timeline

Doble click sobre el nodo Timeline para añadir curvas.

Añade una curva de tipo escalar (Add Float Track), llámala Threshold que tenga la siguiente forma aproximada (con el segundo botón del ratón añades keys):

Timeline con Float Track

Vuelve al Event Graph. Ahora tendrás un pin de salida en el nodo Timeline justamente con el valor del Threshold.

Añade un nodo Set Scalar Parameter Value para cambiar el valor de MC_Dragon_Params y actualizalo con el valor de Timeline:

Set Scalar Parameter Value

Si compilas, guardas y simulas la escena (el acceso rápido para simular la escena es Alt+S) ¡podrás ver el dragón animado!

Dragon animado

Niagara is coming

Nos tocaría hacer la segunda parte del efecto, esto es, la desintegración.

Para ello vamos a usar el nuevo sistema de partículas que trae UE4: Niagara.

Si necesitas una introducción a Niagara en este post tienes una introducción tocando todos los conceptos claves.

Crea una nueva carpeta dentro de la carpeta Dragon, llámala VFX.

Crea un nuevo asset de tipo NiagaraSystem:

New NiagaraSystem

Llámalo FX_Dust. Selecciona que quieres crear el efecto vacío (empezamos desde 0).

Crea otro NiagaraSystem y llámalo FX_Dragon.

Vamos a empezar con el efecto FX_Dust. Este efecto simula polvo en suspensión aunque con mucha licencia artística.

Polvo en suspensión

Abre el editor de Niagara haciendo doble click sobre FX_Dust.

Lo primero que vemos es que no tenemos ningún emisor de partículas:

FX_Dust vacío

Vamos a añadir uno. Vuelve al Content Browser, y crea un Niagara Emitter. Utiliza la plantilla vacía, vamos a crearlo de 0. Llámalo FX_Dust_Emitter.

Vamos a editar el emisor antes de agregarlo al sistema FX_Dust.

Haz doble click sobre el nuevo emisor FX_Dust_Emitter para abrir el editor:

FX_Dust_Emitter vacío

Vemos como tenemos los módulos básicos ya añadidos, en concreto:

  1. En la sección Particle Spawn, cuando una partícula es spawneada por primera vez, tenemos el módulo Initialize Particle que inicializa algunos propiedades básicas de la partícula como su Lifetime,
  2. En la sección Particle Update tenemos el módulo Particle State que se encarga de actualizar el atributo Age de la partícula (cuánto tiempo ha transcurrido desde que se spawneó) y también elimina la partícula una vez su Age es mayor que su Lifetime.
  3. En la sección Render tenemos el módulo Sprite Renderer. Podríamos tener otros como Mesh Renderer o Ribbon, pero en este caso para simular polvo nos vale con Sprite Renderer.

¿Qué nos falta? ¡No tenemos partículas! Nos falta bajo Emitter Update algún módulo que spawnée partículas. También nos falta bajo Particle Spawn un módulo que indique la posición inicial de la partícula.

En nuestro caso dado que será polvo en suspensión vamos a spawnear partículas en el interior de una caja.

Añade el módulo Spawn Rate para spawnear a un ritmo constante partículas:

Añadir módulo Spawn Rate

Setea un valor para la propiedad SpawnRate del módulo recién añadido, por ejemplo 300:

SpawnRate a 300

Eso indicará al módulo que emita a una tasa de 300 partículas por segundo.

Todas las partículas se colocan en la posición (0, 0, 0). Vamos a cambiar eso. Añade el módulo Box Location, esta vez bajo Particle Spawn.

Vamos a aumentar la zona de spawneo. En las propiedades de Box Location actualiza el valor Box Size a (400, 400, 300).

Box Location

En la preview podemos ver como las partículas se spawnean y posicionan en una caja centrada en el origen.

Nos gustaría que las partículas no se posicionaran por debajo del suelo. Es decir, subir el offset de la caja. Como tiene altura 300 podemos subir la caja 150 unidades hacía arriba y de este modo no posicionará partículas por debajo de 0:

BoxOffset a 150

Para nuestro efecto de suspensión de polvo, las partículas mueren demasiado rápido.

Selecciona el módulo Initialize Particle y aumenta el Lifetime a 10.

Para el color de la partícula vamos a seleccionar entre dos valores aleatorios.

¿Cómo lo hacemos? En el módulo solo nos deja poner un color y un alfa para la transparencia.

Aquí es dónde entra parte del potencial de Niagara. Vamos a cambiar la entrada.

¿Cómo? Primero "rompemos" el color en un vector (RGB) y un escalar (Alpha). Luego indicamos que ese vector RGB lo vamos a seleccionar entre dos valores usando un bool (true o false). Y por último nos vamos al bool y decimos que lo vamos a elegir aleatoriamente. ¿Difícil? ¡En absoluto! Fíjate:

Setear el color aleatorio entre dos colores

¡Ya tenemos las partículas a dos colores!

En mi caso he puesto los colores en: Rojo (1.0, 0.0, 0.0) y Amarillo (1.0, 0.5, 0.01).

Entre dos colores aleatorios

Tanto el nacimiento como la muerte de la partícula es demasiado brusca. Cuando spawnea aparece de repente y cuando muere también desparece de repente.

Vamos a arreglar esto usando el alpha del color.

Bajo el epígrafe Particle Update vamos a actualizar el color de la partícula según el tiempo que le quede de vida. Añade el módulo Scale Color.

Usa la flechita al igual que antes para modificar el parámetro Alpha, añade una curva tal que así:

Curva para escalar el alpha

Si quieres puedes usar el siguiente botón para editar la curva en un editor de curvas, más cómodo:

Editor de curvas en Niagara

Ahora vamos a añadir algo de velocidad a las partículas.

En este caso será una velocidad inicial (en principio no queremos cambios de velocidad para este efecto) así que bajo el epígrafe ParticleSpawn añade el módulo Add Velocity. Pulsa en la flechita y selecciona Uniform Ranged Vector para obtener una velocidad aleatoria:

Add Velocity

Volvamos a FX_Dust y añade el emisor haciendo click con el botón derecho sobre una zona libre y Add Emitter.

Add Emitter

Compila y guarda.

Arrastra el asset FX_Dust desde el Content Browser a la escena a ver qué tal queda.

FX_Dust en acción

Quizás nos hayamos pasado con el número de partículas. Prueba a cambiar en el módulo SpawnRate de 300 a 50. Parece más razonable.

Por último voy a añadir un módulo Curl Noise Force en Particle Update para cambiar la velocidad de las partículas siguiendo un ruido.

Curl Noise

Yo dejo el efecto aquí pero tu puedes jugar con la escala de las partículas para que vayan cambiando a lo largo de su vida útil, ajustar la velocidad, etc.,

Dust con Curl Noise

Desintegración

Vamos a hacer la parte de desintegración:

Lo primero que debemos notar es que en este caso las partículas no usan el material por defecto, si no que están usando el material de la piel del dragón.

Duplica el material de la piel del dragón y muévelo a la carpeta VFX, renómbralo a M_Dragon_Particle:

Duplicar M_Dragon a M_Dragon_Particle

Edita el material M_Dragon_Particle, en concreto elimina todos los nodos referentes al Opacity Mask:

M_Dragon_Particle sin los nodos referentes al Opacity Mask

El Opacity Mask (descartar o no la partícula) lo vamos a controlar nosotros a través del canal Alpha del color de la partícula.

ParticleColor.A en el OpacityMask

Vamos a proceder como hicimos con FX_Dust, crea un nuevo emisor (plantilla vacía) y llámado FX_Dragon_Emitter.

Bien, lo primero, al igual que con FX_Dust_Emitter, es indicar cuantas partículas queremos emitir.

En este caso, en cambio, no queremos emitir continuamente partículas. En vez de eso, vamos a emitir una cantidad considerable de partículas al principio y nada más.

En vez del módulo SpawnRate, que emitía partículas a un ritmo por segundo, queremos el módulo SpawnBurstInstantaneous.

Spawn Burst Instantaneous

El siguiente punto es colocar las partículas.

En el efecto anterior las colocamos en una caja (BoxLocation), ¿y en este efecto? Debemos colocarlas sobre la superficie del mesh.

Para ello, antes tenemos que indicar a Niagara que obtenga (cargue en memoria) información relativa al mesh (posición de sus vértices, normales, etc.,).

En concreto, cuando spawnea la partícula podemos usar el módulo SampleStaticMesh.

Sample Static Mesh

Este módulo selecciona aleatoriamente un triángulo del mesh y setea nuevas propiedades a la partícula:

Propiedades que setea Sample Static Mesh

Ahora podemos usar un módulo para setear la posición de la partícula a MeshPosition. O mejor aún, tenemos un módulo que ya hace eso, Static Mesh Location.

Static Mesh Location

Este nodo presume de tener los atributos MeshNormal y MeshPosition para funcionar. Precisamente los atributos que hemos conseguido al añadir previamente el módulo Sample Static Mesh.

Partículas sobre el dragón

En resumen, cuando spawneamos una partícula (bajo el epígrafe Particle Spawn) el módulo Sample Static Mesh elige un triángulo aleatorio del mesh y crea un conjunto de nuevos atributos; entre ellos MeshNormal y MeshPosition. El módulo Static Mesh Position usa dichos atributos para colocar la partícula en dicha posición.

Hay un problema que problamente te hayas fijado, a medida que se reproduce el efecto ¡el contador de partículas sube! Sube de 150.000 en 150.000.

¿Por qué? ¿No hemos indicado acaso con el módulo Spawn Burst Instantaneous que solo spawnee 150.000 al principio y nada más?

Esto es así porque es el efecto (el emisor) se está reproduciendo en bucle. Si seleccionas bajo Emitter Update el módulo Emitter State:

Emitter State

Puedes comprobar como el emisor está configurado para estar en bucle infinito (Loop Behavior = Infinite) y la duración del bucle es de 1 segundo.

Vamos a cambiar eso, lo que nosotros queremos es que solo haya un bucle (es decir, sin repetición) y que dure infinito:

Solo un bucle

¿Recuerdas el material que hicimos para la partícula? Es hora de asignarlo. Ve al módulo de render: Sprite Renderer y cambia el material por el de M_Dragon_Particle.

Cambiar el material a M_Dragon_Particle

Las partículas nos han quedado un poco grande. Selecciona el módulo Initialize Particle y cambie el tamaño a 2x2.

Tamaño de las partículos. Sprite Size a 2x2

Cambia también el Lifetime a 60 segundos.

Toca darle el efecto de desintegración. Añade simplemente un módulo Curl Noise Force para que las partículas "exploten" siguiendo un ruido. Añade también un nodo Drag para que las partículas ofrezcan alguna resistencia al movimiento.

Curl Noise y Drag

Desintegración controlada

No queremos que todo el mesh se desintegre a la vez. Se va desintegrando poco a poco de arriba a abajo.

Vamos a proceder de la misma forma que hicimos en el material con Opacity Mask.

Lo primero, vamos a crear un atributo en la partícula que almacene la posición Z de la partícula dividida por la altura del dragón.

Es decir, este parámetro, que llamaremos NormalizedZ, es 1 cuando la partícula está en la cabeza y 0 cuando está en el pie. Variando de 1 a 0 a medida que vamos bajando por el modelo.

Añade bajo el epígrafe ParticleSpawn el módulo "Set new or existing parameter directly".

Set Parameters

Añade un nuevo parámetro de tipo float, llámalo NormalizedZ.

Utiliza la flechita para calcular dinámicamente el parámetro, en concreto, NormalizedZ es igual a dividir la coordenada Z de la partícula por la altura (137) del mesh:

Set Parameter: NormalizedZ

El cálculo de NormalizedZ se hace cuando la partícula es spawneada.

Vamos a crear ahora un nuevo parámetro de tipo bool. Si es true es que la partícula debe "moverse" o explotar. Si es false la partícula debe estar estática. Llamaremos a este parámetro Exploded.

¿De qué va a depender Exploded? El valor de Exploded dependerá de si NormalizedZ es superior a un determinado umbral. Al igual que hicimos con Opacity Mask. Por ejemplo, si ponemos este umbral a 0.5 significara que la mitad de las partículas hacia arriba tendrán Exploded = true y la otra mitad hacia abajo Exploded = false.

Añade un nuevo módulo  "Set new or existing parameter directly" bajo Particle Update añade un nuevo parámetro de tipo bool, llámalo Exploded y cálculalo tal que así:

Set Exploded

¡Ojo! Que el valor de 0.5 es el umbral. Ahora lo tenemos como un valor fijo, pronto lo cambiaremos por un parámetro configurable. Vamos a dejarlo así solo para probar que todo funciona bien.

Si pulsas en Play para ver el efecto, obviamente no notarás ninguna diferencia ya que estos valores (Exploded y NormalizedZ) no están influyendo en nada gráficamente, simplemente se están calculando.

Para ver el cálculo, puedes usar la pestaña Attribute Spreadsheet. Puedes abrirla desde el menú Window.

Si pulsas sobre el botón Capture en algún fotograma capturarás el valor de las propiedades de cada partícula. Incluso filtrar atributos:

Attribute Spreadsheet

Fíjate como para cada partícula con NormalizedZ superior a 0.5 su Exploded es true (distinto de 0). ¡Justo lo que queremos!.

Ahora toca usar el atributo Exploded para que haga algo.

Selecciona el módulo Curl Noise responsable de la "explosión".

Modifica la fuerza para que tenga en cuenta la variable Exploded del siguiente modo:

Curl Noise en función del parámetro Exploded

Es decir, Noise Strength es calculado en función de un bool; cuando dicho bool es true la fuerza es 10 (la que hemos indicado) y cuando es falso es 0 (no aplica ninguna fuerza). Dicho bool está controlado por Exploded.

Si le das Play, dado que el umbral lo dejamos a 0.5 tenemos el siguiente efecto:

Usando Exploded para controlar la explosión

Fíjate como solo la mitad superior "explota". Puedes aumentar la fuerza de explosión para hacerla más exagerada. Prueba con cambiar el umbral a otros valores.

Por último vamos a hacer que las partículas por debajo del umbral, es decir, las partículas que no han explotado (Exploded = false) no se vean.

¿Recuerdas que añadimos el nodo ParticleColor al material M_Dragon_Particle? Dicho nodo tenía conectado el canal alpha a Opacity Mask.

Bastaría con que la partícula seteara su alpha en función de Exploded.

Color Alpha en función de Exlpoded

Y ya tenemos el efecto de desintegración listo.

Abre el sistema de partículas VFX_Dragon y añade el emisor que acabamos de editar VFX_Dragon_Emitter. Compila y guarda.

Vamos a integrarlo en la escena.

Todo junto

Vamos a hacer el efecto final incluyendo el sistema de partículas de desintegración.

Abre el BP del nivel, lo dejamos tal que así:

Set Scalar Parameter Value

Amplíalo para que cuando finalice el timeline vuelva hacía atrás, para ello duplica el nodo Timeline y usa el pin Reverse:

Timeline Reverse

Lo que queremos es que cuando finalice el primer timeline entre en juego el efecto de partículas. Vamos a hacerlo:

Spawn System at Location

Si simulas la escena verás algo así:

Spawnear VFX_Dragon con el umbral al 0.5

Dos problemas. El primero el wireframe sigue estando, deberíamos eliminarlo. Y segundo, el sistema de partículas tiene fijo el umbral a 0.5

Tenemos que modificar ese umbral fijo del 0.5 en VFX_Dragon por un parámetro que, al igual que con MC_Dragon_Params, modifiquemos en BP.

Edita de nuevo VFX_Dragon_Emitter. Fíjate como en la parte superior de la lista de parámetros tenemos la categoría User Exposed. Añade un parámetro de tipo float llamado ZThreshold.

Parámetro ZThreshold en User Exposed

Ahora sustituye el umbral fijo que teníamos en el módulo "Set (PARTICLES) Exploded" bajo ParticleUpdate por el nuevo parámetro:

Cálculo de Exploded usando ZThreshold

Compila, Apply y guarda.

Si abres VFX_Dragon verás como se ha actualizado y podrás ver el nuevo parámetro expuesto.

Ahora desde BP vamos a actualizar el parámetro y también eliminar el actor SM_Dragon_Wireframe:

DestroyActor de SM_Dragon_Wireframe y SetFloatParameter de NiagaraSystem

Quedando como resultado:

Puedes jugar con SpriteSize y Curl Noise Strength.

Jugando con estos parámetros puedes conseguir efectos muy diferentes:

Explosión violenta

Otro ejemplo podría ser añadir un nuevo parámetro, TimeElapsedAfterExploded y actualizarlo una vez la partícula haya explotado:

Actualizar TimeElapsedAfterExploded una vez haya explotado

Y usamos un módulo Scale Sprite Size usando dicho parámetro:

Scale Sprite Size

Dando como resultado:

Puedes descargar el código fuente del proyecto desde aquí.

Jorge Moreno Aguilera

Jorge Moreno Aguilera