NGUI学习笔记(七):UIPanel剪裁粒子效果
2017-07-30 15:13
2081 查看
一.简介
关于这部分的学习说起来真的有点绕,个人感觉这个属于进阶级别的开发问题了,但又属于不得不会的内容,于是硬着头皮搞下去!
二.UISprite的材质
长期以来,一直搞不懂怎样设置UISprite的材质,UGUI的Sprite材质很easy,在Image组件上可以轻松找到:
NGUI的在哪呢?
找到使用的图集:
终于惊喜的发现,这个图集上有Material,其实这个应该是我一直以来没有注意的地方。
检视一下Shader资源:
为什么会有这么多相似的Shader呢?
三.UIDrawCall
观察下来,这个脚本控制着所有NGUI渲染相关的Shader替换。
当物体将要被渲染时,NGUI首先会更新一次UI所有使用的材质:
更新材质的时候需要创建材质,新材质的Shader会根据剪裁次数(ClipCount)来选择不同版本的Shader,比如剪裁1次则使用 “Hidden/Unlit/Transparent Colored 1”
四.剪裁区域参数的设置
UIPanel的剪裁设置有4种,这里研究的是最常用的SoftClip
当选择了Soft Clip后可以设置剪裁区域的大小、中心、边缘的柔和度。
这些参数的效果会在UIDraw中的被调用,每次OnWillRenderObject函数都会调用SetClipping函数设置剪裁区域:
SetClipping函数将计算好的参数设置到实际用到的Shader中。
看一下剪裁1次所使用Shader的顶点与片元着色器的实现:
在顶点着色器的最后一步
这个是把被剪裁的UI Mesh的模型空间的顶点先按照剪裁区域的长宽进行缩放,然后按照剪裁区域的中心点进行平移,将模型顶点转换到Panel的剪裁区域的局部空间下,并将其“归一化”。
在片元着色器的第一步
这个将用来判断该顶点的x、y分量是否处于剪裁区域[-1,1]内。
后面正式用到
如果factor的任意x、y分量小于0(即不在剪裁区域内),那么输出颜色的透明度alpha将会为0,从而达到剪裁的效果。
五.NGUI DrawCall的基本统计
将UIDraw最上面的宏定义打开:
保存后,在编辑器界面稍等片刻,会发现这些:
原来,NGUI会将所有能够一同提交渲染的UIMesh合并成了一个网格,而每个合并的网格就对应着1个NGUI DrawCall。
同时合并后的网格的缩放大小与UIPanel相同,所以UIPanel下的UI Mesh的模型顶点和Panel实际上处在同一坐标系下。
【NGUI内置shader 的计算方式也验证了这点】
滑动列表合并后的Mesh:
【注意右下角】
六.正式剪裁粒子
七.应用
八.参考链接
http://blog.csdn.net/tkokof1/article/details/52089289
九.完整脚本
http://pan.baidu.com/s/1kU8o9vx
关于这部分的学习说起来真的有点绕,个人感觉这个属于进阶级别的开发问题了,但又属于不得不会的内容,于是硬着头皮搞下去!
二.UISprite的材质
长期以来,一直搞不懂怎样设置UISprite的材质,UGUI的Sprite材质很easy,在Image组件上可以轻松找到:
NGUI的在哪呢?
找到使用的图集:
终于惊喜的发现,这个图集上有Material,其实这个应该是我一直以来没有注意的地方。
检视一下Shader资源:
为什么会有这么多相似的Shader呢?
三.UIDrawCall
观察下来,这个脚本控制着所有NGUI渲染相关的Shader替换。
当物体将要被渲染时,NGUI首先会更新一次UI所有使用的材质:
更新材质的时候需要创建材质,新材质的Shader会根据剪裁次数(ClipCount)来选择不同版本的Shader,比如剪裁1次则使用 “Hidden/Unlit/Transparent Colored 1”
四.剪裁区域参数的设置
UIPanel的剪裁设置有4种,这里研究的是最常用的SoftClip
当选择了Soft Clip后可以设置剪裁区域的大小、中心、边缘的柔和度。
这些参数的效果会在UIDraw中的被调用,每次OnWillRenderObject函数都会调用SetClipping函数设置剪裁区域:
SetClipping函数将计算好的参数设置到实际用到的Shader中。
看一下剪裁1次所使用Shader的顶点与片元着色器的实现:
在顶点着色器的最后一步
o.worldPos = v.vertex.xy * _ClipRange0.zw + _ClipRange0.xy;
这个是把被剪裁的UI Mesh的模型空间的顶点先按照剪裁区域的长宽进行缩放,然后按照剪裁区域的中心点进行平移,将模型顶点转换到Panel的剪裁区域的局部空间下,并将其“归一化”。
在片元着色器的第一步
float2 factor = (float2(1.0, 1.0) - abs(IN.worldPos)) * _ClipArgs0;
这个将用来判断该顶点的x、y分量是否处于剪裁区域[-1,1]内。
后面正式用到
col.a *= clamp( min(factor.x, factor.y), 0.0, 1.0);
如果factor的任意x、y分量小于0(即不在剪裁区域内),那么输出颜色的透明度alpha将会为0,从而达到剪裁的效果。
五.NGUI DrawCall的基本统计
将UIDraw最上面的宏定义打开:
保存后,在编辑器界面稍等片刻,会发现这些:
原来,NGUI会将所有能够一同提交渲染的UIMesh合并成了一个网格,而每个合并的网格就对应着1个NGUI DrawCall。
同时合并后的网格的缩放大小与UIPanel相同,所以UIPanel下的UI Mesh的模型顶点和Panel实际上处在同一坐标系下。
【NGUI内置shader 的计算方式也验证了这点】
滑动列表合并后的Mesh:
【注意右下角】
六.正式剪裁粒子
using UnityEngine; using System.Collections; [ExecuteInEditMode] [RequireComponent(typeof(ParticleSystemRenderer))] public class UIParticle : MonoBehaviour { private UIPanel panel; private ParticleSystemRenderer pRenderer; private Material dyMaterial; private UIWidget coverWidget; // Use this for initialization void Start () { //找到这个粒子系统最近的父节点的UIPanel panel = GetComponentInParent<UIPanel> (); //找到这个粒子系统的Renderer pRenderer = GetComponent<ParticleSystemRenderer> (); dyMaterial = new Material (Shader.Find ("Hidden/Unlit/Transparent Colored 1")) { //提升其渲染队列至4000 renderQueue = 4000, //使用原始material的texture mainTexture = pRenderer.sharedMaterial.mainTexture }; pRenderer.material = dyMaterial; /* 为什么不采用下面这种做法? * pRenderer.material.renderQueue = 4000; * 这样的话,Unity会帮助我们自动创建动态材质 * 如此,该动态引用无法得到,很难判断 * Destroy时也不好操作 */ } void OnWillRenderObject() { if (panel.hasClipping) { //裁剪区域 Vector4 cr = panel.drawCallClipRange; //裁剪边儿的柔和度 Vector2 soft = panel.clipSoftness; Vector2 sharpenss = new Vector2 (1000.0f, 1000.0f); if (soft.x > 0f) sharpenss.x = cr.z / soft.x; if (soft.y > 0f) sharpenss.y = cr.w / soft.y; //经过测试粒子系统产生的Mesh是不受UIPanel缩放比影响的 //所以要将其缩放比记录下来 float scale = panel.transform.lossyScale.x; //粒子系统的顶点坐标系相对于panel会有一定的偏移,所以要将其position记录下来 Vector3 position = panel.transform.position; Debug.Assert (dyMaterial != null, aa65 "dyMaterial 创建失败!!!!!!"); //坐标变化的顺序:缩放、旋转、平移,这里不考虑粒子系统的旋转 dyMaterial.SetVector ( Shader.PropertyToID ("_ClipRange0"), new Vector4 ( -cr.x / cr.z - position.x/scale / cr.z, -cr.y / cr.w - position.y/scale / cr.w, 1f / cr.z / scale, 1f / cr.w / scale ) ); dyMaterial.SetVector(Shader.PropertyToID("_ClipArgs0"),new Vector4(sharpenss.x,sharpenss.y,0,1)); } } void OnDestroy() { DestroyImmediate (dyMaterial); dyMaterial = null; } }
七.应用
八.参考链接
http://blog.csdn.net/tkokof1/article/details/52089289
九.完整脚本
http://pan.baidu.com/s/1kU8o9vx
相关文章推荐
- Unity NGUI UIPanel下对粒子或自定义Mesh的剪裁
- Unity NGUI UIPanel下对粒子的剪裁
- cocos2dx实现转盘旋转外加粒子效果
- Unity 粒子海洋效果实现
- android: qq 5.0 demo学习笔记(主 粒子爆炸效果+ViewDragHelper)
- [js高手之路]html5 canvas动画教程 - 边界判断与小球粒子模拟喷泉,散弹效果
- Android实现粒子爆炸效果的方法
- [Maya] 粒子系统之物体消散效果
- cocos2dx粒子效果出现黑块 解决办法
- 黑洞效果的粒子背景效果
- Android&nbsp;粒子&nbsp;3D效果
- Unity3D学习记录1——粒子效果受WindZone影响
- 粒子效果 CCParticleSystem 编码的实现
- Flash/Flex学习笔记(24):粒子效果
- Cocos2d-x 粒子系统----实现下雪效果
- 插件新渲染的粒子效果
- android使用粒子动画实现炊烟袅袅的效果
- 粒子系统-烟花效果的实现
- 粒子效果
- Cocos2d-JS 粒子效果