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

3.2.7. Tipos de datos

Esta publicación está disponible en...

Antes de continuar definiendo las propiedades y funciones de nuestro shader, debemos hacer un alto en los tipos de datos debido a que existe una pequeña diferencia entre Cg y HLSL.

Cuando creamos un shader por defecto en las versiones actuales de Unity, podemos encontrar números de punto flotante que difieren en precisión, entre los que podemos encontrar:

  • float,
  • half
  • and fixed.

Un shader escrito en Cg puede compilar perfectamente en estos tres tipos de precisión, sin embargo HLSL no es capaz de compilar el tipo de dato “fixed”, por lo tanto, si trabajamos con este lenguaje tendremos que reemplazar todas las variables y vectores de este tipo ya sea por half o float.

“Float” (Cg y HLSL) es un tipo de dato de alta precisión, cuenta con 32 bits y generalmente es utilizado en el cálculo de posiciones en world-space, coordenadas de textura (UV), o cálculos escalares que implican funciones complejas como trigonometría o exponenciación.

A su vez, “Half” (Cg y HLSL) es de media precisión, cuenta con 16 bits y generalmente es utilizado en el cálculo de vectores de baja magnitud, direcciones, posiciones en object-space y colores de alto rango dinámico.

En el caso de “Fixed” (Cg) este es de baja precisión, cuenta con sólo 11 bits y generalmente es utilizado en el cálculo de operaciones simples (e.g. almacenamiento de colores básicos).

Una pregunta que surge comúnmente en la utilización de vectores es, ¿qué ocurriría si sólo utilizamos un tipo de dato flotante (Float) para todas nuestras variables? En la práctica esto es posible, sin embargo, debemos considerar que float es un tipo de dato de alta precisión, quiere decir que posee mayor cantidad de decimales, por ende, la GPU tardará más en calcularlo, aumentando tiempos y generando aumento de calor.

Es fundamental utilizar vectores y/o variables en el tipo de dato que se requiere, así podremos optimizar nuestro programa, disminuyendo la carga gráfica en la GPU.

Otros tipos de datos muy utilizados que podemos encontrar en ambos lenguajes son “int, sampler2D y samplerCube”.

“Sampler” se refiere al estado de sampleo de una textura. Dentro de este tipo de dato podremos almacenar una textura y sus coordenadas UV.

Generalmente, cuando deseamos trabajar con texturas en nuestro shader debemos utilizar el tipo “Texture2D” para almacenar la textura y crear un “SamplerState” para samplear. El tipo de dato “sampler” nos permite almacenar tanto la textura como el estado de sampleo en una sola variable. Para entender en detalle la función de un sampler haremos lo siguiente:

// declare our _MainTex texture as a global variable
Texture2D _MainTex;

// declare the _MainTex sample as a global variable 
SamplerState sampler_MainTex;

// go to the fragment shader stage 
half4 frag(v2f i) : SV_Target
{
    // inside the col vector sample the texture in UV coordinates. 
    half4 col = _MainTex.Sample(sampler_MainTex, i.uv);

    // return the colour of the texture. 
    return col;
}

El proceso anterior puede ser optimizado simplemente utilizando un “sampler”.

// declare our sampler for _MainTex 
sampler2D _MainTex;

// go to the fragment shader stage 
half4 frag(v2f i) : SV_Target
{
    // sample the texture in UV coordinates using the function 
    // tex2D().
    half4 col = tex2D(_MainTex, i.uv)

    // return the colour of the texture. 
    return col;
}

Ambos ejemplos retornan exactamente el mismo valor. Este corresponde a la textura que generamos en nuestras propiedades, la cual será asignada desde el Inspector de Unity.

En nuestro programa podremos utilizar valores escalares, vectores y matrices.

Los valores escalares son aquellos que retornan un número real, ya sea entero o con decimales (e.g. 1, 0.4, 4, etc) y para declararlos en nuestro shader primero debemos agregar el “tipo de dato”, luego el “nombre del valor escalar” y finalmente “inicializamos su valor por defecto”.

Su sintaxis es la siguiente:

float nombre = n;   // e.g. float a = 0;
half nombre = n;    // e.g. float b = 1.456;
fixed nombre = n;   // e.g. float c = 2.5;

Los vectores son aquellos que retornan un valor con más de una dimensión (e.g. XYZW) y para declararlos en nuestro shader primero debemos agregar el “tipo de dato”, luego “la cantidad de dimensiones”, luego “el nombre del vector” y finalmente “inicializamos su valor por defecto».

Su sintaxis es la siguiente:

float2 nombre = n;   // e.g. float2 uv = float2(0.5, 0.5);
half3 nombre = n;    // e.g. half3 position = float3(0, 0, 0);
fixed4 nombre = n;   // e.g. fixed4 color = float4(1, 1, 1, 1);

Las matrices son aquellas que cuentan con valores almacenados en columnas y filas, poseen más de una dimensión y son utilizadas principalmente para shearing, rotación y cambio de posición de los vértices.

Para declarar una matriz en nuestro shader primero debemos agregar el “tipo de dato”, luego la “cantidad de dimensiones multiplicado por sí mismo”, luego el “nombre de la matriz” y finalmente “inicializamos sus valores por defecto” tomando en consideración que las coordenadas Xx, Yy & Zz serán igual a 1.

Su sintaxis es la siguiente:

float3x3 nombre = float3x3    // three rows and three columns 
(
    1, 0, 0,
    0, 1, 0,
    0, 0, 1
);

half2x2 nombre = half2x2        // two rows and two columns
(
    1, 0,
    0, 1
);

fixed4x4 nombre = fixed4x4    // four rows and four columns 
(
    1, 0, 0, 0,
    0, 1, 0, 0, 
    0, 0, 1, 0,
    0, 0, 0, 0
);

Si estás iniciando en el mundo de los shader en Unity, es muy posible que no entiendas del todo lo que se ha intentado explicar. No te preocupes, más adelante en este capítulo revisaremos en detalle todos estos parámetros y veremos el funcionamiento del fragment shader stage.

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.