
正文
Unity NGUI 多个UIPanel对粒子的剪裁
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
之前写过一篇单个 UIPanel 对粒子的裁剪,地址是:https://www.cnblogs.com/jietian331/p/5075487.html
但项目中有时会遇到多个UIPanel,如下面问题,UISprite 被剪裁了,但粒子未被剪裁:

转载请注明出处:https://www.cnblogs.com/jietian331/p/10938837.html
这时解决问题的思路是,找出所有的有剪裁功能的 UIPanel,并求出它们剪裁区域的交集然后传到shader中,效果如下:

代码如下:
using System.Collections.Generic;
using UnityEngine; namespace Modules.UI
{
// 对子节点下所有的粒子和模型进行剪裁,且支持多个 UIPanel
public class EffectClip : MonoBehaviour
{
List<Material> m_materials;
List<UIPanel> m_uiPanels;
UIRoot m_uiRoot; #region Properties UIRoot ObjUIRoot
{
get
{
if (!m_uiRoot)
m_uiRoot = GetComponentInParent<UIRoot>();
return m_uiRoot;
}
} // 找到所有粒子,模型的material
List<Material> Materials
{
get
{
if (m_materials == null)
{
m_materials = new List<Material>(); // particle system 的剪裁
var particleSystems = GetComponentsInChildren<ParticleSystem>();
for (int i = , j = particleSystems.Length; i < j; i++)
{
var ps = particleSystems[i];
var mat = ps.GetComponent<Renderer>().material;
string shaderName = mat.shader.name + ""; // 所用shader,重写一份带剪裁功能的
Shader shader = Shader.Find(shaderName);
if (shader)
{
m_materials.Add(mat);
mat.shader = shader;
}
else
{
Debug.LogError("Shader not found, name: " + shaderName);
}
} // mesh 的剪裁
var renders = GetComponentsInChildren<MeshRenderer>();
for (int i = , j = renders.Length; i < j; i++)
{
var ps = renders[i];
var mat = ps.material;
string shaderName = mat.shader.name + ""; // 所用shader,重写一份带剪裁功能的
Shader shader = Shader.Find(shaderName);
if (shader)
{
m_materials.Add(mat);
mat.shader = shader;
}
else
{
Debug.LogError("Shader not found, name: " + shaderName);
}
}
}
return m_materials;
}
} List<UIPanel> Panels
{
get
{
if (m_uiPanels == null)
{
// 获取所有开启剪裁的 UIPanel
m_uiPanels = new List<UIPanel>();
UIPanel[] panels = GetComponentsInParent<UIPanel>();
for (int i = ; i < panels.Length; i++)
{
UIPanel p = panels[i];
if (p && p.clipping == UIDrawCall.Clipping.SoftClip)
{
m_uiPanels.Add(p);
}
}
}
return m_uiPanels;
}
} #endregion void Update()
{
var mats = Materials;
if (mats != null && mats.Count > )
{
for (int i = ; i < m_materials.Count; i++)
{
Vector4 area = CalcClipArea();
m_materials[i].SetVector("_Area", area);
}
}
} // 整合所有 UIPanel 的剪裁区域
Vector4 CalcClipArea()
{
var panels = Panels;
float x = float.MinValue, y = float.MinValue, z = float.MaxValue, w = float.MaxValue; // 求所有 UIPanel 剪裁区域的交集
for (int i = ; i < panels.Count; i++)
{
UIPanel p = panels[i];
Vector4 area = CalcClipArea(p); // 求交集啊
if (area.x > x)
x = area.x;
if (area.y > y)
y = area.y;
if (area.z < z)
z = area.z;
if (area.w < w)
w = area.w;
} return new Vector4(x, y, z, w);
} // 计算单个 UIPanel 的剪裁区域
Vector4 CalcClipArea(UIPanel p)
{
float h = ;
float temp = h / ObjUIRoot.activeHeight;
Vector3 offsetV3 = new Vector3()
{
x = p.clipOffset.x * temp,
y = p.clipOffset.y * temp,
};
Vector3 worldPos = p.transform.position + offsetV3;
Vector4 clipRegion = p.finalClipRegion;
Vector4 nguiArea = new Vector4()
{
x = -clipRegion.z / ,
y = -clipRegion.w / ,
z = clipRegion.z / ,
w = clipRegion.w /
}; return new Vector4()
{
x = worldPos.x + nguiArea.x * temp,
y = worldPos.y + nguiArea.y * temp,
z = worldPos.x + nguiArea.z * temp,
w = worldPos.y + nguiArea.w * temp
};
} }
}
EffectClip







