NGUI裁剪粒子的实现,完全仿照原有的NGUI SoftClip逻辑思路,可多层裁剪

来源:互联网 发布:国外网络安全设备品牌 编辑:程序博客网 时间:2024/05/22 06:15

参照http://blog.csdn.net/tkokof1/article/details/52107736 这一篇博客

但是他只实现了单层panel的裁剪,虽然他的算法和NGUI的思路是一致的,但是由于传入Shader的值不同,所以不太好移植成多层Panel裁剪。我重新对他的思路进行整理了,并且将值统一为NGUI的规则,传入的值都用_ClipRange0和_ClipArgs0表示。首先是C#端代码

    void UpdateClip(UIPanel panel)    {        if (mCam == null) return;        UIPanel currentPanel = panel;        Vector4 cr = new Vector4();        //计算距离最近的父Panel的中心点 这个点存着 如果有多层的话 就可以用panelCenter,这样不需要重复计算了        var panelWorldCorners1 = panel.worldCorners;        var leftBottom1 = mCam.WorldToViewportPoint(panelWorldCorners1[0]);        var topRight1 = mCam.WorldToViewportPoint(panelWorldCorners1[2]);        var panelCenter = Vector3.Lerp(leftBottom1, topRight1, 0.5f);        //遍历所有的父Panel(所以支持嵌套的Soft Clip)        for (int i = 0; currentPanel != null;)        {            //如果父Panel节点有裁剪            if (currentPanel.hasClipping)            {                //这个里面计算裁剪范围和父Panel和当前DrawCall所属的Panel的角度                float angle = 0f;                //Vector4 cr = currentPanel.drawCallClipRange;                // 与NGUI逻辑不同的第一处 这里将坐标统一为ViewPort坐标系                var panelWorldCorners = currentPanel.worldCorners;                var leftBottom = mCam.WorldToViewportPoint(panelWorldCorners[0]);                var topRight = mCam.WorldToViewportPoint(panelWorldCorners[2]);                var center = Vector3.Lerp(leftBottom, topRight, 0.5f);                cr.x = panelCenter.x;                cr.y = panelCenter.y;                cr.z = (topRight.x - leftBottom.x) / 2;                cr.w = (topRight.y - leftBottom.y) / 2;                //如果有多重Soft Clip的话 就会走到这里                // Clipping regions past the first one need additional math                if (currentPanel != panel)                {                    //这里的计算方式其实是完全一样的 只不过计算的值统一为ViewPort坐标系了                    Vector3 pos = panelCenter - center;                    //Vector3 pos = currentPanel.cachedTransform.InverseTransformPoint(panel.cachedTransform.position);                    cr.x -= pos.x;                    cr.y -= pos.y;                    Vector3 v0 = panel.cachedTransform.rotation.eulerAngles;                    Vector3 v1 = currentPanel.cachedTransform.rotation.eulerAngles;                    Vector3 diff = v1 - v0;                    //其实这个函数就是 把角度限制在-180和180之间                    diff.x = NGUIMath.WrapAngle(diff.x);                    diff.y = NGUIMath.WrapAngle(diff.y);                    diff.z = NGUIMath.WrapAngle(diff.z);                    if (Mathf.Abs(diff.x) > 0.001f || Mathf.Abs(diff.y) > 0.001f)                        Debug.LogWarning("Panel can only be clipped properly if X and Y rotation is left at 0", panel);                    //因为是界面 所以角度是平面的 只有Z是有效角度                    angle = diff.z;                }                var soft = currentPanel.clipSoftness;                var sharpness = new Vector2(1000.0f, 1000.0f);                if (soft.x > 0f)                {                    sharpness.x = panel.baseClipRegion.z / soft.x;                }                if (soft.y > 0f)                {                    sharpness.y = panel.baseClipRegion.w / soft.y;                }                //这里就是真正设置裁剪的地方了,我们看看这里的各个参数的意义吧。                //如果只是单层Soft Clip的话                // i = 0,                // cr就是this.panel的 drawCallClipRange,而这个drawCallClipRange的各个参数意义是这样的: x:中心点X坐标 y:中心点Y坐标 z:panel width的一半, w:panel height的一半                // currentPanel.clipSoftness 软裁剪设置的渐变边缘                // angle 与父Panel的角度 如果 是单层shader的话,这个角度是0(而且shader里面也不会用到)                // Pass the clipping parameters to the shader                for (int j = 0; j < _materials.Count; ++j)                    SetClipping(_materials[j], i, cr, sharpness, angle);                ++i;            }            currentPanel = currentPanel.parentPanel;        }    }    void SetClipping(Material material, int index, Vector4 cr, Vector2 soft, float angle)    {        angle *= -Mathf.Deg2Rad;        if (index < ClipRange.Length)        {            material.SetVector(ClipRange[index], new Vector4(-cr.x / cr.z, -cr.y / cr.w, 1f / cr.z, 1f / cr.w));            material.SetVector(ClipArgs[index], new Vector4(soft.x, soft.y, Mathf.Sin(angle), Mathf.Cos(angle)));        }    }

具体的算法注释上写了 应该和NGUI的代码90%是相似的 ,分析可以参照我的上一篇SoftClip分析:http://blog.csdn.net/nxshow/article/details/72864419


接下来是一层裁剪panel的时候用到的Shader

Shader "Custom/Particles/Additive 1"{Properties{_TintColor("Tint Color", Color) = (0.5,0.5,0.5,0.5)_MainTex("Particle Texture", 2D) = "white" {}}Category{Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }Blend SrcAlpha OneCull Off Lighting Off ZWrite Off Fog{ Color(0,0,0,0) }SubShader{Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"sampler2D _MainTex;fixed4 _TintColor;float4 _ClipRange0 = float4(0.0, 0.0, 1.0, 1.0);float2 _ClipArgs0 = float2(1000.0, 1000.0);struct appdata_t {float4 vertex : POSITION;fixed4 color : COLOR;float2 texcoord : TEXCOORD0;};struct v2f {float4 vertex : SV_POSITION;fixed4 color : COLOR;float2 texcoord : TEXCOORD0;float2 worldPos : TEXCOORD1;};float4 _MainTex_ST;v2f vert(appdata_t v){v2f o;o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);o.color = v.color;o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);// 统一成ViewPort坐标系float2 clipSpace = o.vertex.xy / o.vertex.w;clipSpace = (clipSpace.xy + 1) * 0.5;o.worldPos = clipSpace * _ClipRange0.zw + _ClipRange0.xy;return o;}fixed4 frag(v2f i) : SV_Target{fixed4 c = 2.0f * i.color * _TintColor * tex2D(_MainTex, i.texcoord);// Softness factor  float2 factor = (float2(1, 1) - abs(i.worldPos)) * _ClipArgs0.xy;c.a *= clamp(min(factor.x, factor.y), 0.0, 1.0);return c;}ENDCG}}}}

只改了一个地方,就是将坐标统一成ViewPort坐标系


接下来是有两层Panel裁剪的Shader,一样的

Shader "Custom/Particles/Additive 2"{Properties{_TintColor("Tint Color", Color) = (0.5,0.5,0.5,0.5)_MainTex("Particle Texture", 2D) = "white" {}}Category{Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }Blend SrcAlpha OneCull Off Lighting Off ZWrite Off Fog{ Color(0,0,0,0) }SubShader{Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"sampler2D _MainTex;fixed4 _TintColor;float4 _ClipRange0 = float4(0.0, 0.0, 1.0, 1.0);float4 _ClipArgs0 = float4(1000.0, 1000.0, 0.0, 1.0);float4 _ClipRange1 = float4(0.0, 0.0, 1.0, 1.0);float4 _ClipArgs1 = float4(1000.0, 1000.0, 0.0, 1.0);struct appdata_t {float4 vertex : POSITION;fixed4 color : COLOR;float2 texcoord : TEXCOORD0;};struct v2f {float4 vertex : SV_POSITION;fixed4 color : COLOR;float2 texcoord : TEXCOORD0;float4 worldPos : TEXCOORD1;};float4 _MainTex_ST;float2 Rotate(float2 v, float2 rot){float2 ret;ret.x = v.x * rot.y - v.y * rot.x;ret.y = v.x * rot.x + v.y * rot.y;return ret;}v2f vert(appdata_t v){v2f o;o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);o.color = v.color;o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);// 统一成ViewPort坐标系float2 clipSpace = o.vertex.xy / o.vertex.w;clipSpace = (clipSpace.xy + 1) * 0.5;o.worldPos.xy = clipSpace * _ClipRange0.zw + _ClipRange0.xy;o.worldPos.zw = Rotate(clipSpace, _ClipArgs1.zw) * _ClipRange1.zw + _ClipRange1.xy;return o;}fixed4 frag(v2f i) : SV_Target{fixed4 c = 2.0f * i.color * _TintColor * tex2D(_MainTex, i.texcoord);// First clip regionfloat2 factor = (float2(1.0, 1.0) - abs(i.worldPos.xy)) * _ClipArgs0.xy;float f = min(factor.x, factor.y);// Second clip regionfactor = (float2(1.0, 1.0) - abs(i.worldPos.zw)) * _ClipArgs1.xy;f = min(f, min(factor.x, factor.y));c.a *= clamp(f, 0.0, 1.0);return c;}ENDCG}}}}