Con este tutorial vamos a construir un proyector holográfico utilizando el sistema de partículas Niagara de Unreal Engine 4. Una manera sencilla de hacer un renderizado dinámico de mallas utilizando partículas
La entrada para el holograma
Nuestro primer paso será definir la entrada para el sistema holográfico. Para este ejemplo vamos a utilizar una textura de un mapa de alturas un poco especial. La textura será generada dinámicamente utilizando un objeto SceneCapture2D.
El SceneCapture2D es como una cámara que puede colocarse en un nivel para obtener una vista desde arriba del objeto a renderizar. El resultado del renderizado se guardará en un objeto RenderTarget. Necesitaremos crear este objeto desde el menú contextual del explorador de contenido. Si después abrimos el objeto vemos que se pueden establecer algunas opciones de la textura, como pueden ser las dimensiones, para este ejemplo vamos a utilizar una textura de 512×512.
Ahora tendremos que seleccionar nuestro objeto SceneCapture2D y poner el anterior RenderTarget como su Texture Target.
Tenemos que establecer la fuente de captura (Capture Source) a SceneColor (HDR) in RGB, SceneDepth in A. Esto es muy importante porque así podemos guardar el color del objeto renderizado en las capas RGB y la distancia de cada pixel a la cámara en la capa Alpha. Esta información será utilizada luego en el sistema de partículas para establecer la altura de cada partícula en el holograma.
El sistema de partículas
Para hacer la parte del holograma vamos a utilizar un Niagara Emitter. El Niagara emitter es el generador de partículas pero no puede ser utilizado directamente en el nivel, debe estar dentro de un Niagara System. El Niagara system es el sistema de partículas, pero no genera partículas, es un contenedor de Niagara emitters (múltiples emisores pueden ser añadidos al mismo sistema para conseguir efectos más complejos), y además puede ser posicionado dentro de la escena del nivel.
El emisor que vemos dentro del sistema es una instancia del emisor original, por lo que podemos ajustar los valores del propio emisor o añadirle módulos de manera local desde Niagara system, manteniendo el emisor original sin modificar en el objeto Niagara Emitter original.
El holograma
En nuestro holograma las partículas comenzarán en un anillo exterior, su posición de spawn, y viajaran al centro para dibujar el perfil del objeto renderizado, su posicion de destino.
Ahora podemos continuar con la creación del Niagara Emitter. Utilizando el menu contextual del explorador de contenido podemos crear un emisor Niagara vacio seleccionando la plantilla Empty, y le asignamos el nombre NE_Hologram.
Si abrimos la clase NE_Hologram que acabamos de crear podemos encontrar el nodo de configuración del emisor. Podemos ver diferentes grupos que incluyen multiples módulos. Más módules pueden ser añadidos utilizando el icono + que se encuentra a la derecha del nombre de cada grupo.
En el grupo Emitter Settings podemos encontrar el módulo Emitter Properties, si lo seleccionamos se nos muestran sus opciones en el panel Selection de la derecha. Para este emisor tenemos que seleccionar GPUCompute Sim como el Sim Target, para poder utilizar la textura de alturas posteriormente, y marcar Fixed Bounds.
Ahora vamos a añadir nuestro primer módulo en el grupo Emitter Update, el cual servirá para controlar la tasa de generación de las particulas, por lo que hacemos click en el boton de añadir módulo y buscamos Spawn Rate. Para nuestro emisor un valor de 2000 será más que suficiente.
Ahora pasamos al grupo Particle Spawn, donde tenemos que editar el módulo Initialize Particle. Vamos a establecer un tiempo de vida de cada partícula algo variable cambiando el Lifetime Mode a Random y reducir un poco el tamaño de las partículas con Sprite Size Mode a Uniform y un tamaño de sprite de 3 unidades.
El siguiente módulo que vamos a añadir a este grupo servirá para situar las partículas en su generación en un anillo que delimitará el borde del holograma, hacemos click en el botón de añadir módulo y buscamos Cylinder Location. Como nuestra plataforma es un panel con escala 1 el tamaño de la plataforma es de 1000 unidades, por lo tanto el cilindro deberá tener un radio de 500 unidades. Cambiamos también la altura del cilindro a 10 unidades para tener las partículas un poco más juntas.
Después de esto expandimos la sección utilizando la flecha blanca bajo la opción de Offset y marcamos Surface Only Band Thickness, para limitar la generación de las partículas a la superficie del cilindro, y luego desactivamos Use Endcaps In Surface Only mode eliminar las tapas de la superficie.
Con esto hemos terminado de definir la posición inicial de las partículas. Es hora de ponerse con la parte más complicada.
Vamos a trabajar utilizando una textura y cada partícula va a representar una posición de esta textura, por ello vamos a crear un parámetro en el grupo Particle Spawn para establecer la posición de la partícula dentro de textura, podemos llamarla coordenadas UV de la partícula. Cuando la partícula se genera vamos a generar también una coordenada aleatoria U y otra V para conectar la partícula con una posición de la textura. Para hacer esto empezamos añadiendo un parámetro Vector 2D al grupo Particle Spawn, como si de un módulo se tratara.
Después le cambiamos el nombre a UV y su valor a Random Range Vector 2D, como va a representar una coordenada UV de la textura sus valores deben generarse entre (0,0) y (1,1).
Y ahora ya podemos ponernos con el último grupo, el Particle Update. El primer módulo que añadimos va a ser para añadir la textura (Sample Texture). Tendremos que poner nuestro objeto render target como textura y como coordenadas UV el parámetro que hemos añadido anteriormente.
El siguiente módulo que necesitamos es Recreate Camera Projection. Depth Value debemos cambiarlo a Make Float from Linear Color, LinearColor a Output.SampleTexture.SampledColor (para que coja los valores de nuestra textura) y Channel a A, queremos extraer los datos del canal Alpha para definir la posición final de las partículas
El valor de Projection Space UV Location lo tenemos que enlazar con nuestro parámetro Particles.UV, y desactivamos Write to Instrinsic Value.
Ajustamos los vectores de la sección Tranform para orientar el resultado y obtener una proyección desde arriba.
Uno de los últimos módulos que añadimos a este grupo es un nuevo parámetro que sobrescribe el parámetro que controla la posición de la partícula. Para ello seleccionamos el parámetro existente Particles.Position cuando creamos el nuevo parámetro.
El valor de este parámetro será Output.RecreateCameraProjection.Position, de momento.
Ahora ya podríamos ver el holograma proyectado, pero está desplazado de la posición en la que está el sistema. Es normal, estamos utilizando al distancia a la cámara del SceneCapture que se encuentra a 1000 unidades por encima, por lo que al bajar el punto de origen de la proyección a altura cero el holograma resultante se encuentra a altura -1000.
Una manera sencilla de arreglar esto es mover el sistema de partículas a la misma altura que el SceneCapture. Pero vamos a utilizar una segunda opción, vamos a crear un Niagara Module Script para ajustar la cámara de nuestro proyector holográfico.
En el explorador de contenido, utilizando su menú, seleccionamos crear un nuevo Niagara Module Script.
Para poder ver el script en la lista de módulos tendremos que cambiar su Library Visibility a Exposed
Ahora nos ponemos con los parámetros de entrada y salida. Utilizando el botón + del nodo Map Get podemos añadir los de entrada, y con el de Map Set los de salida.
La salida de nuestro script es Particles.Position, despues de añadirlo lo renombraremos a ProjectedPosition.
Necesitamos multiples entradas. La primera de ellas es un vector con la Posición original (será el valor de Output.RecreateCameraProjection.Position), un float (OffsetDistance) para indicar la distancia entre el objeto scenecapture y el objeto que está capturando, un vector (OffsetDirection) para controlar la dirección de la distancia anterior.
Vamos a añadir dos parámetros más para controlas el cono de la camára y poder cambiar el tamaño de la malla final, necesitamos el Ángulo (que puede ser el mismo que el usado en la cámara del SceneCapture) y el valor Scale para controlar la magnitud del escalado en unidades.
En la primera parte del script vamos a arreglar el desplazamiento de la cámara para poner la malla del holograma en la misma altura que sistema de partículas, solo tendremos que restar la distancia de a la cámara a la posición.
En la segunda parte aplicamos la escala.
Ahora en el emisor de partículas podemos añadir este script como otro módulo cualquiera en el grupo Particle Update, este módulo hay que ponerlo antes que el parámetro Position que ya teníamos para poder utilizar su valor de salida en este parámetro.
Después de esto podemos ajustar los parámetros de entrada del script, el ángulo será el mismo que la cámara del SceneCapture, la dirección de desplazamiento será la que nos de una proyección desde arriba. Su distancia será un poco mayor que la altura del SceneCapture, así el holograma aparecerá un poco elevado del anillo inicial y la plataforma del holograma. Como nuestro anillo tiene un diámetro de 1000 unidades tenemos que escalar el holograma para que las esquinas queden dentro del anillo, un valor de 800 estará bien. La posición original será en valor de Output.RecreateCameraProjection.Position.
Ahora tenemos que reeditar el módulo que sobrescribía el Particles.Position para que utilice la posición proyectada del script.
Cambiamos el valor del parámetro a Smooth Lerp Over Time Vector. Ahora ponemos el parámetro Particles.Position como Smooth Value y el Particles.ProjectedPosition como Target Value. Vamos a hacer una interpolación lineal con el tiempo entre estas dos posiciones. La partícula viajará desde el punto de generación en el anillo exterior hasta su posición en la superficie del holograma, su velocidad estará controlada por la curva de este módulo. Al principio y al final queremos ralentizar su movimiento para apreciar visualmente el anillo y el holograma final.
El último paso es crear el Niagara System para el emisor. Podemos hacer click derecho sobre el emisor en el explorador de contenido y Create Niagara System. Este sistema de partículas ya puede ser colocado dentro del nivel.
Como dijimos al principio de la sección, desde el blueprint del sistema podemos ver y configurar los valores del emisor de partículas si quisiéramos hacer cambios específicos para este sistema.
Con esto hemos terminado nuestro proyector holográfico dinámico. Para cambiar el holograma solo tendremos que reemplazar el objeto que está enfrente del SceneCapture por otro, pero debemos tener en cuenta que estamos utilizando una vista desde la parte superior, por lo que los huecos del objeto tapados por la parte superior no aparecerán en el holograma, solo tenemos guardada una altura por cada pixel.
Una manera de arreglar esto podría ser tener más objetos de SceneCapture desde diferentes ejes y combinar los resultados de cada uno en un holograma único ajustando los vectores de orientación.
Tutorial files
Te puede interesar:
Ayudanos con este blog!
El último año he estado dedicando cada vez más tiempo a la creación de tutoriales, en su mayoria sobre desarrollo de videojuegos. Si crees que estos posts te han ayudado de alguna manera o incluso inspirado, por favor considera ayudarnos a mantener este blog con alguna de estas opciones. Gracias por hacerlo posible!