Iluminación personalizada en Shader Graph: Ampliando tus gráficos en 2019

ALEX LINDMAN / UNITY TECHNOLOGIESContributor
Jul 31, 2019|13 minutos
Iluminación personalizada en Shader Graph: Ampliando tus gráficos en 2019
Para tu comodidad, tradujimos esta página mediante traducción automática. No podemos garantizar la precisión ni la confiabilidad del contenido traducido. Si tienes alguna duda sobre la precisión del contenido traducido, consulta la versión oficial en inglés de la página web.

¡Con el lanzamiento de Unity Editor 2019.1, el paquete Shader Graph salió oficialmente de la vista previa! Ahora, en 2019.2, incorporamos aún más características y funcionalidades a Shader Graph.

¿Qué ha cambiado en 2019?
Funciones personalizadas y actualizaciones de subgráficos

Para mantener el código personalizado dentro de su Shader Graph, ahora puede usar nuestro nuevo nodo de Función personalizada. Este nodo le permite definir sus propias entradas y salidas personalizadas, reordenarlas e inyectar funciones personalizadas directamente en el nodo mismo o haciendo referencia a un archivo externo.

Los subgráficos también han recibido una actualización: ahora puedes definir tus propias salidas para subgráficos, con diferentes tipos, nombres personalizados y puertos reordenables. Además, Blackboard for Sub Graphs ahora admite todos los tipos de datos que admite el gráfico principal.

Modos de color y modos de precisión

Usar Shader Graph para crear sombreadores potentes y optimizados ahora es un poco más fácil. En 2019.2, ahora puede configurar manualmente la precisión de los cálculos en su gráfico, ya sea en todo el gráfico o por nodo. ¡Nuestros nuevos modos de color hacen que sea rápido y fácil visualizar el flujo de precisión, la categoría de nodos o mostrar colores personalizados para su propio uso!

Consulte la documentación de Shader Graph para obtener más información sobre estas nuevas funciones.

Proyecto de muestra

Para ayudarlo a comenzar con el nuevo flujo de trabajo de funciones personalizadas, hemos creado un proyecto de ejemplo junto con instrucciones paso a paso. ¡Descarga el proyecto desde nuestro repositorio y síguelo! Este proyecto le mostrará cómo utilizar el nodo Función personalizada para escribir sombreadores de iluminación personalizados para el canal de renderizado ligero (LWRP). Si desea continuar utilizando un proyecto nuevo, asegúrese de utilizar el Editor 2019.2 y el paquete LWRP versión 6.9.1 o superior.

Obtención de datos de la luz principal

Para comenzar, necesitamos obtener información de la luz principal de nuestra escena. Comience seleccionando Crear > Sombreador > Gráfico sin iluminación para crear un nuevo Gráfico de sombreado sin iluminación. En el menú Crear nodo, ubique el nuevo nodo Función personalizada y haga clic en el ícono de engranaje en la parte superior derecha para abrir el menú del nodo.

En este menú puedes agregar entradas y salidas. Agregue dos puertos de salida para Dirección y Color, y seleccione Vector 3 para ambos. Si ve un indicador de error de "identificador no declarado", no se preocupe; esto desaparecerá cuando comencemos a agregar nuestro código. En el menú desplegable Tipo , seleccione Cadena. Actualice el nombre de su función: en este ejemplo, usamos “MainLight”. Ahora, podemos comenzar a agregar nuestro código personalizado en el cuadro de texto.

Imagen

Primero, vamos a utilizar una bandera llamada `#ifdef SHADERGRAPH_PREVIEW`. Debido a que los cuadros de vista previa en los nodos no tienen acceso a datos de luz, necesitamos indicarle al nodo qué mostrar en los cuadros de vista previa en el gráfico. `#ifdef` le dice al compilador que use código diferente en diferentes situaciones. Comience por definir sus valores de respaldo para los puertos de salida.

A continuación, usaremos `#else` para indicarle al compilador qué hacer cuando no esté en una vista previa. Aquí es donde realmente obtenemos nuestros datos de luz. Utilice la función incorporada `GetMainLight()` del paquete LWRP. Podemos utilizar esta información para asignar las salidas de Dirección y Color . Su función personalizada ahora debería verse así:

Ahora, es una buena idea agregar este nodo a un grupo para que puedas marcar lo que está haciendo. Haga clic con el botón derecho en el nodo, seleccione Crear grupo a partir de la seleccióny luego cambie el nombre del título del grupo para describir lo que está haciendo su nodo. Aquí hemos ingresado “Obtener luz principal”.

Imagen

Ahora que tenemos nuestros datos de luz, podemos calcular algo de sombreado. Comenzaremos con una iluminación lambertiana estándar, así que tomemos el producto escalar del vector normal mundial y la dirección de la luz. Pásalo a un nodo Saturar y multiplícalo por el color claro. Conecte esto al puerto Color del nodo maestro no iluminado y su vista previa debería actualizarse con un sombreado personalizado.

Imagen
Cómo utilizar el modo de archivo de función personalizada

Ahora que sabemos cómo obtener datos de luz utilizando el nodo Función personalizada, podemos ampliar nuestra función. Nuestra siguiente función obtiene valores de atenuación de la luz principal además de la dirección y el color. Como se trata de una función más complicada, cambiemos al modo de archivo y usemos un archivo de inclusión HLSL. Esto le permite crear funciones más complicadas en un editor de código adecuado antes de inyectarlas en el gráfico. Esto también significa que tenemos una ubicación unificada para depurar el código. Comience abriendo el archivo de inclusión `CustomLighting` en la carpeta Activos > Incluir del proyecto. Por ahora, solo nos centraremos en la función `MainLight_half`. La función se ve así:

Esta función incluye algunos datos de entrada y salida nuevos, así que regresemos a nuestro nodo Función personalizada y agreguémoslos. Agregue dos nuevas salidas para DistanceAtten (atenuación de distancia) y ShadowAtten (atenuación de sombra). Luego, agregue la nueva entrada para WorldPos (posición mundial). Ahora que tenemos nuestras entradas y salidas, podemos hacer referencia al archivo de inclusión. Cambie el menú desplegable Tipo a Archivo. En la entrada de Origen, navegue hasta el archivo de inclusión y seleccione el Activo al que hacer referencia. Ahora necesitamos decirle al nodo qué función usar. En el cuadro Nombre , ingresamos “MainLight”.

Imagen

Notarás que el archivo de inclusión tiene `_half` al final del nombre de la función, pero nuestra opción de nombre no. Esto se debe a que el compilador Shader Graph agrega el formato de precisión a cada nombre de función. Como estamos definiendo nuestra propia función, necesitamos que el código fuente le indique al compilador qué formato de precisión utiliza nuestra función. En el nodo, sin embargo, solo necesitamos hacer referencia al nombre de la función principal. Puede crear un duplicado de la función que utiliza valores 'flotantes' para compilar en modo de precisión flotante. El modo de color 'Precisión' le permite rastrear fácilmente la precisión establecida para cada nodo en el gráfico, donde el azul representa la flotación y el rojo la mitad.

Probablemente querremos usar esta función nuevamente en otro lugar, y la forma más fácil de hacer que esta función personalizada sea reutilizable es envolverla en un subgráfico. Seleccione el nodo y su grupo y luego haga clic derecho para buscar Convertir en subgráfico. Lo hemos llamado "Obtener luz principal". En el subgráfico, simplemente agregue los puertos de salida necesarios al nodo de salida del subgráfico y conecte la salida del nodo a la salida del subgráfico. A continuación, agregaremos un nodo de posición mundial para conectarlo a la entrada.

Imagen

Guarde el subgráfico y regrese a nuestro gráfico apagado. Vamos a agregar dos nuevos nodos de multiplicación a nuestra lógica existente. Primero, multiplique las dos salidas de atenuación juntas. Luego, multiplica esa salida por el color de la luz. Podemos multiplicar esto por NdotL de anteriormente para calcular correctamente la atenuación en nuestro sombreado básico.

Imagen
Creación de un sombreador especular directo

El sombreador que hemos creado es genial para objetos mate, pero ¿qué pasa si queremos algo de brillo? ¡Podemos agregar nuestros propios cálculos especulares a nuestro sombreador! Para este paso, utilizaremos otro nodo de función personalizada envuelto en un subgráfico, llamado Direct Specular. Eche un vistazo nuevamente al archivo de inclusión `CustomLighting` y verá que ahora estamos haciendo referencia a otra función del mismo archivo:

Esta función realiza algunos cálculos especulares simples y, si tienes curiosidad, puedes leer más sobre ellos aquí. El subgráfico de esta función también incluye algunas entradas en la pizarra:

Imagen

Asegúrese de que su nuevo nodo tenga todos los puertos de entrada y salida adecuados para que coincidan con la función. Agregar propiedades al Blackboard es sencillo: simplemente haga clic en el ícono Agregar (+) en la parte superior derecha y seleccione el tipo de datos. Haga doble clic en la píldora para cambiar el nombre de la entrada y arrastre y suelte la píldora para agregarla al gráfico. Por último, actualice el puerto de salida de su subgráfico y guárdelo.

Ahora que el cálculo especular está configurado, podemos volver al gráfico sin iluminación y agregarlo a través del menú Crear nodo. Conecte la salida de atenuación a la entrada de color del subgráfico especular directo . A continuación, conecte la salida de Dirección de la función Obtener luz principal a la entrada de Dirección del subgráfico especular. Agregue el resultado de NdotL*Atenuación a la salida del subgráfico especular directo y conéctelo a la salida de color .

Imagen

¡Ahora tenemos un poco de brillo!

Trabajar con múltiples luces

La luz principal del LWRP se refiere a la luz direccional más brillante en relación con el objeto, que generalmente es el sol. Para mejorar el rendimiento en hardware de gama baja, el LWRP calcula la luz principal y cualquier luz adicional por separado. Para asegurarse de que nuestro sombreador calcule correctamente todas las luces de la escena, y no solo la luz direccional más brillante, debe crear un bucle en su función. Para obtener datos de luz adicionales, utilizamos un nuevo subgráfico para envolver un nuevo nodo de función personalizada. Eche un vistazo a la función `AdditionalLight_float` en el archivo de inclusión `CustomLighting`:

Como antes, utilice la función `AdditionalLights` en la referencia del archivo del nodo Función personalizada y asegúrese de haber creado todas las entradas y salidas adecuadas. Asegúrese de exponer el color especular y la suavidad especular en la pizarra del subgráfico en el que está envuelto el nodo. Utilice los nodos Posición, Vector normal y Dirección de vista para conectar la Posición mundial, la Normal mundialy la Dirección de vista del espacio mundial en el subgráfico.

Después de configurar la función, ¡úsala! Primero, tome el gráfico principal no iluminado del paso anterior y contráigalo a un subgráfico. Seleccione los nodos y haga clic derecho en Convertir en subgráfico. Retire el último nodo Agregar y conecte las salidas a los puertos de salida del Subgráfico. Le recomendamos que también cree propiedades de entrada para Especular y Suavidad.

Imagen

Ahora puedes combinar tus cálculos de luz principal y tus cálculos de luz adicional. En el gráfico principal sin iluminación, cree un nuevo nodo para que los cálculos de luz adicional se realicen junto con los cálculos de luz principal. Agregue las salidas difusas y especulares de la luz principal y las luces adicionales juntas. ¡Bastante simple!

Imagen
Creando un sombreador de dibujos animados simple
Imagen

Ahora ya sabes cómo obtener los datos de todas las luces de una escena para un proyecto LWRP, pero ¿qué puedes hacer con ellos? ¡Uno de los usos más comunes de la iluminación personalizada en los shaders es un shader de dibujos animados clásico!

Con todos los datos de luz, crear un sombreador de dibujos animados es bastante simple. Primero, toma todos los cálculos de luz que has hecho hasta ahora y envuélvelos en un subgráfico una vez más. Esto ayudará con la legibilidad en el sombreador final. No olvide eliminar el nodo Agregar final y alimentar Difuso y Especular a puertos de salida separados en el nodo de salida del Subgráfico.

Hay muchos métodos para crear sombreado de dibujos animados, pero en este ejemplo, usaremos la intensidad de la luz para buscar colores en una textura de rampa. Esta técnica generalmente se llama iluminación de rampa. Hemos incluido algunos ejemplos del tipo de recurso de textura necesario para la iluminación de rampa en el proyecto de muestra. También puedes muestrear un degradado para usar rampas dinámicas en Iluminación de rampa. El primer paso es convertir la intensidad de Difuso y Especular de valores RGB a valores HSV. Esto nos permite usar la intensidad del color de la luz (los valores HSV) para determinar el brillo en el sombreador y nos ayuda a muestrear la textura en diferentes puntos a lo largo del eje horizontal del activo. Utilice un valor estático para el canal Y del UV para determinar, de arriba a abajo, qué parte de la imagen debe muestrearse. Puede utilizar este valor estático como índice para hacer referencia a múltiples rampas de iluminación para el proyecto en un solo recurso de textura.

Imagen

Una vez que haya establecido los valores UV, utilice un nodo LOD 2D de textura de muestra para muestrear la textura de rampa. El LOD de muestra es importante; si usamos un nodo de textura de muestra 2D normal, la rampa se mipea automáticamente en una escena y los objetos más alejados tendrán diferentes comportamientos de iluminación. El uso de un nodo LOD 2D de textura de muestra nos permite determinar manualmente el nivel de mip. Además, dado que la textura de rampa solo tiene 2 píxeles de alto, creamos nuestro propio estado de muestreo para las texturas. Para asegurarnos de que la textura se muestrea correctamente, configuramos el filtro en Punto y el envoltorio en Abrazadera. Exponemos esto como una propiedad en Blackboard para que puedas cambiar la configuración si cambia el activo de textura.

Imagen

Finalmente, multiplicamos la muestra de rampa de los cálculos difusos por una propiedad de color, Diffuse, para que podamos cambiar los colores del objeto. Agregue la muestra de rampa de los cálculos especulares a la salida difusa y conecte el color final al nodo maestro.

Imagen
Ampliando la iluminación personalizada
Imagen

Esta sencilla configuración de iluminación personalizada se puede ampliar y aplicar a una amplia variedad de casos de uso en todo tipo de escenas. En nuestro proyecto de ejemplo, hemos incluido una escena completa configurada con sombreadores que utilizan nuestra configuración de iluminación personalizada. También contiene animación de vértices, una aproximación simple de dispersión de subsuperficie, así como refracciones y coloraciones que utilizan la profundidad. ¡Descargue el proyecto y consulte nuestros recursos de ejemplo para explorar métodos más avanzados!

¡Sigue aprendiendo!

¡Si quieres hablar sobre Shader Graph y los sombreadores que puedes crear con él, ven a pasar un rato en nuestro nuevo foro! ¡También puedes encontrar miembros de la comunidad y (a veces) algunos desarrolladores reunidos en el Discord de la comunidad!

¡No olvides estar atento a las grabaciones de nuestras sesiones de SIGGRAPH 2019, donde profundizamos aún más en el uso de Shader Graph para la iluminación personalizada!