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绘制原理学习的更多相关文章

  1. Android View绘制原理分析

    推荐两篇分析view绘制原理比较好的文章,感谢作者的分享. <Android应用层View绘制流程与源码分析> <View 绘制流程>

  2. IIS原理学习

    IIS 原理学习 首先声明以下内容是我在网上搜索后整理的,在此只是进行记录,以备往后查阅只用. IIS 5.x介绍 IIS 5.x一个显著的特征就是Web Server和真正的ASP.NET Appl ...

  3. UIView的绘制原理

    当UIView调用setNeedDisplay之后, 系统会调用view对应layer的 setNeedsDisplay, 在当前runloop即将结束的时候调用CALayer的display方法. ...

  4. zookkeper原理学习

    zookkeper原理学习  https://segmentfault.com/a/1190000014479433   https://www.cnblogs.com/felixzh/p/58692 ...

  5. GIS原理学习目录

    GIS原理学习目录 内容提要 本网络教程是教育部“新世纪网络课程建设工程”的实施课程.系统扼要地阐述地理信息系统的技术体系,重点突出地理信息系统的基本技术及方法. 本网络教程共分八章:第一章绪论,重点 ...

  6. 转:SVM与SVR支持向量机原理学习与思考(一)

    SVM与SVR支持向量机原理学习与思考(一) 转:http://tonysh-thu.blogspot.com/2009/07/svmsvr.html 弱弱的看了看老掉牙的支持向量机(Support ...

  7. Android面试收集录12 View测量、布局及绘制原理

    一.View绘制的流程框架 View的绘制是从上往下一层层迭代下来的.DecorView-->ViewGroup(--->ViewGroup)-->View ,按照这个流程从上往下, ...

  8. Android自复制传播APP原理学习(翻译)

     Android自复制传播APP原理学习(翻译) 1 背景介绍 论文链接:http://arxiv.org/abs/1511.00444 项目地址:https://github.com/Tribler ...

  9. 计算机原理学习(1)-- 冯诺依曼体系和CPU工作原理

    前言 对于我们80后来说,最早接触计算机应该是在95年左右,那个时候最流行的一个词语是多媒体. 依旧记得当时在同学家看同学输入几个DOS命令就成功的打开了一个游戏,当时实在是佩服的五体投地.因为对我来 ...

随机推荐

  1. Bootstrap3免费单页面模板-Shuffle

    在线演示 本地下载 这是一款当前最热门的模板,单页面模板现在越来越时兴,它简洁的页面和每一次滑动都带来的全新视角.非常值得收藏和使用!

  2. [置顶] 【玩转cocos2d-x之二十】从CCObject看cocos2d-x的内存管理机制

    原创作品,转载请标明:http://blog.csdn.net/jackystudio/article/details/13765639 再看CCObject,剔除上节的拷贝相关,以及Lua脚本相关的 ...

  3. 当Activity继承AppCompatActivity如何实现隐藏标题栏与状态栏

    @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); g ...

  4. MAC系统XAMPP 中 MySQL命令行client配置使用

    在PHP的学习过程中.MySQL预计是必定会接触的. MySQL的管理相信大家也会使用phpmyadmin: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv ...

  5. Android Studio怎样加入工程(project)为library(针对非gradle)

    这篇文章还是针对非gradle build的project,gradle build有一些区别.在Eclipse要引用别的project为本project的library非常easy,可是在Andro ...

  6. SVN mime-type 笔记

    背景: 1.最近使用执行svn diff的时候发现有些文本文件无法显示: 2.浏览器会通过判断获取文件的 MIME 类型, 调用不同的客户端程序或使用不同的方式来执行.如果文件的 MIME 缺失或者有 ...

  7. TP5报错variable type error: array

      variable type error: array 当你在tp5框架中写方法时返回一个数组时,tp5会报错:variable type error: array 这是因为tp5不支持返回数组. ...

  8. vue单文件(sfc)编译为js的流程

    1.流程 2.参考文章地址 https://segmentfault.com/a/1190000012336392 3.Vue框架的parseComponent https://github.com/ ...

  9. Ubuntu12.04+OpenERP6.1更改HTTP端口号为80

    在Ubuntu12.04中安装好OpenERP6.1以后,默认的端口号为8069,如果我们想改变为默认的80端口,可以通过如下方式处理. 1.首先通过iptables进行端口映射转换:sudo ipt ...

  10. windows命令行设置IP与DNS

    用dos命令修改IP等本地连接属性 平时我们改IP通常都在是窗口界面本地连接直接修改, 那在命令行也可以设置IP地址?当然可以,这里要用到netsh命令 .点击“开始”->“运行”,输入“cmd ...