1.UI/Default代码研究
首先,我想到的是,既然是对图集纹理进行采样,而且又不能统一更改材质的纹理UV值,我们通常写的shader都是直接根据模型UV值对主纹理进行采样,那会不会是shader中对MainTexture进行了什么神奇的处理,让图片采样只根据指定的UV值进行采样呢?
我去官网下载了shader代码,找到了UI/Default的具体实现:

fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;

v2f vert(appdata_t v)
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
OUT.worldPosition = v.vertex;
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);

OUT.texcoord = v.texcoord;

OUT.color = v.color * _Color;
return OUT;
}

sampler2D _MainTex;

fixed4 frag(v2f IN) : SV_Target
{
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;

#ifdef UNITY_UI_CLIP_RECT
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#endif

#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif

return color;
}
看了上面的代码,我们可以基本确定,没有在shader中做什么特别神奇的MainTexture处理。但是我们还是可以发现一些不同的地方,这里上面的变量_Color,_TextureSampleAdd,_ClipRect并没有暴露在面板上,可以看出来这三个变量是通过某些脚本传递给shader的。
我们知道,伴随着Defalut材质的一般使用的是Image组件、Text组件。这两个组件会绘制顶点与三角形,然后使用指定的材质进行渲染。所以会不会是Image组件或Text组件中使用了什么算法,计算过图片UV值,并把上面三个变量填充好传给shader的呢?

2.Image组件代码研究
因为unity的ui代码已经开源了,所以我们很幸运的可以看到Image的源码是怎么实现的,因为Image组件代码很多,所以这里就只贴出比较主要的绘制顶点的函数:

/// <summary>
/// Update the UI renderer mesh.
/// </summary>
protected override void OnPopulateMesh(VertexHelper toFill)
{
if (activeSprite == null)
{
base.OnPopulateMesh(toFill);
return;
}

switch (type)
{
case Type.Simple:
if (!useSpriteMesh)
GenerateSimpleSprite(toFill, m_PreserveAspect);
else
GenerateSprite(toFill, m_PreserveAspect);
break;
case Type.Sliced:
GenerateSlicedSprite(toFill);
break;
case Type.Tiled:
GenerateTiledSprite(toFill);
break;
case Type.Filled:
GenerateFilledSprite(toFill, m_PreserveAspect);
break;
}
}

我们可以看到,这个函数是用来刷新UI渲染的,unity对图片的四种类型分别进行了处理,这里我们就只看一下最简单的Simple模式的代码:

/// <summary>
/// Generate vertices for a simple Image.
/// </summary>
void GenerateSimpleSprite(VertexHelper vh, bool lPreserveAspect)
{
Vector4 v = GetDrawingDimensions(lPreserveAspect);
var uv = (activeSprite != null) ? Sprites.DataUtility.GetOuterUV(activeSprite) : Vector4.zero;

var color32 = color;
vh.Clear();
vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(uv.x, uv.y));
vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(uv.x, uv.w));
vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(uv.z, uv.w));
vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(uv.z, uv.y));

vh.AddTriangle(0, 1, 2);
vh.AddTriangle(2, 3, 0);
}

/// Image's dimensions used for drawing. X = left, Y = bottom, Z = right, W = top.
private Vector4 GetDrawingDimensions(bool shouldPreserveAspect)
{
var padding = activeSprite == null ? Vector4.zero : Sprites.DataUtility.GetPadding(activeSprite);
var size = activeSprite == null ? Vector2.zero : new Vector2(activeSprite.rect.width, activeSprite.rect.height);

Rect r = GetPixelAdjustedRect();
// Debug.Log(string.Format("r:{2}, size:{0}, padding:{1}", size, padding, r));

int spriteW = Mathf.RoundToInt(size.x);
int spriteH = Mathf.RoundToInt(size.y);

var v = new Vector4(
padding.x / spriteW,
padding.y / spriteH,
(spriteW - padding.z) / spriteW,
(spriteH - padding.w) / spriteH);

if (shouldPreserveAspect && size.sqrMagnitude > 0.0f)
{
PreserveSpriteAspectRatio(ref r, size);
}

v = new Vector4(
r.x + r.width * v.x,
r.y + r.height * v.y,
r.x + r.width * v.z,
r.y + r.height * v.w
);

return v;
}

public void AddVert(Vector3 position, Color32 color, Vector2 uv0);
就是在这里了,首先拿到绘制的尺寸v,也就是四个顶点的位置,然后根据activeSprite拿到纹理的UV值。我们可以看到AddVert函数中,第三个值是绘制的顶点中填充的uv0也就是这个得到的UV值,而shader中也会根据这个uv值对MainTexture进行采样。

3.小实验
我们已经知道计算顶点与UV值的操作是在image中进行的,其实unity有一个组件可以自己控制采样的uv值,就是RawImage组件,相比Image组件,RawImage组件更为精简,因为没有处理Image中的四种图片样式。
其实Image组件中帮我们做的操作其实就相当于(是相当于,其实计算比这复杂的多)在RawImage中设置了不同的UV偏移值。这样就可以做到,每个组件使用的UV值不同,而不是改变统一使用材质上的UV值。

修改RawImage中的UV值

总结
我们最开始的想法是修改材质中的UV值,但是这样是不行的,因为改变了材质UV值后所有物体都会跟着改变。Unity使用了一个巧妙的办法,也就是在建模(绘制顶点/三角形)的时候,就把得到的图集中纹理的UV采样值填充到mesh的UV中。所以材质使用的都是同一个材质,也都是对MainTexture进行采样,只不过每个图片的mesh中存储的UV值都是不同的。

更多unity2018的功能介绍请到paws3d爪爪学院查找。

Unity的UI究竟为什么可以合批的更多相关文章

  1. 关于如何在 Unity 的 UI 菜单中默认创建出的控件 Raycast Target 属性默认为 false

    关于如何在 Unity 的 UI 菜单中默认创建出的控件 Raycast Target 属性默认为 false 我们在 Unity 中通过 UI 菜单创建的各种控件,比如 Text, Image 等, ...

  2. C#程序员整理的Unity 3D笔记(十五):Unity 3D UI控件至尊–NGUI

    目前,UGUI问世不过半年(其随着Unity 4.6发布问世),而市面上商用的产品,UI控件的至尊为NGUI:影响力和广度(可搜索公司招聘Unity 3D,常常能看到对NGUI关键词). NGUI虽然 ...

  3. Unity在UI界面上显示3D模型/物体,控制模型旋转

    Unity3D物体在UI界面的显示 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...

  4. 关于Unity中UI中的Mask组件、Text组件和布局

    一.Mask组件 遮罩,Rect Mask矩形Mask(Rect Mask2D组件),图片Mask(Mask组件)(图片Mask的透明度不为0的部分显示子图片,为0的部分不显示子图片) Rect Ma ...

  5. 关于Unity中UI中的Image节点以及它的Image组件

    一.图片的Inspector面板属性 Texture Type:一般是选择sprite(2D and UI) Sprite Mode:一般是选择Single Packing Tag:打包的标志值,最后 ...

  6. unity简易ui框架

    在unity项目开发中,ui模块的开发往往占据了很大一部分工作,部分游戏甚至绝大部分的工作都是在ui上,如何高效管理各种界面,这里分享一套高效易用的UI框架. 首先,我们定义一个PanelBase类, ...

  7. Unity shader UI的3D效果

    原创,转载请标明出处 1.效果 scene视图中的效果: game视图中效果: 2.核心思想:改变UI的顶点坐标 3.好处:可以用正交相机来实现3D效果. 4.Shader 实现 // Unity b ...

  8. unity UGUI UI跟随

    实现2dUI跟随游戏中角色的移动(应用于玩家名称,血条,称号) using UnityEngine; public class UI_Follow : MonoBehaviour { public C ...

  9. [Unity优化]UI优化(三):GraphicRebuild

    参考链接: https://blog.csdn.net/jingangxin666/article/details/80143176 调试过程: 1.修改Image的颜色 2.Graphic.SetV ...

随机推荐

  1. java 字符串池【转】

    java 字符串池 java运行环境有一个字符串池.比如String str="abc"时,会首先查看字符串池中是否存在字符串"abc",如果存在则直接将&qu ...

  2. git基础命令学习总结

    git版本升级 git clone git://git.kernel.org/pub/scm/git/git.git 列出所有 Git 当时能找到的配置 git config --list git c ...

  3. .NET开发微信小程序-生成二维码

    1.生成小程序二维码功能 直接请求相应的链接.传递相应的参数 以生成商铺的付款码为例: var shopsId = e.ShopsId //付款码的参数 var codeModel = new fun ...

  4. Axios源码深度剖析 - 替代$.ajax,成为xhr的新霸主

    前戏 在正式开始axios讲解前,让我们先想想,如何对现有的$.ajax进行简单的封装,就可以直接使用原声Promise了? let axios = function(config){ return ...

  5. spring+activemq中多个consumer同时处理消息时遇到的性能问题

    最近在做数据对接的工作,用到了activemq,我需要从activemq中接收消息并处理,但是我处理数据的步骤稍微复杂,渐渐的消息队列中堆的数据越来越多,就想到了我这边多开几个线程来处理消息. 可是会 ...

  6. Ajax跨域之ContentType为application/json请求失败的问题

    项目里的接口都是用springmvc写的,其中在@requestmapping接口中定义了consumes="application/json",也就是该接口只接受ContentT ...

  7. elasticSearch+spring 整合 maven依赖详解

    摘自:http://www.mayou18.com/detail/nTxPQSyu.html [Elasticsearch基础]elasticSearch+spring 整合 maven依赖详解 Ma ...

  8. 开源RPC(gRPC/Thrift)框架性能评测

    海量互联网业务系统只能依赖分布式架构来解决,而分布式开发的基石则是RPC:本文主要针对两个开源的RPC框架(gRPC. Apache Thrift),以及配合GoLang.C++两个开发语言进行性能对 ...

  9. Mongodb---操作备忘

     mysql/mongodb对比 CREATE TABLE USERS (a Number, b Number) Implicit or use MongoDB::createCollection() ...

  10. Latex数学公式中的空格表示方法

    两个quad空格 a \qquad b 两个m的宽度 quad空格 a \quad b 一个m的宽度 大空格 a\ b 1/3m宽度 中等空格 a\;b 2/7m宽度 小空格 a\,b 1/6m宽度 ...