NGUI UIPanel绘制原理学习
NGUI底层绘制都是调用UIDrawCall来完成的,它会动态实例化出材质球,改变UV偏移和缩放(图集显示)。并且全部是面片
UIPanel也是面片,但是内部物体遮罩比较特殊,经过查找发现,影响UIPanel内部物体遮罩的是它的shader。
=====================================
查找过程:
1.首先是在UIPanel中找到mClipRange,然后在Fill中找到似乎和UIDrawCall有关。
void Fill (Material mat)
{
// Cleanup deleted widgets
for (int i = mWidgets.size; i > ; ) if (mWidgets[--i] == null) mWidgets.RemoveAt(i); // Fill the buffers for the specified material
for (int i = , imax = mWidgets.size; i < imax; ++i)
{
UIWidget w = mWidgets.buffer[i]; if (w.visibleFlag == && w.material == mat)
{
UINode node = GetNode(w.cachedTransform); if (node != null)
{
if (generateNormals) w.WriteToBuffers(mVerts, mUvs, mCols, mNorms, mTans);
else w.WriteToBuffers(mVerts, mUvs, mCols, null, null);
}
else
{
Debug.LogError("No transform found for " + NGUITools.GetHierarchy(w.gameObject), this);
}
}
} if (mVerts.size > )
{
// Rebuild the draw call's mesh
UIDrawCall dc = GetDrawCall(mat, true);
dc.depthPass = depthPass;
dc.Set(mVerts, generateNormals ? mNorms : null, generateNormals ? mTans : null, mUvs, mCols);
}
else
{
// There is nothing to draw for this material -- eliminate the draw call
UIDrawCall dc = GetDrawCall(mat, false); if (dc != null)
{
mDrawCalls.Remove(dc);
NGUITools.DestroyImmediate(dc.gameObject);
}
} // Cleanup
mVerts.Clear();
mNorms.Clear();
mTans.Clear();
mUvs.Clear();
mCols.Clear();
}
Fill
2.发现UIDrawCall是其对材质球创建控制的底层。不过没做成单例的形式,而是组合进来,缺点是UI组件的粒度比较大。
3.UpdateMaterials方法里是其对Panel软硬边裁剪的实现。
void UpdateMaterials()
{
bool useClipping = (mClipping != Clipping.None); // If clipping should be used, create the clipped material
if (useClipping)
{
Shader shader = null; if (mClipping != Clipping.None)
{
const string alpha = " (AlphaClip)";
const string soft = " (SoftClip)"; // Figure out the normal shader's name
string shaderName = mSharedMat.shader.name;
shaderName = shaderName.Replace(alpha, "");
shaderName = shaderName.Replace(soft, ""); // Try to find the new shader
if (mClipping == Clipping.HardClip ||
mClipping == Clipping.AlphaClip) shader = Shader.Find(shaderName + alpha);
else if (mClipping == Clipping.SoftClip) shader = Shader.Find(shaderName + soft); // If there is a valid shader, assign it to the custom material
if (shader == null) mClipping = Clipping.None;
} // If we found the shader, create a new material
if (shader != null)
{
if (mClippedMat == null)
{
mClippedMat = mSharedMat;
mClippedMat.hideFlags = HideFlags.DontSave;
}
mClippedMat.shader = shader;
mClippedMat.mainTexture = mSharedMat.mainTexture;
}
else if (mClippedMat != null)
{
NGUITools.Destroy(mClippedMat);
mClippedMat = null;
}
}
else if (mClippedMat != null)
{
NGUITools.Destroy(mClippedMat);
mClippedMat = null;
} // If depth pass should be used, create the depth material
if (mDepthPass)
{
if (mDepthMat == null)
{
Shader shader = Shader.Find("Unlit/Depth Cutout");
mDepthMat = new Material(shader);
mDepthMat.hideFlags = HideFlags.DontSave;
}
mDepthMat.mainTexture = mSharedMat.mainTexture;
}
else if (mDepthMat != null)
{
NGUITools.Destroy(mDepthMat);
mDepthMat = null;
} // Determine which material should be used
Material mat = (mClippedMat != null) ? mClippedMat : mSharedMat; if (mDepthMat != null)
{
// If we're already using this material, do nothing
if (mRen.sharedMaterials != null && mRen.sharedMaterials.Length == && mRen.sharedMaterials[] == mat) return; // Set the double material
mRen.sharedMaterials = new Material[] { mDepthMat, mat };
}
else if (mRen.sharedMaterial != mat)
{
mRen.sharedMaterials = new Material[] { mat };
}
}
void UpdateMaterials()
4.OnWillRenderObject()方法里对材质球的调用十分可疑。
mClippedMat.mainTextureOffset = new Vector2(-mClipRange.x / mClipRange.z, -mClipRange.y / mClipRange.w); mClippedMat.mainTextureScale = new Vector2(1f / mClipRange.z, 1f / mClipRange.w);
5.为了验证想法,把动态实例化的材质球改掉,手动调节UV。在UpdateMaterials ()中
//mClippedMat = new Material(mSharedMat);
mClippedMat = mSharedMat;
6.

7.但是UI Panel光是面片还不够,这并不能解释其中的每个物体都能被裁剪的问题。

8.检查了下,不太可能是代码问题。似乎是shader做了手脚。在某个软边裁剪的shader,像素着色器下找到如下内容
half4 frag (v2f IN) : COLOR
{
// Softness factor
float2 factor = (float2(1.0, 1.0) - abs(IN.worldPos)) * _ClipSharpness; // Sample the texture
half4 col = tex2D(_MainTex, IN.texcoord) * IN.color;
col.a *= clamp( min(factor.x, factor.y), 0.0, 1.0);
return col;
}
调试一下,输出值改为tex2D
return tex2D(_MainTex, IN.texcoord) * IN.color;
发现不再显示遮罩效果,但调整offset偏移值也无效。
9.继续刨根问底,发现顶点着色器的UV变换没加TRANSFORM_TEX,百度了下似乎不加外部偏移等参数就无效。加上之后,可以进行偏移等操作。
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);
o.worldPos = TRANSFORM_TEX(v.vertex.xy, _MainTex);
return o;
}

确实是公用UV,不再有遮罩效果
可能是shader里得到屏幕位置再进行计算,达到遮罩效果。时间有限就不继续深究了。总之大概来龙去脉就是这样。
NGUI UIPanel绘制原理学习的更多相关文章
- Android View绘制原理分析
推荐两篇分析view绘制原理比较好的文章,感谢作者的分享. <Android应用层View绘制流程与源码分析> <View 绘制流程>
- IIS原理学习
IIS 原理学习 首先声明以下内容是我在网上搜索后整理的,在此只是进行记录,以备往后查阅只用. IIS 5.x介绍 IIS 5.x一个显著的特征就是Web Server和真正的ASP.NET Appl ...
- UIView的绘制原理
当UIView调用setNeedDisplay之后, 系统会调用view对应layer的 setNeedsDisplay, 在当前runloop即将结束的时候调用CALayer的display方法. ...
- zookkeper原理学习
zookkeper原理学习 https://segmentfault.com/a/1190000014479433 https://www.cnblogs.com/felixzh/p/58692 ...
- GIS原理学习目录
GIS原理学习目录 内容提要 本网络教程是教育部“新世纪网络课程建设工程”的实施课程.系统扼要地阐述地理信息系统的技术体系,重点突出地理信息系统的基本技术及方法. 本网络教程共分八章:第一章绪论,重点 ...
- 转:SVM与SVR支持向量机原理学习与思考(一)
SVM与SVR支持向量机原理学习与思考(一) 转:http://tonysh-thu.blogspot.com/2009/07/svmsvr.html 弱弱的看了看老掉牙的支持向量机(Support ...
- Android面试收集录12 View测量、布局及绘制原理
一.View绘制的流程框架 View的绘制是从上往下一层层迭代下来的.DecorView-->ViewGroup(--->ViewGroup)-->View ,按照这个流程从上往下, ...
- Android自复制传播APP原理学习(翻译)
Android自复制传播APP原理学习(翻译) 1 背景介绍 论文链接:http://arxiv.org/abs/1511.00444 项目地址:https://github.com/Tribler ...
- 计算机原理学习(1)-- 冯诺依曼体系和CPU工作原理
前言 对于我们80后来说,最早接触计算机应该是在95年左右,那个时候最流行的一个词语是多媒体. 依旧记得当时在同学家看同学输入几个DOS命令就成功的打开了一个游戏,当时实在是佩服的五体投地.因为对我来 ...
随机推荐
- linux pdb调试总结
1.首先gdb编译: gcc -g xxx.c -o xxx 2.然后 gdb xxx进入调试 break 行号 加入断点 (1)然后run就能够跑到下一个断点 (2)step(或s)单步跟踪 (3) ...
- Smack 结合 Openfire服务器,建立IM通信,发送聊天消息
在文章开始,请你了解和熟悉openfire方面的相关知识,这样对你理解下面代码以及下面代码的用途有很好的了解.同时,你可能需要安装一个简单的CS聊天工具,来测试你的代码是否成功的在openfire服务 ...
- ionic 项目中 使用 sass
注: 1.先安装node-sass -->> npm install --save node-sass --registry=https://registry.npm.taobao.or ...
- python之函数用法any()
# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之函数用法any() #any() #说明:如果iterable的任何元素不为0.''.Fals ...
- Centos7安装Openresty
通过yum安装 在 /etc/yum.repos.d/ 下新建 OpenResty.repo 内容 [openresty] name=Official OpenResty Repository bas ...
- IT忍者神龟之 oracle行转列、列转行
一.行转列 须要将例如以下格式 转换为: 这就是最常见的行转列,主要原理是利用decode函数.聚集函数(sum).结合group by分组实现的 create table test( id varc ...
- spring.net aop 讲解
spring.net aop几个术语: 切面:针对类 切点:针对方法 object.xml <?xml version="1.0" encoding="utf-8& ...
- coding云进行git push报:permission denied
1.原因可能是 登录其他的git 项目,本地缓存了其他用户的 用户名和密码 认证信息,导致一直权限不通过 解决: git remote add origin http://yourname:passw ...
- 【TP3.2】跨库操作和跨域操作
一.跨库操作:(同一服务器,不同的数据库) 假设UserModel对应的数据表在数据库user下面,而InfoModel对应的数据表在数据库info下面,那么我们只需要进行下面的设置即可. class ...
- (二)Linux实操之——网络配置、进程管理、服务管理、组管理、YUM
接上段 (一)Linux实操之——权限.任务调度.磁盘分区 4.网络配置 4.1 NAT模式的网络配置 目前我们采用的网络配置是NAT模式. windows下cmd通过 ipconfig 命令可以 ...