Unity NGUI 多个UIPanel对粒子的剪裁

之前写过一篇单个 UIPanel 对粒子的裁剪,地址是:https://www.cnblogs.com/jietian331/p/5075487.html

但项目中有时会遇到多个UIPanel,如下面问题,UISprite 被剪裁了,但粒子未被剪裁:

 

 

 

转载请注明出处:https://www.cnblogs.com/jietian331/p/10938837.html

这时解决问题的思路是,找出所有的有剪裁功能的 UIPanel,并求出它们剪裁区域的交集然后传到shader中,效果如下:

 

  

代码如下:

  1 using System.Collections.Generic;
  2 using UnityEngine;
  3 
  4 namespace Modules.UI
  5 {
  6     // 对子节点下所有的粒子和模型进行剪裁,且支持多个 UIPanel
  7     public class EffectClip : MonoBehaviour
  8     {
  9         List<Material> m_materials;
 10         List<UIPanel> m_uiPanels;
 11         UIRoot m_uiRoot;
 12 
 13 
 14         #region Properties
 15 
 16         UIRoot ObjUIRoot
 17         {
 18             get
 19             {
 20                 if (!m_uiRoot)
 21                     m_uiRoot = GetComponentInParent<UIRoot>();
 22                 return m_uiRoot;
 23             }
 24         }
 25 
 26         // 找到所有粒子,模型的material
 27         List<Material> Materials
 28         {
 29             get
 30             {
 31                 if (m_materials == null)
 32                 {
 33                     m_materials = new List<Material>();
 34 
 35                     // particle system 的剪裁
 36                     var particleSystems = GetComponentsInChildren<ParticleSystem>();
 37                     for (int i = 0, j = particleSystems.Length; i < j; i++)
 38                     {
 39                         var ps = particleSystems[i];
 40                         var mat = ps.GetComponent<Renderer>().material;
 41                         string shaderName = mat.shader.name + " 1";     // 所用shader,重写一份带剪裁功能的
 42                         Shader shader = Shader.Find(shaderName);
 43                         if (shader)
 44                         {
 45                             m_materials.Add(mat);
 46                             mat.shader = shader;
 47                         }
 48                         else
 49                         {
 50                             Debug.LogError("Shader not found, name: " + shaderName);
 51                         }
 52                     }
 53 
 54                     // mesh 的剪裁
 55                     var renders = GetComponentsInChildren<MeshRenderer>();
 56                     for (int i = 0, j = renders.Length; i < j; i++)
 57                     {
 58                         var ps = renders[i];
 59                         var mat = ps.material;
 60                         string shaderName = mat.shader.name + " 1";     // 所用shader,重写一份带剪裁功能的
 61                         Shader shader = Shader.Find(shaderName);
 62                         if (shader)
 63                         {
 64                             m_materials.Add(mat);
 65                             mat.shader = shader;
 66                         }
 67                         else
 68                         {
 69                             Debug.LogError("Shader not found, name: " + shaderName);
 70                         }
 71                     }
 72                 }
 73                 return m_materials;
 74             }
 75         }
 76 
 77         List<UIPanel> Panels
 78         {
 79             get
 80             {
 81                 if (m_uiPanels == null)
 82                 {
 83                     // 获取所有开启剪裁的 UIPanel
 84                     m_uiPanels = new List<UIPanel>();
 85                     UIPanel[] panels = GetComponentsInParent<UIPanel>();
 86                     for (int i = 0; i < panels.Length; i++)
 87                     {
 88                         UIPanel p = panels[i];
 89                         if (p && p.clipping == UIDrawCall.Clipping.SoftClip)
 90                         {
 91                             m_uiPanels.Add(p);
 92                         }
 93                     }
 94                 }
 95                 return m_uiPanels;
 96             }
 97         }
 98 
 99         #endregion
100 
101 
102         void Update()
103         {
104             var mats = Materials;
105             if (mats != null && mats.Count > 0)
106             {
107                 for (int i = 0; i < m_materials.Count; i++)
108                 {
109                     Vector4 area = CalcClipArea();
110                     m_materials[i].SetVector("_Area", area);
111                 }
112             }
113         }
114 
115         // 整合所有 UIPanel 的剪裁区域
116         Vector4 CalcClipArea()
117         {
118             var panels = Panels;
119             float x = float.MinValue, y = float.MinValue, z = float.MaxValue, w = float.MaxValue;
120 
121             // 求所有 UIPanel 剪裁区域的交集
122             for (int i = 0; i < panels.Count; i++)
123             {
124                 UIPanel p = panels[i];
125                 Vector4 area = CalcClipArea(p);
126 
127                 // 求交集啊
128                 if (area.x > x)
129                     x = area.x;
130                 if (area.y > y)
131                     y = area.y;
132                 if (area.z < z)
133                     z = area.z;
134                 if (area.w < w)
135                     w = area.w;
136             }
137 
138             return new Vector4(x, y, z, w);
139         }
140 
141         // 计算单个 UIPanel 的剪裁区域
142         Vector4 CalcClipArea(UIPanel p)
143         {
144             float h = 2;
145             float temp = h / ObjUIRoot.activeHeight;
146             Vector3 offsetV3 = new Vector3()
147             {
148                 x = p.clipOffset.x * temp,
149                 y = p.clipOffset.y * temp,
150             };
151             Vector3 worldPos = p.transform.position + offsetV3;
152             Vector4 clipRegion = p.finalClipRegion;
153             Vector4 nguiArea = new Vector4()
154             {
155                 x = -clipRegion.z / 2,
156                 y = -clipRegion.w / 2,
157                 z = clipRegion.z / 2,
158                 w = clipRegion.w / 2
159             };
160 
161             return new Vector4()
162             {
163                 x = worldPos.x + nguiArea.x * temp,
164                 y = worldPos.y + nguiArea.y * temp,
165                 z = worldPos.x + nguiArea.z * temp,
166                 w = worldPos.y + nguiArea.w * temp
167             };
168         }
169 
170 
171     }
172 }
EffectClip

 

posted @ 2019-05-28 17:29  孤独の巡礼  阅读(533)  评论(0编辑  收藏  举报