Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Shaders
Gamedevelopment

Creando Agua de Caricatura para la Internet: Parte 3

by
Difficulty:AdvancedLength:LongLanguages:
This post is part of a series called Creating Toon Water for the Web.
Creating Toon Water for the Web: Part 2

Spanish (Español) translation by RRGG (you can also view the original English article)

Bienvenidos a esta serie de tres partes sobre la creación de agua toon estilizada en PlayCanvas utilizando sombreadores de vértices. En la Parte 2 cubrimos las líneas de flotabilidad y espuma. En esta parte final, vamos a aplicar la distorsión subacuática como un efecto posterior al proceso.

Efectos de Refracción y Post-Proceso

Nuestro objetivo es comunicar visualmente la refracción de la luz a través del agua. Ya hemos explicado cómo crear este tipo de distorsión en un sombreador de fragmentos en un tutorial previo para una escena 2D. La única diferencia aquí es que tendremos que averiguar qué área de la pantalla está bajo el agua y solo aplicar la distorsión allí.

Post-Procesamiento

En general, un efecto de post-proceso es cualquier cosa que se aplica a toda la escena después de que se representa, como un tinte de color o un efecto de pantalla de CRT antigua. En lugar de renderizar su escena directamente en la pantalla, primero la renderiza en un búfer o textura, y luego la renderiza en la pantalla, pasando por un sombreador personalizado.

En PlayCanvas, puede configurar un efecto de postproceso creando un nuevo guión. Llámalo Refraction.js y copia esta plantilla para comenzar con:

Esto es como una secuencia de comandos normal, pero definimos una clase RefractionPostEffect que se puede aplicar a la cámara. Esto necesita un vértice y un sombreador de fragmentos para renderizar. Los atributos ya están configurados, así que vamos a crear Refraction.frag con este contenido:

Y Refraction.vert con un sombreador de vértices básico:

Ahora adjunte el script Refraction.js a la cámara y asigne los sombreadores a los atributos apropiados. Cuando inicies el juego, deberías ver la escena exactamente como estaba antes. Este es un efecto de publicación en blanco que simplemente vuelve a renderizar la escena. Para verificar que esto funcione, intente darle a la escena un tono rojo.

En Refraction.frag, en lugar de simplemente devolver el color, intente configurar el componente rojo en 1.0, que debería verse como la imagen de abajo.

Scene rendered with a red tint

Sombreador de Distorsión

Necesitamos agregar un uniforme de tiempo para la distorsión animada, así que ve y crea uno en Refraction.js, dentro de este constructor para el efecto de publicación:

Ahora, dentro de esta función de renderización, la pasamos a nuestro sombreador y la incrementamos:

Ahora podemos usar el mismo código de sombreado del tutorial de distorsión de agua, haciendo que nuestro sombreador de fragmentos completo se vea así:

Si todo salió bien, ahora todo debería verse como si estuviera bajo el agua, como se muestra a continuación.

Underwater distortion applied to the whole scene
Reto # 1: Haga que la distorsión solo se aplique a la mitad inferior de la pantalla.

Máscaras de Cámara

Casi estamos allí. Todo lo que tenemos que hacer ahora es aplicar este efecto de distorsión solo en la parte submarina de la pantalla. La manera más directa que he encontrado para hacer esto es volver a renderizar la escena con la superficie del agua representada como un blanco sólido, como se muestra a continuación.

Water surface rendered as a solid white to act as a mask

Esto se representaría en una textura que actuaría como una máscara. Luego, pasaríamos esta textura a nuestro sombreador de refracción, que solo distorsionaría un píxel en la imagen final si el píxel correspondiente en la máscara es blanco.

Agreguemos un atributo booleano en la superficie del agua para saber si se está utilizando como una máscara. Agregue esto a Water.js:

Luego podemos pasarlo al shader con material.setParameter ('isMask', this.isMask); como siempre. Luego, declare en Water.frag y establezca el color en blanco si es verdadero.

Confirme que esto funciona alternar entre "¿Es la máscara?" propiedad en el editor y relanzamiento del juego. Debería verse blanco, como en la imagen anterior.

Ahora, para volver a renderizar la escena, necesitamos una segunda cámara. Crea una nueva cámara en el editor y llámala CameraMask. Duplique también la entidad Water en el editor y llámela WaterMask. Asegúrate de que "¿Es la máscara?" es falso para la entidad Agua pero es cierto para la WaterMask.

Para decirle a la nueva cámara que represente una textura en lugar de la pantalla, cree una nueva secuencia de comandos llamada CameraMask.js y conéctela a la nueva cámara. Creamos un RenderTarget para capturar la salida de esta cámara así:

Ahora, si inicia, verá que esta cámara ya no se está renderizando en la pantalla. Podemos tomar la salida de su objetivo de renderizado en Refraction.js de la siguiente manera:

Tenga en cuenta que paso esta textura de máscara como un argumento para el constructor de efectos posteriores. Necesitamos crear una referencia en nuestro constructor, por lo que se ve así:

Finalmente, en la función de renderización, pase el búfer a nuestro sombreador con:

Ahora para verificar que todo esto funciona, lo dejo como un desafío.

Reto # 2: renderiza uMaskBuffer a la pantalla para confirmar que es la salida de la segunda cámara.

Una cosa a tener en cuenta es que el destino del renderizado está configurado en la inicialización de CameraMask.js, y que debe estar listo cuando se llame a Refraction.js. Si los scripts se ejecutan al revés, obtendrás un error. Para asegurarse de que se ejecutan en el orden correcto, arrastre CameraMask a la parte superior de la lista de entidades en el editor, como se muestra a continuación.

PlayCanvas editor with CameraMask at top of entity list

La segunda cámara siempre debería estar mirando la misma vista que la original, así que hagamos que siempre siga su posición y rotación en la actualización de CameraMask.js:

Y defina CameraToFollow en la inicialización:

Máscaras de Sacrificio

Ambas cámaras están renderizando lo mismo. Queremos que la cámara con máscara represente todo excepto el agua real, y queremos que la cámara real represente todo, excepto el agua de la máscara.

Para hacer esto, podemos usar la máscara de bits de descarte de la cámara. Esto funciona de manera similar a las máscaras de colisión si alguna vez las utilizó. Un objeto será eliminado (no renderizado) si el resultado de un Y a nivel de bit entre su máscara y la máscara de la cámara es 1.

Digamos que Water tendrá el bit 2 configurado, y WaterMask tendrá el bit 3. Entonces la cámara real necesita tener todos los bits configurados a excepción de 3, y la máscara de cámara debe tener todos los bits configurados, excepto 2. Una manera fácil de decir "todos los bits, excepto N" es hacer:

Puede leer más sobre los operadores bitwise aquí.

Para configurar las máscaras de eliminación de imágenes de la cámara, podemos poner esto dentro de la inicialización de CameraMask.js en la parte inferior:

Ahora, en Water.js, establece la máscara de malla de agua en el bit 2 y la versión de máscara en el bit 3:

Ahora, una vista tendrá el agua normal y la otra tendrá el agua blanca sólida. La mitad izquierda de la imagen a continuación es la vista desde la cámara original, y la mitad derecha es desde la cámara con máscara.

Split view of mask camera and original camera

Aplicando la Máscara

¡Un último paso ahora! Sabemos que las áreas bajo el agua están marcadas con píxeles blancos. Solo debemos comprobar si no estamos en un píxel blanco, y si es así, desactivar la distorsión en Refraction.frag:

¡Y eso debería hacerlo!

Una cosa a tener en cuenta es que dado que la textura de la máscara se inicializa en el inicio, si cambia el tamaño de la ventana en el tiempo de ejecución, ya no coincidirá con el tamaño de la pantalla.

Anti-Aliasing

Como paso de limpieza opcional, es posible que haya notado que los bordes de la escena ahora se ven un poco nítidos. Esto se debe a que cuando aplicamos nuestro efecto de publicación, perdimos el anti-aliasing.

Podemos aplicar un anti-alias adicional sobre nuestro efecto como otro efecto de publicación. Afortunadamente, hay uno disponible en la tienda PlayCanvas que podemos usar. Vaya a la página de activos del script, haga clic en el botón de descarga verde grande y elija su proyecto de la lista que aparece. El script aparecerá en la raíz de su ventana de activos como posteffect-fxaa.js. ¡Simplemente adjunte esto a la entidad de la Cámara, y su escena debería verse un poco mejor!

Pensamientos Finales

Si has llegado hasta aquí, ¡date una palmadita en la espalda! Cubrimos muchas técnicas en esta serie. Ahora debería sentirse cómodo con los sombreadores de vértices, renderizando texturas, aplicando efectos de posprocesamiento, eliminando selectivamente objetos, utilizando el búfer de profundidad y trabajando con mezcla y transparencia. A pesar de que estábamos implementando esto en PlayCanvas, estos son todos los conceptos generales de gráficos que encontrarás de alguna forma en cualquier plataforma en la que termines.

Todas estas técnicas también son aplicables a una variedad de otros efectos. Una aplicación particularmente interesante que he encontrado de los sombreadores de vértices es en esta charla sobre el arte de Abzu, donde explican cómo usaron sombreadores de vértices para animar eficientemente a decenas de miles de peces en la pantalla.

¡Ahora también deberías tener un agradable efecto de agua que puedes aplicar a tus juegos! Puede personalizarlo fácilmente ahora que ha reunido cada detalle usted mismo. Todavía hay mucho más que puedes hacer con el agua (ni siquiera he mencionado ningún tipo de reflejo). A continuación hay un par de ideas.

Olas Basadas en Sonido

En lugar de simplemente animar las ondas con una combinación de seno y coseno, puede muestrear una textura de ruido para que las ondas se vean un poco más naturales e impredecibles.

Rutas de Espuma Dinámica

En lugar de líneas de agua completamente estáticas en la superficie, puede dibujar sobre esa textura cuando los objetos se mueven, para crear un rastro dinámico de espuma. Hay muchas maneras de hacerlo, por lo que este podría ser su propio proyecto.

Código Fuente

Aquí puede encontrar el proyecto PlayCanvas alojado terminado. Un puerto Three.js también está disponible en este repositorio.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.