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.3.2. Cg / HLSL vertex shader stage

Esta publicación está disponible en...

En esta etapa en donde los vértices son transformados desde un espacio 3D a una proyección bidimensional en la pantalla.

Dentro del shader USB_simple_color podremos encontrar una función llamada “vert” la cual corresponde a nuestro vertex shader stage. La razón por la que sabemos que de hecho es nuestro vertex shader se debe a que fue declarada como tal en el #pragma vertex.

#pragma vertex vert
...
v2f vert (appdata v)
{
    ...
}

Antes de continuar con la explicación de esta etapa, debemos recordar que nuestro shader USB_simple_color es de tipo Unlit (no posee luz) por esta razón incluye una función para el vertex shader y otra para el fragment shader (#pragma fragment frag). Es fundamental mencionar esto dado que Unity provee una manera rápida de escribir shaders en la forma de “Surface Shader” (surf) que en sí mismo genera código Cg de manera automática, exclusivamente para materiales que son afectados por la iluminación. Esto permite optimizar el tiempo de desarrollo, pero resta control sobre lo que deseamos entender debido a que muchas funciones y cálculos ocurren de manera interna en el programa. Es por esto que creamos un Unlit shader al comienzo de este libro; para entender en detalle el funcionamiento del mismo.

Vamos a analizar la estructura del vertex shader stage. Nuestra función inicia con la palabra “v2f” la cual significa “vertex to fragment”. Este nombre tiene mucho sentido cuando entendemos el proceso interno que está ocurriendo en el programa. Básicamente v2f será utilizado posteriormente como argumento en el fragment shader stage, de ahí el nombre. Entonces, como nuestra función inicia con v2f quiere decir que es de tipo vertex output, por lo tanto, tendremos que retornar un valor asociado a este tipo de dato.

Continua con “vert” el cual es el nombre de nuestro vertex shader stage y luego los argumentos entre paréntesis en donde appdata cumple la función de vertex input.

v2f vert (appdata v) {} ...

Dentro de esta función podemos transformar y conectar las propiedades que se encuentran en appdata con las propiedades en v2f. Si continuamos nuestro análisis, notaremos que dentro de la función, el struct v2f ha sido inicializado con la letra “o”, es decir que “o” sería nuestro puntero, por lo tanto, dentro de esta variable se encontrarán todos las propiedades que fueron declarados en el struct v2f .

v2f o;
o.vertex …
o.uv …
return o;

Entonces la primera operación que ocurre dentro del vertex shader stage es la transformación de los vértices del objeto desde object-space a clip-space a través del método “UnityObjectToClipPos”. Recordemos que nuestros objetos se encuentran dentro de un espacio tridimensional en la escena y debemos transformar esas coordenadas a una proyección bidimensional de píxeles en pantalla. Esa transformación ocurre precisamente dentro de la función “UnityObjectToClipPos”. Lo que hace esta función es multiplicar la matriz del modelo actual (unity_ObjectToWorld) por el factor de la multiplicación entre la vista actual y la matriz de proyección (UNITY_MATRIX_VP).

UnityObjectToClipPos( float3 pos).
{
    return mul(
        UNITY_MATRIX_VP, 
        mul(unity_ObjectToWorld, float4(pos , 1.0)));
}

Esta operación viene declarada en el archivo “UnityShaderUtilities.cginc” la cual ha sido incluida como dependencia en UnityCG.cginc y por esta razón podemos utilizarla dentro de nuestro shader. Entonces, tomamos el input de vértices de nuestro objeto (v.vertex), transformamos la matriz desde object-space a clip-space (UnityObjectToClipPos) y guardamos el resultado en el output de vértices (o.vertex).

v2f vert (appdata v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
}

Un factor que debemos considerar al momento de trabajar con inputs u outputs es que ambas propiedades deben poseer la misma cantidad de dimensiones. Por ejemplo: si vamos al vertex input appdata notaremos que el vector “float4 vertex” tiene la misma cantidad de dimensiones que “float4 vertex” en el vertex output (v2f).

Si una propiedad es de tipo float4 y la otra float3 entonces es posible que Unity arroje un error debido a que en la mayoría de los casos no se puede transformar desde un vector de cuatro dimensiones a un vector de tres o menos dimensiones.

Luego podemos encontrar la función TRANSFORM_TEX. Esta función pide dos argumentos los cuales son: 1. el input de coordenadas UV del objeto (v.uv) y 2. la textura que vamos a posicionar sobre esas coordenadas (_MainTex). Básicamente cumple la función de controlar el “tiling y offset” en las coordenadas UV de la textura.

Finalmente pasamos estos valores al output de UV (o.uv) ya que posteriormente los utilizaremos en el 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.