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

Unity3D Shader实现动态屏幕遮罩

程序员文章站 2023-08-17 20:45:13
屏幕可视范围跟随目标物体移动,可修改可视范围大小,边缘渐变大小、以及遮罩颜色,支持最高物体数量可在shader中修改,当前版本支持最多9个物体。 效果图如下: 控制...

屏幕可视范围跟随目标物体移动,可修改可视范围大小,边缘渐变大小、以及遮罩颜色,支持最高物体数量可在shader中修改,当前版本支持最多9个物体。

效果图如下:

Unity3D Shader实现动态屏幕遮罩

控制面板如下:

Unity3D Shader实现动态屏幕遮罩

shader代码如下:

shader "peter/darkeffect"
{
  properties
  {
    _maintex ("texture", 2d) = "white" {}
  }

  subshader
  {
    // no culling or depth
    cull off zwrite off ztest always

    pass
    {
      cgprogram
      #pragma vertex vert
      #pragma fragment frag

      #include "unitycg.cginc"

      //追踪物体最多个数
      #define itemsize 9

      struct appdata
      {
        float4 vertex : position;
        float2 uv : texcoord0;
      };

      struct v2f
      {
        float2 uv : texcoord0;
        float4 vertex : sv_position;
      };

      sampler2d _maintex;

      fixed4 _darkcolor;
      float _smoothlength;
      fixed _itemcnt;
      float4 _item[itemsize];

      v2f vert (appdata v)
      {
        v2f o;
        o.vertex = unityobjecttoclippos(v.vertex);
        o.uv = v.uv;
        return o;
      }

      fixed calcalpha(float4 vt, float4 pt)
      {
        if(pt.z < 0)
        {
          return 1;
        }

        float distpow2 = pow(vt.x - pt.x, 2) + pow(vt.y - pt.y, 2);
        float dist = (distpow2 > 0) ? sqrt(distpow2) : 0;

        float smoothlength = _smoothlength;
        if(smoothlength < 0)
        {
          smoothlength = 0;
        }

        float maxvalue = pt.z;
        float minvalue = pt.z - smoothlength;
        if(minvalue < 0)
        {
          minvalue = 0;
          smoothlength = pt.z;
        }

        if(dist <= minvalue)
        {
          return 0;
        }
        else if (dist > maxvalue)
        {
          return 1;
        }

        fixed retval = (dist - minvalue) / smoothlength;

        return retval;
      }

      fixed4 frag (v2f i) : sv_target
      {
        fixed alphaval = 1;
        fixed tmpval = 1;

        for(fixed index = 0; index < _itemcnt; ++index)
        {
          tmpval = calcalpha(i.vertex, _item[index]);
          if(tmpval < alphaval)
          {
            alphaval = tmpval;
          }
        }

        alphaval *= _darkcolor.a;

        return tex2d(_maintex, i.uv) * ( 1 - alphaval) + _darkcolor * alphaval;
      }

      endcg
    }
  }
}

c#调用代码如下:

using system.collections;
using system.collections.generic;
using unityengine;

[executeineditmode]
[requirecomponent(typeof(camera))]
public class darkeffect : monobehaviour
{
  [system.serializable]
  public class item
  {
    [serializefield]
    public transform target;

    [serializefield]
    public int radius;

    public vector3 getscreenposition(camera cam)
    {
      return cam.worldtoscreenpoint(target.position);
    }
  }

  //渐变像素数量
  public int _smoothlength = 20;
  //遮罩混合颜色
  public color _darkcolor = color.black;
  //目标物体
  public list<item> _items = new list<item>();

  protected material _mainmaterial;
  protected camera _maincamera;

  vector4[] _itemdatas;
  item _tmpitem;
  vector4 _tmpvt;
  vector3 _tmppos;
  int _tmpscreenheight;

  private void onenable()
  {
    _mainmaterial = new material(shader.find("peter/darkeffect"));
    _maincamera = getcomponent<camera>();
  }

  private void onrenderimage(rendertexture source, rendertexture destination)
  {

    if (_itemdatas == null || _itemdatas.length != _items.count)
    {
      _itemdatas = new vector4[_items.count];
    }

    _tmpscreenheight = screen.height;

    for (int i = 0; i < _items.count; i++)
    {
      _tmpitem = _items[i];
      _tmppos = _tmpitem.getscreenposition(_maincamera);

      _tmpvt.x = _tmppos.x;
      _tmpvt.y = _tmpscreenheight - _tmppos.y;
      _tmpvt.z = _tmpitem.radius;
      _tmpvt.w = 0;

      _itemdatas[i] = _tmpvt;
    }

    _mainmaterial.setint("_smoothlength", _smoothlength);
    _mainmaterial.setcolor("_darkcolor", _darkcolor);
    _mainmaterial.setint("_itemcnt", _itemdatas.length);
    _mainmaterial.setvectorarray("_item", _itemdatas);

    graphics.blit(source, destination, _mainmaterial);
  }
}

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