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命令就成功的打开了一个游戏,当时实在是佩服的五体投地.因为对我来 ...
随机推荐
- 生成activiti需要的25张系统表
Activiti的运行支持,必须要有Activiti的25张表,主要是在流程运行过程中,记录存储一些参与流程的用户主体, 组,以及流程定义的存储,流程执行时候的一些信息,以及流程的历史信息等. 下面我 ...
- 解决this web application instance has been stopped already
重启tomcat的时候出错 Illegal access: this web application instance has been stopped already. Could not loa ...
- 实现锁死的有滚动条的div的表格(datagird)
JS框架使用Jquery 最终效果: 代码结构: 代码: <HEAD><TITLE>new document</TITLE> <META name=Gener ...
- PHP中的密码加密的解决方案
层出不穷的类似事件对用户会造成巨大的影响,因为人们往往习惯在不同网站使用相同的密码,一家“暴库”,全部遭殃 一般的解决方案 1.将明文密码做单向hash $password = md5($_POST[ ...
- LNMP的的编译安装全过程
一.对系统进行更新 yum update -y lsb_release -a 二.禁用SELINUX sed -i '/SELINUX/s/enforcing/disabled/' /etc/seli ...
- HDUOJ-------1753大明A+B(大数之小数加法)
大明A+B Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- HDUOJ---1754 I Hate It (线段树之单点更新查区间最大值)
I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- HDUOJ---(4708)Rotation Lock Puzzle
Rotation Lock Puzzle Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- access database in a helper function ?
<?php if(! function_exists('get_user_info')){ function get_user_info($field) { $ci = & get_in ...
- Oracle截取字符串函数和查找字符串函数,连接运算符||
参考资料:Oracle截取字符串和查找字符串 oracle自定义函数学习和连接运算符(||) oracle 截取字符(substr),检索字符位置(instr) case when then else ...