欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Unity Shader实现新手引导遮罩镂空效果

程序员文章站 2023-11-14 17:07:16
这两天实现了下新手引导需要的遮罩镂空shader效果,记录一下。1、圆形镂空shader代码://计算片元世界坐标和目标中心位置的距离float dis = distance(in.worldposi...

这两天实现了下新手引导需要的遮罩镂空shader效果,记录一下。

1、圆形镂空shader代码:    

//计算片元世界坐标和目标中心位置的距离
float dis = distance(in.worldposition.xy, _center.xy);
//过滤掉距离小于(半径-过渡范围)的片元
clip(dis - (_radius - _transitionrange));
//优化if条件判断,如果距离小于半径则执行下一步,等于if(dis < _radius)
fixed tmp = step(dis, _radius);
//计算过渡范围内的alpha值
color.a *= (1 - tmp) + tmp * (dis - (_radius - _transitionrange)) / _transitionrange;

效果:忽略渐变的蒙版,随便找的图片

Unity Shader实现新手引导遮罩镂空效果

2、椭圆镂空shader代码:

//计算x轴方向距离
float disx = distance(in.worldposition.x, _center.x);
//计算y轴方向距离
float disy = distance(in.worldposition.y, _center.y);
//运用椭圆方程计算片元的alpha值,_ellipse为椭圆系数
fixed factor = clamp(pow(abs(disx / _width), _ellipse) + pow(abs(disy / _height), _ellipse), 0.0, 1.0);
//优化if条件判断
fixed tmp = step(factor, 1.0f);
//赋值椭圆外或椭圆内的alpha值
color.a *= (1 - tmp) + tmp * factor;

效果:

Unity Shader实现新手引导遮罩镂空效果

3、圆形目标位置聚合动画shader代码:

//_starttime为效果开始时间点,unity中对应赋值material.setfloat("_starttime", time.timesincelevelload);
fixed processtime = _time.y - _starttime;
//判断shader执行时长是否超过_totaltime
clip(_totaltime - processtime);
//优化if条件判断
fixed tmp = step(processtime, _reducetime);
//计算当前时间点的圆形镂空半径
float curradius = (1 - tmp) * _radius + tmp * (_maxradius - (_maxradius - _radius) * processtime / _reducetime);
float dis = distance(in.worldposition.xy, _center.xy);
//抛弃距离小于当前圆形镂空半径的片元
clip(dis - curradius);

效果:不知道为啥上传上来就有问题了,正常是没问题的

Unity Shader实现新手引导遮罩镂空效果

整个shader源码,在unity ugui 自带default shader基础上添加:

// unity built-in shader source. copyright (c) 2016 unity technologies. mit license (see license.txt)

shader "ui/default_mask"
{
  properties
  {
    [perrendererdata] _maintex ("sprite texture", 2d) = "white" {}
    _color ("tint", color) = (1,1,1,1)

    _stencilcomp ("stencil comparison", float) = 8
    _stencil ("stencil id", float) = 0
    _stencilop ("stencil operation", float) = 0
    _stencilwritemask ("stencil write mask", float) = 255
    _stencilreadmask ("stencil read mask", float) = 255

    _colormask ("color mask", float) = 15

    [toggle(unity_ui_alphaclip)] _useuialphaclip ("use alpha clip", float) = 0
 //-------------------add----------------------
 _center("center", vector) = (0, 0, 0, 0)
 _radius("radius", range(0,1000)) = 1000 // sliders
 _transitionrange("transition range", range(0, 100)) = 10
 _width("width", float) = 1
 _height("height", float) = 1
 _ellipse("ellipse", float) = 4
 _reducetime("reducetime", float) = 1
 _totaltime("totaltime", float) = 1
 _starttime("starttime", float) = 0
 _maxradius("maxradius", float) = 1500
 [keywordenum(round, ellipse, dynamic_round)] _roundmode("mask mode", float) = 0
 //-------------------add----------------------
  }

  subshader
  {
    tags
    {
      "queue"="transparent"
      "ignoreprojector"="true"
      "rendertype"="transparent"
      "previewtype"="plane"
      "canusespriteatlas"="true"
    }

    stencil
    {
      ref [_stencil]
      comp [_stencilcomp]
      pass [_stencilop]
      readmask [_stencilreadmask]
      writemask [_stencilwritemask]
    }

    cull off
    lighting off
    zwrite off
    ztest [unity_guiztestmode]
    blend srcalpha oneminussrcalpha
    colormask [_colormask]

    pass
    {
      name "default"
    cgprogram
      #pragma vertex vert
      #pragma fragment frag
      #pragma target 2.0

      #include "unitycg.cginc"
      #include "unityui.cginc"

      #pragma multi_compile __ unity_ui_clip_rect
      #pragma multi_compile __ unity_ui_alphaclip
  #pragma multi_compile _roundmode_round _roundmode_ellipse _roundmode_dynamic_round

      struct appdata_t
      {
        float4 vertex  : position;
        float4 color  : color;
        float2 texcoord : texcoord0;
        unity_vertex_input_instance_id
      };

      struct v2f
      {
        float4 vertex  : sv_position;
        fixed4 color  : color;
        float2 texcoord : texcoord0;
        float4 worldposition : texcoord1;
        unity_vertex_output_stereo
      };

      fixed4 _color;
      fixed4 _texturesampleadd;
      float4 _cliprect;
  //-------------------add----------------------
  half _radius;
  float2 _center;
  half _transitionrange;
  half _width;
  half _height;
  half _ellipse;
  fixed _reducetime;
  half _totaltime;
  float _starttime;
  half _maxradius;

  //-------------------add----------------------

      v2f vert(appdata_t v)
      {
        v2f out;
        unity_setup_instance_id(v);
        unity_initialize_vertex_output_stereo(out);
        out.worldposition = v.vertex;
        out.vertex = unityobjecttoclippos(out.worldposition);

        out.texcoord = v.texcoord;

        out.color = v.color * _color;
        return out;
      }

      sampler2d _maintex;

      fixed4 frag(v2f in) : sv_target
      {
        half4 color = (tex2d(_maintex, in.texcoord) + _texturesampleadd) * in.color;

        #ifdef unity_ui_clip_rect
        color.a *= unityget2dclipping(in.worldposition.xy, _cliprect);
        #endif

        #ifdef unity_ui_alphaclip
        clip (color.a - 0.001);
        #endif

  //-------------------add----------------------
#ifdef _roundmode_round
  //计算片元世界坐标和目标中心位置的距离
  float dis = distance(in.worldposition.xy, _center.xy);
  //过滤掉距离小于(半径-过渡范围)的片元
  clip(dis - (_radius - _transitionrange));
  //优化if条件判断,如果距离小于半径则执行下一步,等于if(dis < _radius)
  fixed tmp = step(dis, _radius);
  //计算过渡范围内的alpha值
  color.a *= (1 - tmp) + tmp * (dis - (_radius - _transitionrange)) / _transitionrange;
#elif _roundmode_ellipse
  //计算x轴方向距离
  float disx = distance(in.worldposition.x, _center.x);
  //计算y轴方向距离
  float disy = distance(in.worldposition.y, _center.y);
  //运用椭圆方程计算片元的alpha值,_ellipse为椭圆系数
  fixed factor = clamp(pow(abs(disx / _width), _ellipse) + pow(abs(disy / _height), _ellipse), 0.0, 1.0);
  //优化if条件判断
  fixed tmp = step(factor, 1.0f);
  //赋值椭圆外或椭圆内的alpha值
  color.a *= (1 - tmp) + tmp * factor;
#else
  //_starttime为效果开始时间点,unity中对应赋值material.setfloat("_starttime", time.timesincelevelload);
  fixed processtime = _time.y - _starttime;
  //判断shader执行时长是否超过_totaltime
  clip(_totaltime - processtime);
  //优化if条件判断
  fixed tmp = step(processtime, _reducetime);
  //计算当前时间点的圆形镂空半径
  float curradius = (1 - tmp) * _radius + tmp * (_maxradius - (_maxradius - _radius) * processtime / _reducetime);
  float dis = distance(in.worldposition.xy, _center.xy);
  //抛弃距离小于当前圆形镂空半径的片元
  clip(dis - curradius);
#endif
  //-------------------add----------------------
        return color;
      }
    endcg
    }
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。