Привет всем!
Делаю текст на UI канвасе, пытаюсь сделать так, чтобы текст плавно исчезал.
В UI unity есть замечательная штука "Mask"& Как выяснилось она не умеет блендить.
Хотел отнаследовать свой скрипт от Mask и с ним поработать, но он не доступен в MonoDevelop.
Как можно блендить UI элементы?)
Регулировка прозрачности(алфа канал) цвета текста не?
Не-не-не. В том-то и фишка, что текст должен быть не везде прозрачен.
Вот так должно это выглядеть:
Скрипт Mask делает либо alpha = 1 либо 0.
Ситуация пока такая:
UI состоит из канваса в котором дочерний обьект Foo содержит Image с моим материалом.
Foo содержит в себе game object с Text:
Canvas-
|-Foo-(Image component)
|-GameObject (Text component)
Получилось изменять картинку, которая находится в Foo с помощью alpha-маски, которая передается в материал и вешается на Image. Тут достаточно все просто:
Cull Off Lighting Off //ZWrite off //ZTest [unity_GUIZTestMode] ZTest Always//GEqual ZWrite off Fog { Mode Off } Blend SrcAlpha OneMinusSrcAlpha ColorMask [_ColorMask] Tags { "Queue"="Overlay" "IgnoreProjector"="True" "RenderType"="Transparent" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata{ float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; float2 depth : TEXCOORD1; //float4 color : COLOR; }; struct v2f{ float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; float2 depth : TEXCOORD1; //float4 color : COLOR; }; uniform sampler2D _MainTex; uniform sampler2D _MaskTex; float4 _MainTex_ST; v2f vert (appdata v){ v2f o; o.vertex = mul( UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX( v.uv, _MainTex); UNITY_TRANSFER_DEPTH( o.depth); return o; } fixed4 frag ( v2f i) : SV_Target{ fixed4 col = tex2D( _MainTex, i.uv); float alpha = tex2D( _MaskTex, i.uv); col.a *= alpha; float2 depth = i.depth; UNITY_OUTPUT_DEPTH( depth); return col; } ENDCG }
Что хотел бы достичь, не знаю это так делается или нет:
как-то получить доступ к пикселям текста, который должен отрисоваться и сблендить их с маской, которая в материале Foo.
Как достучаться до пикселей текста? Через буффер глубины? Пока я не имел опыта с такого рода махинациями)
В сети, на сколько я понял, многие интересовались этим эффектом, но unity пока не реализовало его, то есть нет готового скрипта так что вставил и все заработало. Неужто никаких идей по этому поводу?
У компонента Text тоже есть материал, в который можно вставить любой шейдер.
Перепробовал что мог попробовать. Непонятно как этот материал использовать. Я не спец в шейдерах, и не понимаю как UI Text работает.
Похоже, что каждая буква имеет свои вершины. Но тогда шейдер будет работать относительно вершин этой буквы.
Хорошо, можно попробовать как-то передать в шейдер текста вершины UI Image.
И это уже хорошо. Я верно мыслю?
Вообщем, пришла такая мысль: в материал передать текстуру по которй альфу настраиваем.
Вообщем-то идея норм, вот код:
Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 3.0 #include "UnityCG.cginc" struct appdata{ float2 uv : TEXCOORD0;// tex float4 vertex : SV_POSITION; // pos } ; struct v2f{ float2 uv : TEXCOORD0; float4 vertex : SV_POSITION;// WPOS float4 scrPos; } ; uniform sampler2D _MainTex; uniform sampler2D _MaskTex; // (беру эти данные из RectTransform) uniform float _BackgroundParamMinY;// нижняя граница картинки с маской uniform float _BackgroundParamH;// высотка маски fixed4 _Color; v2f vert (appdata v){ v2f o; o.uv = v.uv;//ComputeScreenPos(v.uv); o.vertex = mul( UNITY_MATRIX_MVP, v.vertex);// o.scrPos = ComputeScreenPos( o.vertex); return o; } fixed4 frag ( v2f i, float4 sp:WPOS) : COLOR{ fixed4 col = tex2D( _MainTex, i.uv); col.rgb = ( 1.0-col.rgb)*_Color.rgb; sp.x = 0; sp.y = ( sp.y - _BackgroundParamMinY) / _BackgroundParamH;// uv float alpha = tex2D( _MaskTex, sp.xy); col.a *= alpha; return col; } ENDCG }
sp:WPOS - нашел в сети, вроде как позиция пиуселя в мире.
Беда в том, что на вращение этот код не расчитан + считает все в координатах экрана.
Как правильно получать sp.xy?
С шейдером действительно оказалось довольно заморочено. Сходу не сообразил, как перевести входящие в шейдер координаты вершин (заданные в локальной системе координат родительского Canvas) в uv-координаты для маски. Не уверен, что в шейдере для этого есть вся нужная информация. Если нету, то нужен скрипт, который скормит шейдеру эту информацию.
Но раз всё равно нужен скрипт, то можно обойтись и без шейдера. Так, например:
using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class VerticalTextGradient : BaseMeshEffect { public Color topColor = new Color(1, 1, 1, 0); public Color bottomColor = new Color( 1, 1, 1, 1); private List<UIVertex> vertices = new List<UIVertex>( ); private Vector3[] corners = new Vector3[4]; // lower-left, upper-left, upper-right, lower-right public override void ModifyMesh( VertexHelper vh) { if ( IsActive( ) == false || vh.currentVertCount == 0) { return; } graphic.rectTransform.GetLocalCorners( corners); var top = corners[1].y; var bottom = corners[0].y; vh.GetUIVertexStream( vertices); for ( int i = 0; i < vertices.Count; i++) { var uiVertex = vertices[i]; var t = Mathf.InverseLerp( bottom, top, uiVertex.position.y); uiVertex.color *= Color.Lerp( bottomColor, topColor, t); vertices[i] = uiVertex; } vh.Clear( ); vh.AddUIVertexTriangleStream( vertices); } }
Получилось сделать настоящую маску:
Для этого потребовались:
1. Скрипт, который пересчитывает координаты прямоугольника с текстом в uv-координаты для маски и сохраняет результат в дополнительный канал uv, который можно будет читать из шейдера.
2. Шейдер, накладывающий маску. Чуть модифицировал стандартный GUI/Text Shader.
Что-то странное творитcя.
ModifyMesh(VertexHelper vh) этой функции нет в BaseMeshEffect:
public abstract class BaseMeshEffect : UIBehaviour, IMeshModifier
{
//
// Properties
//
protected Graphic graphic{...
//
// Methods
//
public abstract void ModifyMesh (Mesh mesh);
protected override void OnDidApplyAnimationProperties ()...
protected override void OnDisable ()...
protected override void OnEnable ()...
protected override void OnValidate ()...
}
Я не особо силен в ModifyMesh, пока не разобрался как он работает и как из него выудить VertexHelper. Похоже этот метод устарел и его исключили: http://forum.unity3d.com/threads/basemesheffect-that-removes-elements.365783/
Обнови Unity.
alexzzzz
Спасибо! Очень помог)
Тема в архиве.