Consigue un 20% de descuento usando el código RELEASE en la compra de tu libro. Por tiempo limitado.

Introducción al lenguaje de programación de shaders

4.0.5. Depurando un shader

Esta publicación está disponible en...

Cuando escribimos un script en C# en Unity podemos depurar nuestro programa utilizando la función Debug.Log(object message). Esta función nos permite imprimir en consola una operación de nuestro código, sin embargo esta función no está disponible en Cg o HLSL.

Entonces, ¿cómo podemos depurar un shader? Para ello debemos tomar en consideración varios factores, entre ellos: “los colores”. En un shader, existen tres colores importantes que veremos constantemente, estos son: blanco (1, 1, 1, 1), negro (0, 0, 0, 1) y magenta (1, 0, 1, 1). El blanco representa un valor por defecto, mientras que el negro representa un valor inicializado. Por otra parte, el color magenta representa un error gráfico, de hecho es muy común importar assets a Unity que lucen de color magenta en nuestra escena.

(Fig. 039)

Para abordar este concepto, vamos a recordar la declaración de Propiedades en ShaderLab, para ello, recrearemos una propiedad de color.

_Color (“Tint”, Color) = (1, 1, 1, 1)

En el ejemplo anterior, la propiedad ha sido declarada con un color “blanco” por defecto, esto podemos corroborarlo en el vector de cuatro dimensiones; al final de la operación (1, 1, 1, 1). Esta propiedad como tal va a generar un “selector de color” en el Inspector de Unity y su color y/o valor de inicialización será blanco.

Analicemos otra propiedad.

_MainTex (“Texture”, 2D) = “white”{}

Nuevamente, esta propiedad como tal va a generar un “selector de textura” en el Inspector de Unity, pero, ¿cuál será su color por defecto en caso de que no utilicemos ninguna textura? Su color será blanco, esto podemos corroborarlo en la declaración “white” que se encuentra en la propiedad.

El color negro lo veremos con frecuencia en declaraciones de vectores y variables internas en nuestro código, de hecho es muy común inicializar vectores en “cero” para luego sumar alguna operación, e.g., el vector de cuatro dimensiones “float4 col = 0” ha sido inicializado en “0”, esto quiere decir que todos sus canales (RGBA) van a tener cero como valor por defecto.

Cabe mencionar, que el color blanco representa el valor máximo de iluminación de un pixel y el negro representa el mínimo de iluminación del mismo. Es muy importante tener esto en cuenta ya que, en la medida que avancemos, tendremos algunas operaciones que excederán los valores máximos (x > 1) y mínimos (x < 0). En estos casos se produce saturación de color y para ello utilizaremos algunas funciones como “clamp” que nos permitirá limitar un valor entre dos números (mínimo y máximo).

¿Por qué a veces nuestros objetos aparecen de color magenta? Como ya sabemos, este color representa un “error gráfico”. Básicamente, cuando la GPU no ha sido capaz de llevar a cabo las operaciones que se encuentran dentro del shader, arroja un color magenta por defecto. En Unity, las razones de este color se deben a dos factores principalmente: 1. que el render pipeline no ha sido configurado o 2. que el shader tiene un error en su código.

Cuando importamos un asset al software, lo primero que debemos saber es, ¿en cuál render pipeline estamos trabajando? Recordemos que en Unity existen tres tipos de render pipeline y cada uno posee una configuración distinta.

Supongamos, si importamos un asset que incluye un material con un shader tipo Standard Surface en Universal RP entonces nuestro asset aparecerá de color magenta debido a que este tipo de shader es soportado sólo en Built-in RP. Para solucionar este error gráfico tendremos que seleccionar el material, ir al inspector y cambiar el tipo de shader por alguno que se encuentre dentro del menú “Shader Graphs”.

Una vez que hemos identificado el tipo de rendering pipeline que estamos utilizando debemos proceder a la evaluación del shader.

Los errores en un shader son gráficamente evidentes dado que los objetos adquieren un color magenta. si prestamos atención a la consola podremos encontrar su definición. Para solucionarlos debemos considerar algunos factores, entre ellos: término de una instrucción o función en HLSL y ShaderLab. La mayoría de los errores se generan por mala redacción o sintaxis. A continuación revisaremos uno bastante común:

// in console
Shader error in “Unlit/ simpleColor”: syntax error: unexpected token '}' at line 60 (on d3d11)

¿Cómo podemos leer el enunciado anterior? En este caso, el shader que se encuentra en el menú «Unlit», llamado «USB_simple_color», posee un error en la línea de código 60 y no puede compilar en Direct3D 11.

Ahora bien, ¿es ese realmente el problema del shader? Para ello, vamos a analizar la línea de código que está generando el error.

58    fixed4 frag (v2f i) : SV_TARGET
59    {
60        fixed4 col = tex2D(_MainTex, i.uv); 
61        return col
62    }

Según la consola, el error se está generando en la línea de código número 60 pero, como podemos ver, ahí no hay ningún problema. Cabe preguntarnos entonces, ¿qué es lo que está ocurriendo? El error se debe a que olvidamos cerrar la operación en la línea de código número 61. Si prestamos atención al return nos daremos cuenta que al vector col le falta un punto y coma (;) entonces la GPU piensa que la operación continua, por eso no puede compilarla.

Otro error que veremos con frecuencia es el siguiente:

Shader error in 'Unlit/simpleColor': cannot implicitly convert from 'half2' to 'half4' at line 60 (on d3d11)

half4 frag (v2f i) : SV_TARGET
{
    half4 col = tex2D(_MainTex, i.uv); 
    half2 uv = 0;
    col = uv;
    return col;
}

En este caso el error se está generando, porque estamos intentando convertir un vector de cuatro dimensiones (col) en uno de dos dimensiones (uv). El vector col, al ser de cuatro dimensiones posee los canales RGBA o XYZW, en cambio, el vector uv, al ser de dos dimensiones sólo posee la combinación de dos canales (RG, RB, GB, etc), por lo tanto, no se puede convertir desde un vector de dos dimensiones a uno de cuatro.

Siguenos para mantenerte informado sobre todas las novedades, actualizaciones y más.

Únete al grupo para compartir tus experiencias con otros desarrolladores.

¡Suscríbete a nuestro canal y sigue aprendiendo sobre desarrollo de juegos!

jettelly-logo

Jettelly Team

Somos un equipo de desarrolladores independientes con más de 9 años de experiencia en videojuegos. Como estudio independiente, hemos desarrollado Nom Noms el que publicamos con Hyperbeard en 2019. Actualmente estamos desarrollando La Biblia de Shader en Unity.

Síguenos en nuestras redes sociales.