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命令就成功的打开了一个游戏,当时实在是佩服的五体投地.因为对我来 ...
随机推荐
- 绕过Web授权和认证之篡改HTTP请求
一.什么是HTTP请求 超文本传输协议(HTTP)提供了多种请求方法来与web服务器沟通.当然,大多数方法的初衷是帮助开发者在开发或调试过程中部署和测试HTTP应用.如果服务器配置不当,这些请求方法可 ...
- acm2024
/** * C语言合法标识符 */ import java.util.*; public class acm2024 { public static void main(String[] args ...
- cocos2d 重写顶点着色语言
bool CCShaderSprite::initWithFile( const char *pszFilename ) { bool ret=false; do { ret=CCSpri ...
- Android:子线程向UI主线程发送消息
在Android里,UI线程是不同意被堵塞的.因此我们要将耗时的工作放到子线程中去处理. 那么子线程耗时处理后要如何通知UI线程呢? 我们能够在UI主线程中创建一个handler对象,然后通过重写其h ...
- 算法笔记_195:历届试题 错误票据(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 某涉密单位下发了某种票据,并要在年终全部收回. 每张票据有唯一的ID号.全年所有票据的ID号是连续的,但ID的开始数码是随机选定的. 因为 ...
- $ionicModal
Ionic中[弹出式窗口]有两种(如下图所示),$ionicModal和$ionicPopup; $ionicModal是完整的页面: $ionicPopup是(Dialog)对话框样式的,直接用Ja ...
- 全国出现大面积DNS服务器故障 域名被劫持
1月21日消息,继今日上午腾讯16项服务出现故障后,大量网站出现了无法访问的情况,据了解,该故障是由于国内DNS根服务器故障所致. 据了解,此次攻击式由于国内所有通用顶级域的根服务器出现异常,导致大量 ...
- lambda 2
# -*- coding: utf-8 -*- #python 27 #xiaodeng def action(x): return (lambda y:x+y) act=action(99) pri ...
- mysql字符集和字符排序
mysql的字符集和字符序: 字符序:字符序(Collation)是指在同一字符集内字符之间的比较规则 一个字符序唯一对应一种字符集,但一个字符集可以对应多种字符序,其中有一个是默认字符序 ...
- PHP-Ajax跨域解决方案
1.先了解下Ajax跨域问题: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "ht ...