Planteamiento de la UI en Unity
Buenas tardes gente. Lo que voy a mostrar ahora es la metodología que he seguido para generar y utilizar los recursos gráficos que van a conformar mi juego. No digo que sea la panacea pero, bajo mi criterio, es la manera más óptima que conozco de hacer algo... ¿"decente"?
Intentaré que sea una lectura interesante ![:sweat_smile:](//mediavida.b-cdn.net/img/emoji/u/1f605.png)
Ligero vistazo al pasado
Mi planteamiento antes era 1 textura = 1 sprite, es decir, que si quería tener 3 botones rectangulares, me hacía mis 3 .PNGs correspondientes. Horrible, lo sé, casi todos tenemos algo oscuro en nuestro pasado
.
Cambio de tercio
Cierto tiempo después, cuano abro los proyectos a medias y veo que tenía la carpeta Sprites petada de imágenes de 40 - 200KB, es cuando comprendo lo fácil que era en su día cambiar en Photoshop, guardar con otro nombre, importar y seguir tirando. Ahora, algo más veterano, sigo las siguientes pautas:
- Buscar la figura más primitiva y reutilizable posible (cuadrados y círculos sobre todo)
- No generar ninguna textura de más de 128 x 128 si todo va a ser para la UI (peso innecesario)
- A la hora de elegir el color pensar siempre que blanco = lo que desees y que, salvo que necesite un contraste concreto, utilizar grises de relleno ofrece suficiente calidad
- Mantener un fondo transparente y procurar que el color nunca toque los bordes (suele notarse mucho el corte o los límites de una textura si le aplicamos cualquier efecto posterior)
Así es como genero algo similar a estas texturas:
![](http://i63.tinypic.com/svgsvo.png)
![](http://i68.tinypic.com/rk3tp4.png)
![](http://i66.tinypic.com/4ui3qq.png)
Resultado en proyecto:
Si ahora le meto estas texturas a uno de mis botones pues tengo lo siguiente:
(Poco sexy y se nota que el color llega hasta el borde)
Modificación de sprites en el editor de Unity
Estos son mis pasos desglosados al importar una imagen en Unity y meterla en la carpeta Assets/Resources/Sprites para que quede como quiero:
1 - Convertir el Sprite a tipo 2D UI
![](http://i67.tinypic.com/2i0vr4g.png)
![](http://i68.tinypic.com/t6tnbm.png)
2 - Editar el Sprite para hacerlo extensible
![](http://i63.tinypic.com/675elx.png)
3 - Otros cambios
*(No olvidar poner el Mesh Type como Full Rect para objetos que no sean de la UI, en otro caso se puede dejar como Tight)
Uso de los sprites en UI y en escena
Antes de conseguir el efecto deseado hay que hacer un último cambio en el componente de destino (SpriteRenderer, Image, loquesea):
![](http://i66.tinypic.com/20kds8k.png)
Y ahora sí, tenemos un resultado como este:
*(Nótese que solamente uso el color del editor, pero el botón muestra dos tonalidades por el borde y el relleno)
Conclusiones
- Este sistema me permite utilizar imágenes de menor resolución (32 x 32 en el ejemplo) pero buen resultado en pantallas que ocupan menos de 10KB
- Las imágenes son mucho más reutilizables al aprovechar el color de Unity como multiplicador
- Puedo aprovechar materiales para hacer cambios y transformaciones puntuales, que es más respetuoso con la memoria y no produce una sobrecarga de GPU sensible:
El gif se ve como la mierda pero no logro hacerlo mejor así que dejo una captura también:
![](http://i65.tinypic.com/1zzm5aq.png)
Muchísimas gracias por leerme, aquí os dejo el shader utilizado para el efecto de neón (aún en progreso para optimizar):
spoilerShader "Venat/Glow"
{
// Original here: https://gist.github.com/jzayed/d96f002b7eb149bf600c55ceb835da78
Properties
{
[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
_AlphaIntensity_Fade_1("_AlphaIntensity_Fade_1", Range(0.1, 2)) = 1
_MainTint("_MainTint", COLOR) = (1,1,1,1)
_AlphaIntensity_Fade_2("_AlphaIntensity_Fade_2", Range(0.1, 2)) = 1
_SecondaryTint("_SecondaryTint", COLOR) = (1,1,1,1)
_OperationBlend_Fade_1("_OperationBlend_Fade_1", Range(0, 1)) = 1
_SpriteFade("SpriteFade", Range(0, 1)) = 1.0
// required for UI.Mask
[HideInInspector]_StencilComp("Stencil Comparison", Float) = 8
[HideInInspector]_Stencil("Stencil ID", Float) = 0
[HideInInspector]_StencilOp("Stencil Operation", Float) = 0
[HideInInspector]_StencilWriteMask("Stencil Write Mask", Float) = 255
[HideInInspector]_StencilReadMask("Stencil Read Mask", Float) = 255
[HideInInspector]_ColorMask("Color Mask", Float) = 15
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"IgnoreProjector" = "true"
"RenderType" = "Transparent"
"PreviewType" = "Plane"
"CanUseSpriteAtlas" = "True"
}
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
// required for UI.Mask
Stencil
{
Ref[_Stencil]
Comp[_StencilComp]
Pass[_StencilOp]
ReadMask[_StencilReadMask]
WriteMask[_StencilWriteMask]
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float2 texcoord : TEXCOORD0;
float4 vertex : SV_POSITION;
float4 color : COLOR;
};
sampler2D _MainTex;
float _SpriteFade;
float _AlphaIntensity_Fade_1;
float4 _MainTint;
float _AlphaIntensity_Fade_2;
float4 _SecondaryTint;
float _OperationBlend_Fade_1;
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color;
return OUT;
}
float4 TintRGBA(float4 txt, float4 color)
{
float3 tint = dot(txt.rgb, float3(.222, .707, .071));
tint.rgb *= color.rgb;
txt.rgb = lerp(txt.rgb,tint.rgb,color.a);
return txt;
}
float4 OperationBlend(float4 origin, float4 overlay, float blend)
{
float4 o = origin;
o.a = overlay.a + origin.a * (1 - overlay.a);
o.rgb = (overlay.rgb * overlay.a + origin.rgb * origin.a * (1 - overlay.a)) / (o.a + 0.0000001);
o.a = saturate(o.a);
o = lerp(origin, o, blend);
return o;
}
float4 AlphaIntensity(float4 txt,float fade)
{
if (txt.a < 1) txt.a = lerp(0, txt.a, fade);
return txt;
}
float4 frag(v2f i) : COLOR
{
float4 _MainTex_1 = tex2D(_MainTex, i.texcoord);
float4 AlphaIntensity_1 = AlphaIntensity(_MainTex_1,_AlphaIntensity_Fade_1);
float4 TintRGBA_1 = TintRGBA(AlphaIntensity_1, _MainTint);
float4 _MainTex_2 = tex2D(_MainTex, i.texcoord);
float4 AlphaIntensity_2 = AlphaIntensity(_MainTex_2,_AlphaIntensity_Fade_2);
float4 TintRGBA_2 = TintRGBA(AlphaIntensity_2, _SecondaryTint);
float4 OperationBlend_1 = OperationBlend(TintRGBA_2, TintRGBA_1, _OperationBlend_Fade_1);
float4 FinalResult = OperationBlend_1;
FinalResult.rgb *= i.color.rgb;
FinalResult.a = FinalResult.a * _SpriteFade * i.color.a;
return FinalResult;
}
ENDCG
}
}
Fallback "Sprites/Default"
}