[Unity3D]Shader编程之动态屏幕遮罩

版权声明:本文为博主原创文章,转载请注明 http://blog.csdn.net/u012741077 https://blog.csdn.net/u012741077/article/details/78425834

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

效果图如下:
这里写图片描述

控制面板如下:
这里写图片描述

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);
    }
}

这里写图片描述

猜你喜欢

转载自blog.csdn.net/u012741077/article/details/78425834