A menudo es conveniente mantener la mayor parte de código shader fijo, pero también permiten que se produzcan variantes de shader ligeramente diferentes. Esto se denomina comúnmente “mega shaders” o “uber shaders”, y se logra compilando el código de shader varias veces con diferentes directivas de preprocesador para cada caso.
En Unity esto puede lograrse añadiendo una directiva #pragma multi_compile
o#pragma shader_feature
a un shader snippet. Esto funciona en surface shaders también.
En tiempo de ejecución, la variante shader adecuada se obtiene de las palabras clave Material (Material.EnableKeyword and DisableKeyword) o palabras claves globales shader (Shader.EnableKeyword y DisableKeyword).
Una directiva cómo:
#pragma multi_compile FANCY_STUFF_OFF FANCY_STUFF_ON
Producirá dos variantes shader, una con FANCY_STUFF_OFF
defined y otra conFANCY_STUFF_ON
. En tiempo de ejecución, uno de ellos se activará basándose en las palabras clave Material o global shader. Si ninguna de estas dos palabras clave está activada, se utilizará la primera (“off”).
There can be more than two keywords on a multi_compile line, for example this will produce four shader variants:
#pragma multi_compile SIMPLE_SHADING BETTER_SHADING GOOD_SHADING BEST_SHADING
Cuando cualquiera de los nombres son todos los subrayados, se producirá una variante de sombreado, sin definir la macro del preprocesador. Esto se utiliza comúnmente para las características de sombreadores, para evitar el uso de dos palabras clave (véanse las notas sobre límite de trabajo de teclado a continuación). Por ejemplo, la directiva a continuación producirá dos variantes de sombreado; Primero con nada definido y el segundo con FOO_ON
definido:
#pragma multi_compile __ FOO_ON
#pragma shader_feature
is very similar to #pragma multi_compile
, the only difference is that unused variants of shader_feature shaders will not be included into game build. So shader_feature makes most sense for keywords that will be set on the materials, while multi_compile for keywords that will be set from code globally.
Además, tiene una notación abreviada con una sola palabra clave:
#pragma shader_feature FANCY_STUFF
Que es sólo un acceso directo para #pragma shader_feature _ FANCY_STUFF
, es decir, se expande en dos variantes de shader (el primero sin definir, el segundo con él).
Varias líneas multi_compile pueden ser proporcionadas, y el shader resultante será compilado para todas las combinaciones posibles de las líneas:
#pragma multi_compile A B C
#pragma multi_compile D E
Esto produciría tres variantes para la primera línea, y dos para la segunda línea, o en total seis variantes de shader (A + D, B + D, C + D, A + E, B + E, C + E).
It’s easiest to think of each multi_compile line as controlling a single shader “feature”. Keep in mind that the total number of shader variants grows really fast this way. For example, ten multi_compile “features” with two options each produces 1024 shader variants in total!
When using Shader variants, remember that there is a limit of 256 keywords in Unity, and around 60 of them are used internally (therefore lowering the available limit). Also, the keywords are enabled globally throughout a particular Unity project, so be careful not to exceed the limit when multiple keywords are defined in several different Shaders.
Hay varias anotaciones “de acceso directo” para compilar múltiples variantes shader; Son principalmente para tratar con diferentes tipos de luz, sombra y lightmap en Unity. Ver rendering pipeline para más detalles.
Multi_compile_fwdbase
compila todas las variantes que necesita el tipo de pasoForwardBase
(forward rendering base). Las variantes tratan con diferentes tipos de lightmap y la luz direccional principal que tiene sombras activadas o desactivadas.Multi_compile_fwdbase
compila todas las variantes que necesita el tipo de pasoForwardBase
(forward rendering base). Las variantes tratan con diferentes tipos de lightmap y la luz direccional principal que tiene sombras activadas o desactivadas.Multi_compile_fwdadd_fullshadows
- igual que arriba, pero también incluye habilidad para que las luces tengan sombras en tiempo real.Multi_compile_fog
se expande a varias variantes para manejar distintos tipos de niebla (off/linear/exp/exp2).La mayoría de los accesos directos incorporados dan lugar a muchas variantes shader. Es posible omitir la compilación de algunos de ellos si sabe que no son necesarios, utilizando #pragma skip_variants
. Por ejemplo:
#pragma multi_compile_fwdadd
// will make all variants containing
// "POINT" or "POINT_COOKIE" be skipped
#pragma skip_variants POINT POINT_COOKIE
Una razón común para usar variantes shader es crear alternativas o shaders simplificados que pueden ejecutarse eficientemente en hardware de alto y bajo nivel dentro de una única plataforma de destino, como OpenGL ES. Para proporcionar un conjunto especialmente optimizado de variantes para diferentes niveles de capacidad de hardware, puede utilizar variantes de hardware shader.
Para habilitar la generación de variantes de hardware shader, añada #pragma hardware_tier_variants renderer
, donde renderer
es una de las plataformas de renderizado disponibles para shader program pragmas. Con este #pragma
se generarán 3 variantes de shader para cada shader, independientemente de cualquier otra palabra clave. Cada variante tendrá una de las siguientes definiciones:
UNITY_HARDWARE_TIER1
UNITY_HARDWARE_TIER2
UNITY_HARDWARE_TIER3
Puede usarlos para escribir retrocesos condicionales o funciones adicionales para un extremo inferior o superior. En el editor puede probar cualquiera de los niveles mediante el menú Emulación de gráficos, que le permite cambiar entre cada uno de los niveles.
Para ayudar a mantener el impacto de estas variantes lo más pequeño posible, sólo se carga un conjunto de shaders en el reproductor. Además, cualquier shaders que terminen idénticos - por ejemplo si sólo escribes una versión especializada para TIER1 y todos los demás son los mismos - no ocupará ningún espacio extra en el disco.
En el momento de cargar, Unity examinará la GPU que está utilizando y detectará automáticamente un valor de nivel; El valor predeterminado será el nivel más alto si la GPU no se detecta automáticamente. Puede anular este valor de nivel estableciendo Shader.globalShaderHardwareTier
, pero esto debe hacerse antes de cargar cualquier shaders que desee variar. Una vez que los shaders están cargados, habrán seleccionado su conjunto de variantes y este valor no tendrá ningún efecto. Un buen lugar para establecer esto sería en una escena de pre-carga antes de cargar su escena principal.
Tenga en cuenta que estos niveles de hardware shader no están relacionados con la configuración de calidad del reproductor, sino que se detectan únicamente a partir de la capacidad relativa de la GPU en la que se está ejecutando el reproductor.
Aparte de modificar su código shader para diferentes niveles de hardware, es posible que desee modificar las definiciones internas de la unidad (por ejemplo, puede que quiera forzar mapas de sombra en cascada en móviles). Puede encontrar detalles sobre esto en la documentación de UnityEditor.Rendering.PlatformShaderSettings , que proporciona una lista de las funciones actualmente soportadas para reemplazar por nivel. Utilice UnityEditor.Rendering.EditorGraphicsSettings.SetShaderSettingsForPlatform para ajustar las configuraciones shader por plataforma por-tier.
Tenga en cuenta que si PlatformShaderSetting
establecido en diferentes niveles no son idénticos, entonces variantes de nivel se generarán para el shader incluso si#pragma hardware_tier_variants
falta.