NGUI Panel裁剪、层级实现原理
目录:NGUI源码学习
Unity渲染顺序:https://www.jianshu.com/p/0341f0ab9020
1.NGUI渲染顺序。
上面的文章详细的分析了unity中camera depth -> sorting layer -> sorting order -> RenderQueue -> Z等属性是如何影响渲染的,大家有疑问可以参考这篇文章。
在NGUI中,层级主要是通过sorting order 和 RenderQueue实现的。
源码如下,NGUI默认使用RenderQueue设置显示层级,这里的renderQueue是根据panel+widget的depth递增(+1)得出来的。
for (int i = 0; i < drawCalls.Count; ++i) { UIDrawCall dc = drawCalls[i]; dc.renderQueue = (renderQueue == RenderQueue.Explicit) ? startingRenderQueue : startingRenderQueue + i; dc.alwaysOnScreen = alwaysOnScreen && (mClipping == UIDrawCall.Clipping.None || mClipping == UIDrawCall.Clipping.ConstrainButDontClip); dc.sortingOrder = useSortingOrder ? ((mSortingOrder == 0 && renderQueue == RenderQueue.Automatic) ? sortOrder : mSortingOrder) : 0; dc.sortingLayerName = useSortingOrder ? mSortingLayerName : null; dc.clipTexture = mClipTexture; }
2.NGUI裁剪。
UIPanel的裁剪主要是通过名字为Hidden/Unlit/Transparent Colored x的shader实现的,x小等于3
看不懂这个shader的可以参考https://gameinstitute.qq.com/community/detail/128082
3.简单实现NGUI的层级和裁剪功能。
1.生成两个mesh,设置不同的depth和贴图,便于显示层级关系。
与上一篇的区别在于设置了NGUI用于裁剪shader,以及mRenderer.sortingOrder和裁剪属性。
public class NguiObjTest: MonoBehaviour { private Texture mMeshMatTex; private MeshFilter mFilter; private MeshRenderer mRenderer; private Material mDynamicMat; private Vector4 drawingDimensions = new Vector4(0, 0, 200, 400); private int mDepth = 0; private NguiTest mTest; //颜色测试 Color mColor = Color.grey; Color mGradientTop = Color.green; Color mGradientBottom = Color.red; public void Create(Texture tex, int depth, NguiTest panel) { //transform.localScale = Vector3.one * 0.2f; transform.localPosition = new Vector3(depth*20, depth*20 , 0); mMeshMatTex = tex; mDepth = depth; mTest = panel; CreateMesh(); SetMeshRender(); } private void CreateMesh() { Vector3[] newVertices; Vector2[] newUV; GetUITextureVertices(out newVertices, out newUV); int indexCount = (newVertices.Length >> 1) * 3; //四个顶点构成两个三角形,共2*3 = 6个顶点 int[] newTriangles = new int[indexCount]; int index = 0; for (int i = 0; i < newVertices.Length; i += 4) { newTriangles[index++] = i; newTriangles[index++] = i + 1; newTriangles[index++] = i + 2; newTriangles[index++] = i + 2; newTriangles[index++] = i + 3; newTriangles[index++] = i; } if (mFilter == null) mFilter = gameObject.GetComponent<MeshFilter>(); if (mFilter == null) mFilter = gameObject.AddComponent<MeshFilter>(); Mesh mesh = new Mesh(); mesh.hideFlags = HideFlags.DontSave; // Do some calculations... mesh.vertices = newVertices; mesh.uv = newUV; mesh.triangles = newTriangles; mesh.SetColors(SetColor()); mesh.name = "NGUI Test"; mFilter.mesh = mesh; } /// <summary> /// 显示一个Texture,顶点数4 /// </summary> /// <param name="vert"></param> /// <param name="uvs"></param> private void GetUITextureVertices(out Vector3[] vert, out Vector2[] uvs) { Vector4 v = drawingDimensions; vert = new []{new Vector3(v.x,v.y), new Vector3(v.x,v.w), new Vector3(v.z,v.w),new Vector3(v.z,v.y), }; uvs = new []{new Vector2(0,0), new Vector2(0,1),new Vector2(1,1),new Vector2(1,0), }; } /// <summary> /// 通过Hidden/Unlit/Transparent Colored 1 shader实现裁剪。_ClipRange0裁剪区域,虚边_ClipArgs0(边缘渐隐效果) /// mDynamicMat.renderQueue\mRenderer.sortingOrder都可以修改显示层级 /// </summary> private void SetMeshRender() { if (mRenderer == null) mRenderer = gameObject.GetComponent<MeshRenderer>(); if (mRenderer == null) mRenderer = gameObject.AddComponent<MeshRenderer>(); Shader shader = Shader.Find("Hidden/Unlit/Transparent Colored 1"); mDynamicMat = new Material(shader); mDynamicMat.name = "[NGUI] " + shader.name; mDynamicMat.mainTexture = mMeshMatTex; Vector4 cr = mTest.ClipRange; Vector4 soft = mTest.ClipSoftness; float angle = 0f; angle *= -Mathf.Deg2Rad; Vector2 sharpness = new Vector2(1000.0f, 1000.0f); if (soft.x > 0f) sharpness.x = cr.z / soft.x; if (soft.y > 0f) sharpness.y = cr.w / soft.y; mDynamicMat.SetVector(Shader.PropertyToID("_ClipRange0"), new Vector4(-cr.x / cr.z, -cr.y / cr.w, 1f / cr.z, 1f / cr.w)); mDynamicMat.SetVector(Shader.PropertyToID("_ClipArgs0"), new Vector4(sharpness.x, sharpness.y, Mathf.Sin(angle), Mathf.Cos(angle))); //mDynamicMat.renderQueue = 3000 + mDepth; mRenderer.sortingOrder = mDepth; //层级 mRenderer.sharedMaterials = new Material[] { mDynamicMat }; } /// <summary> /// 颜色设置,参考UIBasicSprite.AddVertexColours /// 每个顶点对应一个颜色值,通过mesh.SetColors传给mesh做显示 /// </summary> public List<Color> SetColor() { List<Color> col = new List<Color>(); col.Add(mColor * mGradientBottom);//0,0 col.Add(mColor * mGradientTop);//0,1 col.Add(mColor * mGradientTop);//1,1 col.Add(mColor * mGradientBottom);//1,0 return col; } } 2.生成测试mesh。 public class NguiTest: MonoBehaviour { public Vector4 mClipRange; public Vector4 mClipSoftness; public Texture mTop; public Texture mBottom; // Start is called before the first frame update void Start() { TestPanel(); } /// <summary> /// 生成两个对象,传入不一样的depth和Texture /// 测试层级和裁剪区域 /// </summary> private void TestPanel() { GameObject bottom = new GameObject("Bottom"); NguiObjTest ntBottom = bottom.AddComponent<NguiObjTest>(); ntBottom.Create(mBottom, 1, this); GameObject top = new GameObject("Top"); NguiObjTest ntTop = top.AddComponent<NguiObjTest>(); ntTop.Create(mTop, 2, this); } public Vector4 ClipRange { get { return mClipRange; } } public Vector4 ClipSoftness { get { return mClipSoftness; } } }
3.测试,基于上述代码实现NGUI的层级、裁剪、颜色功能。
在界面上生成一个空对象并挂载NguiTest组件,设置如下属性,mClipRange是裁剪区域(世界坐标),mClipSoftness是便于的渐隐效果,mTop是显示在上层的图片。
效果如下:这边加了NGUI的Gradient颜色渐变效果。
一直想把之前工作、学习时记录的文档整理到博客上,一方面温故而知新,一方面和大家一起学习 -程序小白