讥慰捷 发表于 4 天前

【URP】Unity3D物体遮罩的多种方案实现

【从UnityURP开始探索游戏渲染】专栏-直达
物体自身遮罩控制方案

基于Unity URP实现3D物体方向性动态遮罩

‌Shader核心功能‌:


[*]通过_MaskDirection向量定义遮罩方向
[*]使用_MaskProgress参数(0-1范围)控制显示比例
[*]基于顶点世界坐标在遮罩方向上的投影值进行裁剪(clip)
[*]兼容URP渲染管线标准结构
‌控制器特点‌:


[*]支持运行时动态调整遮罩方向和进度
[*]内置演示动画(旋转方向和进度波动)
[*]提供外部调用接口用于程序控制
[*]自动规范化方向向量确保计算准确
[*]DirectionalMask.shader
Shader "Custom/DirectionalMask"
{
    Properties
    {
      _MainTex("Texture", 2D) = "white" {}
      _MaskDirection("Mask Direction", Vector) = (1,0,0,0)
      _MaskProgress("Mask Progress", Range(0, 1)) = 0.5
    }

    SubShader
    {
      Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" }

      HLSLINCLUDE
      #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

      struct Attributes
      {
            float4 positionOS : POSITION;
            float2 uv : TEXCOORD0;
      };

      struct Varyings
      {
            float4 positionCS : SV_POSITION;
            float2 uv : TEXCOORD0;
            float3 positionWS : TEXCOORD1;
      };

      TEXTURE2D(_MainTex);
      SAMPLER(sampler_MainTex);
      float4 _MainTex_ST;
      float3 _MaskDirection;
      float _MaskProgress;

      Varyings Vert(Attributes input)
      {
            Varyings output;
            output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
            output.uv = TRANSFORM_TEX(input.uv, _MainTex);
            output.positionWS = TransformObjectToWorld(input.positionOS.xyz);
            return output;
      }

      half4 Frag(Varyings input) : SV_Target
      {
            half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv);
            
            // 计算物体顶点在遮罩方向上的投影比例
            float dotProduct = dot(normalize(input.positionWS), normalize(_MaskDirection));
            float normalizedDot = (dotProduct + 1) * 0.5; // 映射到0-1范围
            
            // 根据进度参数裁剪
            clip(normalizedDot - _MaskProgress);
            
            return col;
      }
      ENDHLSL

      Pass
      {
            HLSLPROGRAM
            #pragma vertex Vert
            #pragma fragment Frag
            ENDHLSL
      }
    }
}
[*]DirectionalMaskController.cs
using UnityEngine;

public class DirectionalMaskController : MonoBehaviour
{
    private Renderer _targetRenderer;
    private Vector3 _maskDirection = Vector3.right;
    public float maskProgress = 0.5f;
    private float _rotationSpeed = 30f;
    private float _progressSpeed = 0.2f;

    private Material _material;
    private static readonly int MaskDirection = Shader.PropertyToID("_MaskDirection");
    private static readonly int MaskProgress = Shader.PropertyToID("_MaskProgress");

    void Start()
    {
      _material = _targetRenderer.material;
      UpdateShaderParams();
    }

    void Update()
    {
      // 动态旋转遮罩方向
      _maskDirection = Quaternion.Euler(0, _rotationSpeed * Time.deltaTime, 0) * _maskDirection;
      
      // 动态调整遮罩进度
      maskProgress = Mathf.PingPong(Time.time * _progressSpeed, 1f);
      
      UpdateShaderParams();
    }

    private void UpdateShaderParams()
    {
      _material.SetVector(MaskDirection, _maskDirection.normalized);
      _material.SetFloat(MaskProgress, maskProgress);
    }

    // 外部调用接口
    public void SetMaskDirection(Vector3 newDirection)
    {
      _maskDirection = newDirection.normalized;
      UpdateShaderParams();
    }

    public void SetMaskProgress(float progress)
    {
      maskProgress = Mathf.Clamp01(progress);
      UpdateShaderParams();
    }
}
‌扩展:


[*]可添加_MaskSharpness参数控制边缘过渡柔和度
[*]结合Stencil Buffer实现多物体遮罩叠加
[*]通过AnimationCurve控制进度变化曲线
该方案相比基础遮罩实现增加了方向向量参数和动态进度控制,通过顶点投影计算实现方向性裁剪效果。控制器脚本支持运行时动态调整所有参数,并保持与Shader的高效数据交互。
‌HLSL Shader实现‌(基于透明度遮罩):


[*]unity_urp遮罩shader
Shader "Custom/TransparentColorURP" {
    Properties {
      _Color("Color Tint", Color) = (1,1,1,1)
      _MainTex("Main Tex", 2D) = "white" {}
      _AlphaScale("Alpha Scale", Range(0, 1)) = 0.5
    }
    SubShader {
      Pass {
            ZWrite On
            ColorMask 0
      }
      Pass {
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            // HLSL代码...
      }
    }
}
‌控制脚本‌:


[*]unity_遮罩控制脚本
public class MaskController : MonoBehaviour {
    public Renderer targetRenderer;
    public float maskProgress = 0.5f;

    void Update() {
      targetRenderer.material.SetFloat("_AlphaScale",
            Mathf.PingPong(Time.time, 1f));
    }
}
模板测试实现方案

‌模板Shader核心代码‌:

‌RenderFeature配置要点‌:


[*]需创建URP Renderer Feature
[*]设置Layer Mask匹配目标层级
[*]在后处理前添加Pass
三、其他实现方式

‌多Pass深度测试法‌:

Shader "Custom/StencilMask"
{
    SubShader
    {
      Tags { "RenderType"="Opaque" "Queue"="Geometry-100" }
      
      Pass
      {
            ColorMask 0
            ZWrite Off
            
            Stencil {
                Ref 1
                Comp Always
                Pass Replace
            }
      }
    }
}‌UGUI Mask混合方案‌:


[*]使用RectTransform确定遮罩区域
[*]通过第二摄像机渲染3D物体
[*]结合UI Mask组件控制显示范围
‌RenderTexture遮罩‌:


[*]创建临时RenderTexture
[*]使用特定Shader渲染遮罩通道
[*]通过后期处理合成最终效果
四、方案对比

方案类型优点适用场景模板测试高性能,精确控制角色轮廓/固定形状遮罩多Pass无需额外纹理简单遮挡提示UGUI混合可结合UI系统HUD元素遮罩RenderTexture效果最灵活复杂动态遮罩模板测试适合需要精确控制像素级显示的场景,而多Pass方案更适合简单的遮挡提示效果
【从UnityURP开始探索游戏渲染】专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 【URP】Unity3D物体遮罩的多种方案实现