zt3ff3n 发表于 2022-11-21 14:52

unity Mask遮罩效果

Unity

官方2DMask                                                               

在场景创建个UI-Panel,再创建个Image子物体                                                               
给Panel-Add Component添加Mask                                                               
则Image在Panel范围内的显示,其余不显示                                                               
Show Mask Graphic显示遮罩物体                                                               
试了下2D有效3D无效                                                                                                                        屏幕遮罩效果

参考https://zhuanlan.zhihu.com/p/138568019                                                               
后处理效果,原理是把源像素和遮罩图形像素相乘                                                               
在Camera的OnRenderImage方法里进行处理                                                               
shader,MaskEffect                                                               
Properties                                                               
{                                                               
    _MainTex("Texture", 2D) = "white" { }                                                               
}                                                               
Cull Off ZWrite Off ZTest Always                                                               
Tags { "Queue" = "Transparent" }                                                               
                                                               
struct appdata                                                               
{                                                               
    float4 vertex : POSITION;                                                               
    float2 uv : TEXCOORD0;                                                               
};                                                               
                                                               
struct v2f                                                               
{                                                               
    float2 uv : TEXCOORD0;                                                               
    float4 vertex : SV_POSITION;                                                               
    float4 srcPos : TEXCOORD1;                                                               
};                                                               
                                                               
v2f vert(appdata v)                                                               
{                                                               
    v2f o;                                                               
    o.vertex = UnityObjectToClipPos(v.vertex);                                                               
    o.uv = v.uv;                                                               
    o.srcPos = ComputeScreenPos(o.vertex);                                                               
    return o;                                                               
}                                                               
                                                               
sampler2D _MainTex;                                                               
float2 _Pos;                                                               
float _Size;                                                               
float _EdgeBlurLength;                                                               
// 创建圆                                                               
fixed3 createCircle(float2 pos, float radius, float2 uv)                                                               
{                                                               
    //当前像素到中心点的距离                                                               
    float dis = distance(pos, uv);                                                               
    //smoothstep 平滑过渡                                                               
    float col = smoothstep(radius + _EdgeBlurLength, radius, dis);                                                               
    return fixed3(col, col, col);                                                               
}                                                               
fixed4 frag(v2f i) : SV_Target                                                               
{                                                               
    // 根据屏幕比例缩放                                                               
    float2 scale = float2(_ScreenParams.x / _ScreenParams.y, 1);                                                               
                                                               
    fixed4 col = tex2D(_MainTex, i.uv);                                                               
    fixed3 mask = createCircle(_Pos * scale, _Size, i.uv * scale);                                                               
                                                               
    return col * fixed4(mask, 1.0);                                                               
}                                                                                                                                C#,Mask                                                               
public class Mask : PostEffectsBase                                                               
这个PostEffectsBase的源码网上一搜很多人都在用,没法判断最早的作者是谁                                                               
using UnityEngine;                                                               
                                                               
/// <summary>                                                               
/// 屏幕后处理效果基类                                                               
/// </summary>                                                               
                                                               
                                                               
public class PostEffectsBase : MonoBehaviour                                                               
{                                                               
    private Camera mainCamera;                                                               
    public Camera MainCamera { get { return mainCamera = mainCamera == null ? GetComponent<Camera>() : mainCamera; } }                                                               
                                                               
    public Shader targetShader;                                                               
    private Material targetMaterial = null;                                                               
    public Material TargetMaterial { get { return CheckShaderAndCreateMaterial(targetShader,ref targetMaterial); } }                                                               
                                                               
    /// <summary>                                                               
    /// 检测资源,如果不支持,关闭脚本活动                                                               
    /// </summary>                                                               
    protected void Start()                                                               
    {                                                               
      if (CheckSupport() == false)                                                               
            enabled = false;                                                               
    }                                                               
                                                               
    /// <summary>                                                               
    /// 检测平台是否支持图片渲染                                                               
    /// </summary>                                                               
    /// <returns></returns>                                                               
    protected bool CheckSupport()                                                               
    {                                                               
      if (SystemInfo.supportsImageEffects == false)                                                               
      {                                                               
            Debug.LogWarning("This platform does not support image effects or render textures.");                                                               
            return false;                                                               
      }                                                               
      return true;                                                               
    }                                                               
                                                               
    /// <summary>                                                               
    /// 检测需要渲染的Shader可用性,然后返回使用了该shader的material                                                               
    /// </summary>                                                               
    /// <param name="shader">指定shader</param>                                                               
    /// <param name="material">创建的材质</param>                                                               
    /// <returns>得到指定shader的材质</returns>                                                               
    protected Material CheckShaderAndCreateMaterial(Shader shader, ref Material material)                                                               
    {                                                               
      if (shader == null || !shader.isSupported)                                                               
            return null;                                                               
                                                               
      if (material && material.shader == shader)                                                               
            return material;                                                               
                                                               
      material = new Material(shader);                                                               
      material.hideFlags = HideFlags.DontSave;                                                               
      return material;                                                               
    }                                                               
}                                                                C#                                                       
// shader                                                               
public Shader myShader;                                                               
//材质                                                                
private Material mat = null;                                                               
public Material material                                                               
{                                                               
    get                                                               
    {                                                               
      // 检查着色器并创建材质                                                               
      mat = CheckShaderAndCreateMaterial(myShader, ref mat);                                                               
      return mat;                                                               
    }                                                               
}                                                               
                                                               
// 遮罩大小                                                               
                                                               
public float size = 5.0f;                                                               
// 边缘模糊程度                                                               
                                                               
public float edgeBlurLength = 0.05f;                                                               
// 遮罩中心位置                                                               
private Vector2 pos = new Vector4(0.5f, 0.5f);                                                               
                                                               
void Start()                                                               
{                                                               
    //找到对应的Shader文件,可以注释掉直接拖动                                                                
    myShader = Shader.Find("lcl/screenEffect/MaskEffect");                                                               
}                                                               
void OnRenderImage(RenderTexture source, RenderTexture destination)                                                               
{                                                               
    if (material)                                                               
    {                                                               
      // 把鼠标坐标传递给shader                                                               
      material.SetVector("_Pos", pos);                                                               
      // 遮罩大小                                                               
      material.SetFloat("_Size", size);                                                               
      // 模糊程度                                                               
      material.SetFloat("_EdgeBlurLength", edgeBlurLength);                                                               
      // 渲染                                                               
      Graphics.Blit(source, destination, material);                                                               
    }                                                               
    else                                                               
    {                                                               
      Graphics.Blit(source, destination);                                                               
    }                                                               
}                                                                                                                3D Mask

参考魔镜https://zhuanlan.zhihu.com/p/573367729                                                               
小记录:2盏灯Frame Debugger里会渲染2次,而且会造成无法合批batched                                                               
创建一个Plane以及几个Cube。                                                               
创建Plane的ASE-Surface以及Material,Cube同理                                                               
镜子Shader-Plane                                                               
Stencil Buffer=true                                                               
设置Reference=1,Comparison=Always,Pass Front=Replace                                                               
隐藏Plane,取消Blend Mode的Color Mask的RGBA                                                               
拉近后,镜子又显示出来了,解决方式:                                                               
调整渲染顺序:RenderQueue改成1999                                                               
关闭深度写入:Depth-ZWrite Mode=Off                                                                                                                        场景shader实现mask遮罩效果                                                               
Stencil Buffer=true                                                               
设置Reference=1,Comparison=Equal                                                               
只能看到镜子里的物体,镜子外的看不到                                                                                                                                原理:
输出合并阶段的模板测试Stencil Test->深度测试Depth Test                                                               
模板缓冲区Stencil buffer,01的集合矩阵                                                               
开启Stencil Buffer后,设置模板值Reference及规则                                                               
通过模板测试后可渲染到屏幕上(反之则无),且更新到模板缓冲区。                                                                                                                        Plane                                                               
开启Stencil Buffer没效果                                                               
设置Reference=1,Pass Front=Replace,则他前面的物体会被隐藏,原理是这个1替换掉了其他的0                                                               
设置ZWrite Mode=Off后Plane变透明                                                               
取消Blend Mode的Color Mask的RGBA后Plane消失                                                                                                                        Cube                                                               
开启Stencil Buffer没效果                                                               
设置Reference=1,Comparison=Greater后Plane前后的被隐藏,其他正常显示                                                               
设置Reference=1,Comparison=Equal后Plane前后的被显示,其他被隐藏                                                                                                        Render Queue值2500后为半透明,前为不透明,值小先渲染                                                                                                               
Frame Debugger                                                               
UpdateDepthTexture画深度图                                                               
Drawing绘制                                                               
Camera.ImageEffetc后处理                                                                                                                               
魔镜的做法是用天空盒罩住场景,设置总是通过模板测试,来覆盖魔镜背后的现实物体
页: [1]
查看完整版本: unity Mask遮罩效果