Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / Unity: Как сделать alpha blending mask в UI?

Unity: Как сделать alpha blending mask в UI?

AlerrПостоялецwww23 фев. 201612:55#0
Привет всем!
Делаю текст на UI канвасе, пытаюсь сделать так, чтобы текст плавно исчезал.
В UI unity есть замечательная штука "Mask"& Как выяснилось она не умеет блендить.
Хотел отнаследовать свой скрипт от Mask и с ним поработать, но он не доступен в MonoDevelop.
Как можно блендить UI элементы?)
k119_55524Постоялецwww23 фев. 201613:34#1
Регулировка прозрачности(алфа канал) цвета текста не?
AlerrПостоялецwww23 фев. 201614:29#2
Не-не-не. В том-то и фишка, что текст должен быть не везде прозрачен.
Вот так должно это выглядеть:
Безымянный | Unity: Как сделать alpha blending mask в UI?

Скрипт Mask делает либо alpha = 1 либо 0.

AlerrПостоялецwww23 фев. 201615:40#3
Ситуация пока такая:
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.
Как достучаться до пикселей текста? Через буффер глубины? Пока я не имел опыта с такого рода махинациями)

AlerrПостоялецwww23 фев. 201616:48#4
В сети, на сколько я понял, многие интересовались этим эффектом, но unity пока не реализовало его, то есть нет готового скрипта так что вставил и все заработало. Неужто никаких идей по этому поводу?
alexzzzzПостоялецwww23 фев. 201617:12#5
У компонента Text тоже есть материал, в который можно вставить любой шейдер.
AlerrПостоялецwww24 фев. 201610:19#6
Перепробовал что мог попробовать. Непонятно как этот материал использовать. Я не спец в шейдерах, и не понимаю как UI Text работает.
Похоже, что каждая буква имеет свои вершины. Но тогда шейдер будет работать относительно вершин этой буквы.
Хорошо, можно попробовать как-то передать в шейдер текста вершины UI Image.
И это уже хорошо. Я верно мыслю?
AlerrПостоялецwww26 фев. 201619:23#7
Вообщем, пришла такая мысль: в материал передать текстуру по которй альфу настраиваем.
Вообщем-то идея норм, вот код:
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?
alexzzzzПостоялецwww26 фев. 201623:27#8
С шейдером действительно оказалось довольно заморочено. Сходу не сообразил, как перевести входящие в шейдер координаты вершин (заданные в локальной системе координат родительского 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);
  }
}
alexzzzzПостоялецwww27 фев. 20160:28#9
Получилось сделать настоящую маску:

mask | Unity: Как сделать alpha blending mask в UI?

Для этого потребовались:

1. Скрипт, который пересчитывает координаты прямоугольника с текстом в uv-координаты для маски и сохраняет результат в дополнительный канал uv, который можно будет читать из шейдера.

+ Показать

2. Шейдер, накладывающий маску. Чуть модифицировал стандартный GUI/Text Shader.

+ Показать
AlerrПостоялецwww27 фев. 20169:16#10
Что-то странное творит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 ()...
  }

AlerrПостоялецwww27 фев. 201610:06#11
Я не особо силен в ModifyMesh, пока не разобрался как он работает и как из него выудить VertexHelper. Похоже этот метод устарел и его исключили: http://forum.unity3d.com/threads/basemesheffect-that-removes-elements.365783/
alexzzzzПостоялецwww27 фев. 201615:05#12
Обнови Unity.
AlerrПостоялецwww27 фев. 201622:03#13
alexzzzz
Спасибо! Очень помог)

/ Форум / Программирование игр / Графика

Тема в архиве.

2001—2018 © GameDev.ru — Разработка игр