Tutoriales de Gráficas
Shaders: programas vertex y fragment

Shaders: ShaderLab y shaders con función fija

Este tutorial le enseña a usted los primeros pasos de crear sus propios shaders, para ayudarle a controlar el aspecto de su juego y optimizar el rendimiento de los gráficos.

Unity está equipado con un lenguaje de material y shading poderoso llamadoÇ ShaderLab. En estilo es similar a los lenguajes CgFX y Direct3D Effects (.FX) - describe todo lo que necesita para mostrar un Material.

Los Shaders describe propiedades que están expuestas en el Inspector del Material de Unity y varias implementaciones shader (SubShaders) que apuntan a a diferentes capacidades gráficas de hardware, cada una describiendo completamente el estado de rendering de la tarjeta gráfica, y programas vertex/fragment ha utilizar. Los programas Shader están escritos en el lenguaje de programación de alto-nivel Cg/HLSL.

En este tutorial vamos a describir cómo escribir shaders muy simples usando la denominada notación de “función fija”. En el capítulo siguiente introduciremos vertex y fragment shader programs](SL-ShaderPrograms.html). Asumimos que el lector tiene un entendimiento básico de OpenGL o estados de render de Direct3D, y tiene algún conocimiento de los lenguajes de programación shader HLSL, Cg, GLSL o Metal

Empezando

Para crear un nuevo shader, elija Assets > Create > Shader > Unlit Shader del menú principal, o duplique un shader existente y trabaje desde ese. El nuevo shader se puede editar haciendo doble clic en él en el Project View.

Unity tiene una manera de escribir shaders muy simples en la denominada notación de “función fija”. Comenzaremos con esto por simplicidad. Internamente los shaders de función fija se convierten en vertex y fragment programs regulares al tiempo de importación del shader.

Comenzaremos con un shader muy básico:

Shader "Tutorial/Basic" {
    Properties {
        _Color ("Main Color", Color) = (1,0.5,0.5,1)
    }
    SubShader {
        Pass {
            Material {
                Diffuse [_Color]
            }
            Lighting On
        }
    }
}

This simple shader demonstrates one of the most basic shaders possible. It defines a color property called Main Color and assigns it a default pink color (red=100% green=50% blue=50% alpha=100%). It then renders the object by invoking a Pass and in that pass setting the diffuse material component to the property _Color and turning on per-vertex lighting.

Para probar este shader, cree un nuevo material, seleccione el shader desde el menú desplegable (Tutorial->Basic) y asigne el Material a algún objeto. Ajuste el color en el Inspector del Material y mire los cambios. Tiempo de moverse a cosas más complicadas!

Iluminación de vértice básica

Si abre un shader complejo existente, puede ser un poco difícil obtener una buena visión general. Para empezar, diseccionaremos el shader VertexLit integrado que se suministra con Unity. Este shader utiliza una pipeline de función fija para hacer la iluminación estándar por vértice.

Shader "VertexLit" {
    Properties {
        _Color ("Main Color", Color) = (1,1,1,0.5)
        _SpecColor ("Spec Color", Color) = (1,1,1,1)
        _Emission ("Emmisive Color", Color) = (0,0,0,0)
        _Shininess ("Shininess", Range (0.01, 1)) = 0.7
        _MainTex ("Base (RGB)", 2D) = "white" { }
    }

    SubShader {
        Pass {
            Material {
                Diffuse [_Color]
                Ambient [_Color]
                Shininess [_Shininess]
                Specular [_SpecColor]
                Emission [_Emission]
            }
            Lighting On
            SeparateSpecular On
            SetTexture [_MainTex] {
                constantColor [_Color]
                Combine texture * primary DOUBLE, texture * constant
            }
        }
    }
}

Todos los shaders comienzan con la palabra clave Shader seguido de un string que representa el nombre del shader. Este es el nombre que se muestra en el Inspector. Todo el código para este shader debe colocarse dentro de los corchetes: { } (llamado bloque).

  • El nombre debe ser corto y descriptivo. No tiene que coincidir con el nombre del archivo .Shader.
  • Para poner shaders en submenús en Unity, utilice barras inclinadas -e.g. MyShaders/Test se mostraría como Test en un submenú llamado MyShaders o MyShaders->Test.

El shader está compuesto de un bloque de Properties seguido por bloques SubShader. Cada uno de estos se describe en una sección de abajo.

Propiedades

Al principio del bloque de shader puede definir las propiedades que los artistas pueden editar en el Inspector del Material. En el ejemplo de VertexLit las propiedades se ven así:

Las propiedades se enumeran en líneas separadas dentro del bloque de Propiedades. Cada propiedad comienza con el nombre interno (Color, MainTex). Después de esto entre paréntesis viene el nombre mostrado en el inspector y el tipo de la propiedad. Después de eso, el valor predeterminado de esta propiedad aparece listada como:

La lista de los tipos posibles se encuentra en la Referencia de Propiedades. El valor predeterminado depende del tipo de propiedad. En el ejemplo de un color, el valor por defecto debe ser un vector de cuatro componentes.

Ahora tenemos nuestras propiedades definidas, y estamos listos para comenzar a escribir el shader real.

El cuerpo del shader

Antes de seguir, definamos la estructura básica de un archivo shader.

Diferente hardware gráfico tiene diferentes capacidades. Por ejemplo, algunas tarjetas gráficas admiten fragment programs y otros no; Algunos pueden configurar cuatro texturas por pass, mientras que los otros pueden hacer sólo dos o una; Etc. Para permitirle hacer uso completo de cualquier hardware que tenga su usuario, un shader puede contener varios SubShaders. Cuando Unity procesa un shader, pasará por todos los subshaders y utilizará el primero que soporte el hardware.

Shader "Structure Example" {
    Properties { /* ...shader properties... }
    SubShader {
        // ...subshader that requires fancy DX11 / GLES3.1 hardware...
    }
    SubShader {
        // ...subshader that requires DX9 SM3 / GLES3 hardware...
    }
    SubShader {
        // ...subshader that might look ugly but runs on anything :)
    }
}

Este sistema le permite a Unity soportar todo el hardware existente y maximiza la calidad de cada uno. Sin embargo, resulta en algunos shaders largos.

Dentro de cada bloque SubShader se configura el estado de rendering compartido por todos los passes; Y definen los passes de rendering ellos mismos. Se puede encontrar una lista completa de los comandos disponibles en la referencia SubShader.

Passes

ada subshader es una colección de passes. Para cada pass, la geometría del objeto es renderizada, por lo que debe haber al menos un pass. Nuestro shader VertexLit tiene sólo un pass:

// ...snip...
Pass {
    Material {
        Diffuse [_Color]
        Ambient [_Color]
        Shininess [_Shininess]
        Specular [_SpecColor]
        Emission [_Emission]
    }
    Lighting On
    SeparateSpecular On
    SetTexture [_MainTex] {
        constantColor [_Color]
        Combine texture * primary DOUBLE, texture * constant
    }
}
// ...snip...

Cualquier comando definido en un pass configura el hardware de gráficos para renderizar la geometría de una manera específica.

En el ejemplo anterior tenemos un bloque Material que une nuestros valores de propiedad a los ajustes de material de la iluminación de función fija. El comando Lighting On enciende la iluminación estándar del vértice, y SeparateSpecular On permite el uso de un color separado para el resaltado especular.

Todos estos comandos hasta ahora asignan muy directamente a la función fija del modelo de hardware OpenGL/Direct3D. Consulte OpenGL red book para obtener más información al respecto.

The next command, SetTexture, is very important. These commands define the textures we want to use and how to mix, combine and apply them in our rendering. SetTexture command is followed by the property name of the texture we would like to use (_MainTex here) This is followed by a combiner block that defines how the texture is applied. The commands in the combiner block are executed for each pixel that is rendered on screen.

Within this block we set a constant color value, namely the Color of the Material, _Color. We’ll use this constant color below.

En el siguiente comando especificamos cómo mezclar la textura con los valores de color. Hacemos esto con el comando Combine que especifica cómo mezclar la textura con otra o con un color. Generalmente se ve así: Combine ColorPart, AlphaPart

Aquí ColorPart y AlphaPart definen la mezcla de componentes de color (RGB) y alfa (A), respectivamente. Si se omite AlphaPart, utilice la misma mezcla que ColorPart.

En nuestro ejemplo VertexLit: Combine texture * primary DOUBLE, texture * constant

Here texture is the color coming from the current texture (here _MainTex). It is multiplied (*) with the primary vertex color. Primary color is the vertex lighting color, calculated from the Material values above. Finally, the result is multiplied by two to increase lighting intensity (DOUBLE). The alpha value (after the comma) is texture multiplied by constant value (set with constantColor above). Another often used combiner mode is called previous (not used in this shader). This is the result of any previous SetTexture step, and can be used to combine several textures and/or colors with each other.

Resumen

Nuestro shader VertexLit configura la iluminación de vértices estándar y configura los combinadores de textura para que la intensidad de iluminación renderizada se duplique.

Podríamos poner más passes en el shader, se obtendrían uno tras otro. Por el momento, sin embargo, eso no es necesario ya que tenemos el efecto deseado. Solo necesitamos un SubShader ya que no hacemos uso de ninguna característica avanzada - este shader en particular funcionará en cualquier tarjeta gráfica que soporte Unity.

El shader VertexLit es uno de los shaders más básicos que podemos imaginar. No usamos ninguna operación específica de hardware, ni utilizamos ninguno de los comandos más especiales y buenos que ShaderLab y Cg/HLSL tienen para ofrecer.

En el capítulo siguiente procederemos explicando cómo escribir programas personalizados de vertex & fragment usando el lenguaje Cg/HLSL.

Tutoriales de Gráficas
Shaders: programas vertex y fragment