其中,float c = step(a, b)是Shader内置的API函数,当b大于a时,返回0,剩下返回1,对4个值分布判断,只有都在区域内时,最后的rectClip才为1,否则为0,最后返回的顶点颜色也就成了全透明,视觉上就是被裁剪了。Shader中少用if,多用自带的api,由于GPU的计算方式不同于CPU,if这种是个高消耗的计算操作。
有些低端GPU上,使用step函数可能会有精度问题,这个时候也可以直接用if
1 2 3 4 5 6 7
float inRect = 1.0; if (i.pos.x < _MinX) inRect = 0.0; if (i.pos.x > _MaxX) inRect = 0.0; if (i.pos.y < _MinY) inRect = 0.0; if (i.pos.y > _MaxY) inRect = 0.0;
publicclassClipParticleSystem : MonoBehaviour { public Mask mask; public Material[] materials;
privatevoidLateUpdate() { Clip(); }
privatevoidClip() { var corner = new Vector3[4]; var rect = (RectTransform) mask.transform; rect.GetWorldCorners(corner); foreach (var mat in materials) { mat.SetFloat("_MinX", corner[0].x); mat.SetFloat("_MinY", corner[0].y); mat.SetFloat("_MaxX", corner[2].x); mat.SetFloat("_MaxY", corner[2].y); } } }
publicvoidStart() { _mpb = new MaterialPropertyBlock();
// Try to initialize mask _mask = GetComponentInParent<Mask>(); if (_mask) _maskRect = _mask.GetComponent<RectTransform>();
_renderers = GetComponentsInChildren<Renderer>();
// Initial clip set to infinite to prevent disappearance if mask not found UpdateMaterialClip(-99999, -99999, 99999, 99999); _lastCorners = new Vector4(-99999, -99999, 99999, 99999);
privatevoidSetClip() { // Robustness: Try to find mask if missing if (_mask == null) { _mask = GetComponentInParent<Mask>(); if (_mask) { _maskRect = _mask.GetComponent<RectTransform>(); } }
// Get clipping area _isMask = false;
// Check for mask existence (ignoring enabled state for logical clipping purposes) if (_mask && _mask.gameObject.activeInHierarchy) { _maskRect.GetWorldCorners(_corners); _isMask = true; }
if (_mpb == null) _mpb = new MaterialPropertyBlock();
// Only clear the specific properties we are managing to avoid wiping other MPB data if any _mpb.SetFloat(MinXId, minX); _mpb.SetFloat(MinYId, minY); _mpb.SetFloat(MaxXId, maxX); _mpb.SetFloat(MaxYId, maxY);
if (_renderers != null) { foreach (var t in _renderers) { if (t != null) { t.SetPropertyBlock(_mpb); } } } } }