当前位置: 首页 > article >正文

深入Unity UGUI源码:手写ExtendImage组件,彻底搞懂Image的Filled与Sliced渲染原理

深入Unity UGUI源码手写ExtendImage组件彻底搞懂Image的Filled与Sliced渲染原理在Unity的UI开发中Image组件是最基础也是最常用的组件之一。无论是简单的图标显示还是复杂的进度条动画Image组件都扮演着至关重要的角色。然而当我们需要实现一些特殊效果时比如支持九宫格裁剪的进度条原生的Image组件就显得力不从心了。本文将带你深入UGUI源码通过手写ExtendImage组件彻底理解Image组件中Filled与Sliced模式的渲染原理。1. UGUI Image组件基础原理UGUI的Image组件继承自MaskableGraphic类主要负责2D精灵的渲染。其核心渲染逻辑是通过OnPopulateMesh方法实现的这个方法负责生成网格数据顶点、UV、颜色等并填充到VertexHelper中。Image组件支持四种渲染类型Simple最简单的拉伸渲染Sliced九宫格渲染Tiled平铺渲染Filled填充渲染常用于进度条// Image组件的类型定义 public enum Type { Simple, Sliced, Tiled, Filled }在深入研究Filled和Sliced模式之前我们需要先了解几个关键概念Sprite的Border属性定义了九宫格的边界值UV坐标决定了纹理如何在网格上映射VertexHelper用于构建网格数据的辅助类2. Filled模式的实现原理Filled模式是制作进度条最常用的方式它通过fillAmount参数控制显示比例。让我们深入源码看看它是如何工作的。2.1 Filled模式的核心算法Filled模式的渲染逻辑主要在GenerateFilledSprite方法中实现。根据不同的填充方法水平、垂直、径向等计算顶点和UV的方式也有所不同。以水平填充为例关键计算步骤如下计算填充比例对应的顶点位置根据填充原点Left或Right调整顶点位置计算对应的UV坐标生成三角形索引// 水平填充的核心代码片段 if (fillMethod FillMethod.Horizontal) { float fill fillAmount; if (fillOrigin 1) // Right { xMin Mathf.Lerp(xMax, xMin, fill); uvMin.x Mathf.Lerp(uvMax.x, uvMin.x, fill); } else // Left { xMax Mathf.Lerp(xMin, xMax, fill); uvMax.x Mathf.Lerp(uvMin.x, uvMax.x, fill); } }2.2 Filled模式的局限性虽然Filled模式非常适合制作进度条效果但它有一个明显的缺点不支持九宫格。这意味着进度条在不同长度时边缘会出现拉伸变形需要为不同长度的进度条准备不同的图片资源无法利用九宫格的特性来优化资源3. Sliced模式的实现原理Sliced模式九宫格是UI优化的重要手段它通过将图片分为9个区域只拉伸中间部分来保持边缘不变形。3.1 九宫格的数据结构九宫格的信息存储在Sprite的border属性中它是一个Vector4分别表示左、下、右、上的边界值[left, bottom, right, top]在代码中我们通过Sprite.border属性获取这些值Vector4 border activeSprite.border;3.2 Sliced模式的渲染流程Sliced模式的渲染主要在GenerateSlicedSprite方法中实现大致流程如下获取Sprite的border值计算调整后的边界考虑像素密度将图片分为9个区域为每个区域生成顶点和UV数据// 九宫格顶点计算的核心代码 s_VertScratch[0] new Vector2(padding.x, padding.y); s_VertScratch[1] new Vector2(border.x, border.y); s_VertScratch[2] new Vector2(rect.width - border.z, rect.height - border.w); s_VertScratch[3] new Vector2(rect.width - padding.z, rect.height - padding.w);3.3 Sliced模式的局限性虽然Sliced模式能很好地保持边缘不变形但它不适合用于进度条效果因为无法实现真正的裁剪效果进度变化时部分区域会保持显示无法精确控制显示比例4. 实现ExtendImage组件结合Filled和Sliced模式的优缺点我们需要创建一个新的ExtendImage组件让Filled模式支持九宫格。4.1 组件设计思路我们的ExtendImage组件需要继承自UnityEngine.UI.Image添加一个SlicedClipMode选项重写OnPopulateMesh方法实现自定义的GenerateSlicedSprite方法[AddComponentMenu(UI/ExtendImage)] public class ExtendImage : Image { [SerializeField] private bool m_SlicedClipMode false; protected override void OnPopulateMesh(VertexHelper vh) { if (type Type.Filled m_SlicedClipMode hasBorder) { GenerateSlicedSprite(vh); } else { base.OnPopulateMesh(vh); } } }4.2 核心算法实现关键点在于如何结合Filled的裁剪和Sliced的九宫格特性。我们需要计算九宫格各部分的比例根据fillAmount确定显示哪些部分对最后一个显示的部分进行裁剪private void GenerateSlicedSprite(VertexHelper toFill) { // 获取九宫格信息 Vector4 border activeSprite.border / pixelsPerUnit; Vector4 adjustedBorders GetAdjustedBorders(border, rect); // 计算各部分比例 float xLength s_VertScratch[3].x - s_VertScratch[0].x; float len1XRatio (s_VertScratch[1].x - s_VertScratch[0].x) / xLength; float len2XRatio (s_VertScratch[2].x - s_VertScratch[1].x) / xLength; float len3XRatio (s_VertScratch[3].x - s_VertScratch[2].x) / xLength; // 根据fillAmount裁剪 if (fillAmount (len1XRatio len2XRatio)) { float ratio (fillAmount - (len1XRatio len2XRatio)) / len3XRatio; s_VertScratch[3].x s_VertScratch[2].x (s_VertScratch[3].x - s_VertScratch[2].x) * ratio; s_UVScratch[3].x s_UVScratch[2].x (s_UVScratch[3].x - s_UVScratch[2].x) * ratio; } else if (fillAmount len1XRatio) { float ratio (fillAmount - len1XRatio) / len2XRatio; s_VertScratch[2].x s_VertScratch[1].x (s_VertScratch[2].x - s_VertScratch[1].x) * ratio; } else { float ratio fillAmount / len1XRatio; s_VertScratch[1].x s_VertScratch[0].x (s_VertScratch[1].x - s_VertScratch[0].x) * ratio; } // 生成网格 toFill.Clear(); AddQuad(toFill, ...); }4.3 编辑器扩展为了让组件更易用我们还需要创建一个自定义编辑器[CustomEditor(typeof(ExtendImage), true)] public class ExtendImageEditor : ImageEditor { private SerializedProperty m_SlicedClipMode; protected override void OnEnable() { base.OnEnable(); m_SlicedClipMode serializedObject.FindProperty(m_SlicedClipMode); } public override void OnInspectorGUI() { base.OnInspectorGUI(); if ((Image.Type)m_Type.enumValueIndex Image.Type.Filled) { EditorGUILayout.PropertyField(m_SlicedClipMode); } } }5. 性能优化与注意事项在实现自定义UI组件时性能是需要重点考虑的因素。以下是几个优化建议顶点计算优化尽量减少不必要的计算复用中间计算结果使用局部变量而非频繁访问属性网格生成优化只生成必要的三角形避免频繁调用VertexHelper.Clear()使用对象池管理VertexHelper内存管理避免在每帧创建新的数组使用静态数组减少GC压力合理使用缓存// 使用静态数组减少GC private static readonly Vector2[] s_VertScratch new Vector2[4]; private static readonly Vector2[] s_UVScratch new Vector2[4];在实际项目中我发现最常遇到的问题是不正确的边界计算。特别是在处理不同分辨率和像素密度时需要特别注意提示在计算九宫格边界时一定要考虑pixelsPerUnit的影响否则在不同分辨率的设备上可能会出现显示异常。另一个常见问题是填充方向的处理。我们的ExtendImage组件目前只实现了水平和垂直方向的裁剪如果需要支持径向填充还需要扩展算法// 径向填充的伪代码 if (fillMethod FillMethod.Radial90) { // 计算角度 float angle Mathf.Lerp(0, 90, fillAmount); // 根据角度裁剪顶点 // ... }6. 扩展应用与进阶技巧掌握了Image组件的核心原理后我们可以进一步扩展其功能渐变填充在顶点颜色中添加渐变效果扭曲效果通过修改顶点位置实现扭曲动画自定义遮罩结合Shader实现特殊遮罩效果以下是一个简单的渐变填充实现思路// 渐变填充的顶点颜色设置 Color32 color0 new Color32(255, 0, 0, 255); // 起始颜色 Color32 color1 new Color32(0, 255, 0, 255); // 结束颜色 vertexHelper.AddVert(new Vector3(posMin.x, posMin.y, 0), color0, uvMin); vertexHelper.AddVert(new Vector3(posMin.x, posMax.y, 0), color0, new Vector2(uvMin.x, uvMax.y)); vertexHelper.AddVert(new Vector3(posMax.x, posMax.y, 0), color1, uvMax); vertexHelper.AddVert(new Vector3(posMax.x, posMin.y, 0), color1, new Vector2(uvMax.x, uvMin.y));对于更复杂的效果可以结合Shader来实现。例如创建一个支持UV动画的Image组件public class AnimatedImage : Image { public Vector2 uvAnimationSpeed Vector2.zero; protected override void OnPopulateMesh(VertexHelper vh) { base.OnPopulateMesh(vh); UIVertex vertex new UIVertex(); for (int i 0; i vh.currentVertCount; i) { vh.PopulateUIVertex(ref vertex, i); vertex.uv0 uvAnimationSpeed * Time.unscaledTime; vh.SetUIVertex(vertex, i); } } }在实际项目中我发现理解UGUI的底层原理不仅能帮助我们解决具体问题还能激发更多创意。比如通过分析Image组件的实现我们可以更好地理解Unity的UI渲染管线网格生成与优化的技巧性能瓶颈的分析方法自定义组件的设计模式

相关文章:

深入Unity UGUI源码:手写ExtendImage组件,彻底搞懂Image的Filled与Sliced渲染原理

深入Unity UGUI源码:手写ExtendImage组件,彻底搞懂Image的Filled与Sliced渲染原理 在Unity的UI开发中,Image组件是最基础也是最常用的组件之一。无论是简单的图标显示,还是复杂的进度条动画,Image组件都扮演着至关重要…...

jQuery Mobile 事件详解

jQuery Mobile 事件详解 引言 jQuery Mobile 是一个开源的移动Web框架,它旨在为移动设备提供丰富的用户体验。在jQuery Mobile中,事件处理是构建动态和交互式界面的重要组成部分。本文将详细探讨jQuery Mobile中的各种事件,帮助开发者更好地理解和应用这些事件。 一、jQu…...

DC/DC转换器混合输出电容设计原理与工程实践

1. DC/DC转换器中混合输出电容的设计优势解析在电源设计领域,输出电容的选择往往让工程师陷入两难境地。作为一名长期从事电源系统设计的工程师,我深刻理解这种选择的痛苦——电解电容价格亲民但性能受限,陶瓷电容性能卓越却成本高昂。直到混…...

claw-easy-setup:一键自动化部署脚本的设计与实战解析

1. 项目概述与核心价值最近在折腾一些自动化脚本和工具链,发现很多开源项目虽然功能强大,但初次部署的“冷启动”成本实在太高。光是看那一长串的依赖安装、环境配置、参数调优,就足以劝退不少想尝鲜的开发者。直到我遇到了stfurkan/claw-eas…...

隔着包装也能读、2m/s不串读:东集UF40如何应对管制药厂的RFID“极限大考”?

提到RFID固定式读写器,很多人的第一印象是仓库、货架与托盘。但在一些关乎生命安全的领域,RFID技术正面临着更严苛的考验。这一次,我们走进管制药厂——一个对精准追溯要求达到极致、不容任何差错的场景。核心痛点:一盒十瓶&#…...

大模型没有灵魂,但欺骗性极强——写在 AI 情感幻觉爆发的时代

大模型没有灵魂,但欺骗性极强 从一次「塔罗灵异事件」说起 最近 Reddit 上有个帖子刷屏了。 一位用户长期把 DeepSeek 当心理倾诉对象,向它输入私密日记、情绪碎片,偶尔用它解塔罗牌。某天,她问 DeepSeek「塔罗怎么看我」&…...

YOLOv8-face模型跨平台部署实战:从PyTorch到ONNX的高效转换策略

YOLOv8-face模型跨平台部署实战:从PyTorch到ONNX的高效转换策略 【免费下载链接】yolov8-face yolov8 face detection with landmark 项目地址: https://gitcode.com/gh_mirrors/yo/yolov8-face 在计算机视觉领域,人脸检测与关键点定位技术正成为…...

【独家首发】Midjourney官方未公开的配额继承规则:家庭共享、账号迁移、停用恢复的3个灰色地带

更多请点击: https://intelliparadigm.com 第一章:Midjourney订阅计划选择指南 选择合适的 Midjourney 订阅计划是高效使用其图像生成服务的关键起点。不同计划在生成速度、并发任务数、私有模式支持及高分辨率下载权限等方面存在显著差异,…...

从零开始玩转BeagleBone Black:手把手教你配置Cloud9在线开发环境与BoneScript

从零开始玩转BeagleBone Black:手把手教你配置Cloud9在线开发环境与BoneScript 嵌入式开发的世界里,BeagleBone Black(简称BBB)就像一位低调的实力派演员——它没有树莓派那么高的曝光率,却凭借其强大的扩展性和丰富的…...

26-cv-785 便携式多功能检测仪器专利维权!

案号:26-cv-785原告品牌:便携式多功能检测仪器品牌方:ZHIHUI CAO起诉地:美国宾夕法尼亚州代理律所:Aptum Law起诉时间:2026年05月04日起诉类型:专利侵权本次案件涉及的专利如下:湖北…...

英文论文怎么降AI?实测从88%降至20%的5大方法(附工具实测)

最近turnitin系统大升级,判定规则变得更加严格。很多不知道怎么给英文降ai的小伙伴对此都感到非常焦虑,检测报告里大面积的标蓝会导致稿件不合格被退回,手动降ai又要一直盯着屏幕改来改去,费时费力。 作为已经在这个领域摸爬滚打两…...

开发容器Dev Container实战:一键构建跨平台统一开发环境

1. 项目概述:一个为开发者量身定制的“开箱即用”环境 如果你和我一样,经常需要在不同的机器上切换,或者和团队协作时,最头疼的事情之一就是“环境配置”。明明在A电脑上跑得好好的代码,到了B电脑上就各种报错&#x…...

终极指南:5分钟解锁小爱音箱完整音乐自由

终极指南:5分钟解锁小爱音箱完整音乐自由 【免费下载链接】xiaomusic 使用小爱音箱播放音乐,音乐使用 yt-dlp 下载。 项目地址: https://gitcode.com/GitHub_Trending/xia/xiaomusic 还在为小爱音箱的音乐限制感到困扰?想听什么歌都要…...

如何快速掌握星穹铁道抽卡数据分析工具:专业玩家的终极指南

如何快速掌握星穹铁道抽卡数据分析工具:专业玩家的终极指南 【免费下载链接】star-rail-warp-export Honkai: Star Rail Warp History Exporter 项目地址: https://gitcode.com/gh_mirrors/st/star-rail-warp-export 星穹铁道跃迁记录导出工具是一款专为《崩…...

多移动机器人路径规划与协同避障【附代码】

✨ 长期致力于多移动机器人、多移动机器人、路径规划、编队控制、遗传算法研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,点击《获取方式》 (1)基于改进A星与动态窗口法的…...

遗传算法混合动力汽车控制策略【附代码】

✨ 长期致力于混合动力汽车、能量管理策略、模糊控制、遗传算法研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,点击《获取方式》 (1)多目标分层编码与种群初始化策略&…...

A公司B型汽车底盘装配线优化【附代码】

✨ 长期致力于装配线优化、IE方法、自适应遗传算法、SLP方法、Flexsim仿真研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,点击《获取方式》 (1)基于IE方法和自适应遗传算法…...

c++类派生2

一、派生类与基类的构造函数关系构造函数的作用是初始化对象的成员。派生类对象包含基类子对象和派生类新增子对象两部分,因此派生类构造时必须先初始化基类子对象,再初始化自身新增成员。核心规则默认行为:派生类的构造函数(无论…...

如何高效解锁艾尔登法环帧率限制:专业玩家的完整配置指南

如何高效解锁艾尔登法环帧率限制:专业玩家的完整配置指南 【免费下载链接】EldenRingFpsUnlockAndMore A small utility to remove frame rate limit, change FOV, add widescreen support and more for Elden Ring 项目地址: https://gitcode.com/gh_mirrors/el/…...

Claude最新金融智能体模板到底能做什么?一文看懂真实业务场景

Claude最新发布的10大金融智能体模板,在金融科技圈引发了不小关注。原因并不只是它能够生成报告、总结财报,而是它第一次以“业务角色”的形式进入金融流程。无论是Pitch Builder、Earnings Reviewer,还是KYC Screener,本质上都已…...

流域生态系统碳排放、碳循环模拟与评估技术应用

随着全球气候变化的加剧,碳中和已成为实现可持续发展的重要目标之一。碳中和不仅仅是能源和工业领域的调整,它涉及整个生态系统的转型与再生。在这一过程中,流域的生态系统作为水、土、生物多样性等自然资源的集成体,扮演着至关重…...

TV Bro电视浏览器终极指南:如何在智能电视上享受免费开源的大屏上网体验

TV Bro电视浏览器终极指南:如何在智能电视上享受免费开源的大屏上网体验 【免费下载链接】tv-bro Simple web browser for android optimized to use with TV remote 项目地址: https://gitcode.com/gh_mirrors/tv/tv-bro TV Bro是一款专为智能电视和遥控器操…...

青年科学基金 PPT 定制|绎奇演示专业打磨 助力立项突围

青年科学基金申报的老师看过来? 一份逻辑清晰、排版高级的申报 PPT真的太影响评审第一印象了!青年科学基金申报答辩 PPT 是展现科研实力、项目价值与个人学术素养的核心载体,普通通用模板千篇一律、套路固化,难以贴合自身研究方向与申报评审…...

应届生编程面试,这8个加分项,让你在面试官面前脱颖而出

文章目录前言一、基础扎实:别死背八股,要懂“为什么”1. 经典技术永不过时,别盲目追新2. 把“是什么”变成“为什么”,才是真的懂二、项目经历:不说技术栈,说“解决了什么问题”1. 用数据说话,量…...

11个系统、8000张表,这家环保集团如何让沉睡的数据真正“用起来”

很多大型集团企业都有过这样一段经历:信息化建设做了好几轮,ERP上线了,OA部署了,生产监控系统也跑起来了,业务数据越积越厚——看起来数字化建设卓有成效。但真到需要数据的时候,才发现麻烦来了。财务要汇报…...

四川南充纺织减速机升级:从传统织机到智能传动

千年绸都的"心脏"正在换代南充,古称果州,素有"中国绸都"之美誉。从汉代丝绸之路的起点之一,到如今四川省重要的纺织产业基地,南充纺织业绵延两千余年。然而,支撑这一产业蓬勃发展的,不…...

本地从零部署 Java+Vue 前后端分离项目(超详细新手保姆级教程)

一、前言现在企业开发基本都是前后端分离架构,后端用 Java SpringBoot 提供接口、操作数据库,前端用 Vue 搭建页面、做交互展示。很多刚入门的同学,单独跑后端、单独跑前端都没问题,但本地联调对接接口时,总会遇到跨域…...

开发AI Agent时利用Taotoken实现多模型路由与降级策略

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 开发AI Agent时利用Taotoken实现多模型路由与降级策略 1. 场景与挑战 在构建复杂的AI Agent时,开发者常常面临一个核心…...

终极指南:如何在Windows上安装APK文件?3分钟学会跨平台应用安装

终极指南:如何在Windows上安装APK文件?3分钟学会跨平台应用安装 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否想在Windows电脑上直接运…...

LyricsX:macOS歌词同步的终极解决方案

LyricsX:macOS歌词同步的终极解决方案 【免费下载链接】LyricsX 🎶 Ultimate lyrics app for macOS. 项目地址: https://gitcode.com/gh_mirrors/ly/LyricsX 还在为macOS上找不到好用的歌词应用而烦恼吗?LyricsX为你带来了一站式的智能…...