内容简介:前两个项目我一直用的是
前两个项目我一直用的是 UGUI研究院之Mask裁切UI粒子特效或者3D模型(十七) 做的裁切,但是实际开发中由循环列表中需要动态创建元素,每个新创建的元素都需要根据MaskRect的区域重新给Shader中指定,这个小小的隐患总是引起BUG。最近在做技术储备看到了Stencil一个东西,发现可以很好的代替原来裁切的方法,如下图所示,一共有2个裁切区域,同时裁切 UI 模型 粒子特效。
首先无论怎么做,我觉得需要一个脚本,只需要将模型 UI 特效挂在下面就可以全部裁切,运行期间动态添加不需要调用刷新方法。如下图所示,添加一个新的脚本RectMask3D来代替UGUI自带的RectMask2D
RectMask3D.cs 代码中的m_ID是为了区分裁切区域,大部分情况下裁切区域都是一致的,当然也不排除有重叠的情况,就像最上面的图一样。
using UnityEngine;
using UnityEngine.UI;
public class RectMask3D : RectMask2D
{
GameObject m_Mask3D = null;
[SerializeField] private Material m_Material;
[SerializeField] private int m_ID = 1;
public int id
{
get { return m_ID; }
set
{
if (value != m_ID)
{
m_ID = value;
Refresh();
}
}
}
#if UNITY_EDITOR
protected void OnValidate()
{
if (Application.isPlaying)
{
Refresh();
}
}
#endif
protected override void Awake()
{
base.Awake();
if (Application.isPlaying)
{
Refresh();
}
}
private void Refresh()
{
if (m_Mask3D == null)
{
m_Mask3D = GameObject.CreatePrimitive(PrimitiveType.Quad);
m_Mask3D.layer = LayerMask.NameToLayer("UI");
m_Mask3D.name = "Mask3D";
m_Mask3D.hideFlags = HideFlags.NotEditable;
m_Mask3D.GetComponent<MeshRenderer>().material = m_Material;
m_Mask3D.transform.SetParent(transform);
}
m_Mask3D.transform.localPosition = Vector3.zero;
m_Mask3D.transform.localScale = this.rectTransform.sizeDelta;
var material = m_Mask3D.GetComponent<Renderer>().material;
material.SetInt("_ID", m_ID);
}
}
#if UNITY_EDITOR
[UnityEditor.CustomEditor(typeof(RectMask3D))]
class SuperMask2DInspector : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
}
}
#endif
m_Material 是裁切3D所需要的,Shader中需要Stencil,为了避免每次添加一个新的裁切区域手动绑定,可以提前挂在Inspector面板上。
Mask.shader
Shader "Unlit/Mask"
{
Properties
{
[HideInInspector] _ID ("_ID",int) = 1
}
SubShader
{
Pass
{
Tags{ "RenderType" = "Opaque" "Queue" = "Geometry-1" }
ColorMask 0
ZWrite off
ZTest off
Stencil
{
Ref [_ID]
Comp always
Pass replace //替换相同ID模板像素
}
CGINCLUDE
struct appdata {
float4 vertex : POSITION;
};
struct v2f {
float4 vertex : SV_POSITION;
};
v2f vert(appdata v) {
v2f o;
return o;
}
half4 frag(v2f i) : SV_Target{
return 0;
}
ENDCG
}
}
}
接着就是Mask裁切的元素了,由于脚本继承了RectMask2D所以自带就可以裁切UI,需要处理的就是特效和模型,这里我用特效来举例,其他的做法都类似。给参与裁切的特效或者模型绑定RectImage3D脚本,(也可以不绑定,主要就是ID的值需要和RectMask3D里填的一致)。Type枚举可以设置永远显示(Always)或者被裁切(Equal)
RectItem3D.cs
using UnityEngine;
public class RectItem3D : MonoBehaviour
{
[SerializeField]
private int m_ID = 1;
[SerializeField]
private MaskType m_Type = MaskType.Always;
public MaskType type
{
get { return m_Type; }
set
{
if(value != m_Type)
{
m_Type = value;
Refresh();
}
}
}
#if UNITY_EDITOR
protected void OnValidate()
{
if (Application.isPlaying)
{
Refresh();
}
}
#endif
private void Awake()
{
Refresh();
}
void Refresh()
{
foreach (var render in GetComponentsInChildren<Renderer>(true))
{
var material = render.material;
material.SetInt("_ID", m_ID);
material.SetInt("_StencilComp", (int)m_Type);
}
}
public enum MaskType : byte
{
Always = 8,
Equal = 3
}
}
同样还需要给粒子或者模型绑定新的Shader,这里我就举个简单的粒子,将//—-add—-中间的代码添加到需要裁切的模型或者粒子的Shader中。
Shader "Unlit/Cube"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
//----add----
[HideInInspector] _ID ("_ID",int) = 1
[HideInInspector] _StencilComp ("_StencilComp",Float) = 8
//----add----
}
SubShader
{
Tags { "RenderType"="Opaque" "Queue"="Geometry"}
Pass
{
//----add----
Stencil
{
Ref [_ID]
Comp [_StencilComp]
Pass keep
}
//----add----
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.texcoord = v.texcoord;
return o;
}
fixed4 frag (v2f IN) : SV_Target
{
return tex2D(_MainTex, IN.texcoord);
}
ENDCG
}
}
}
这样需要裁切的粒子或者模型就可以保证只使用同一个Shader,运行时代码灵活的控制。
最后说说我的总结:
1.我还是建议模型使用RT,因为UI界面需要叠层挡住模型的现象,关于AlphaBlend或者显示不清楚的现象,可以参考我之前的文章 UGUI研究院之在UI上使用RenderTexture显示模型+AlphaBlend特效(二十五)
2.粒子特效适合使用这篇文章的方法,其实UI的粒子特效需要裁切的 无非就是 滑动列表中的图标上的转圈特效,配合SortOrder可以很好解决层级的问题。
3.RectTransform的Scale是(1,1,1) 但是模板需要添加scale的区域,我不知道怎么可以和RectTransform公用一个,所以我不得不创建一个和RectTransform区域相同的m_Mask3D,如果有知道的朋友欢迎告诉我。
- 本文固定链接: https://www.xuanyusong.com/archives/4562
- 转载请注明:雨松MOMO 于雨松MOMO程序研究院 发表
雨松MOMO提醒您:亲,如果您觉得本文不错,快快将这篇文章分享出去吧 。另外请点击网站顶部彩色广告或者捐赠支持本站发展,谢谢!
捐 赠 如果您愿意花20块钱请我喝一杯咖啡的话,请用手机扫描二维码即可通过支付宝直接向我捐款哦。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 深度高能粒子对撞追踪:Kaggle TrackML粒子追踪挑战赛亚军访谈
- 粒子滤波Matlab示例
- 粒子滤波Matlab示例
- 粒子系统的设计
- CAEmitterLayer 粒子动画
- 学习 PixiJS — 粒子效果
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript Patterns
Stoyan Stefanov / O'Reilly Media, Inc. / 2010-09-21 / USD 29.99
What's the best approach for developing an application with JavaScript? This book helps you answer that question with numerous JavaScript coding patterns and best practices. If you're an experienced d......一起来看看 《JavaScript Patterns》 这本书的介绍吧!