cocos creator使用mesh修改图片为圆形,减少使用mask,j减少drawcall,优化性能
cocos creator版本2.4.11
一个mask占用drawcall 3个以上,针对游戏中技能图标,cd,以及多玩家头像,是有很大优化空间
1.上代码,只适合单独图片的,不适合在图集中的图片
const { ccclass, property } = cc._decorator;const gfx = cc.gfx;
cc.Class({extends: cc.Component,properties: {radius: 100, // 圆的半径segments: 32, // 圆的细分段数(顶点数)/*** !#en The sprite frame of the sprite.* !#zh 精灵的精灵帧* @property spriteFrame* @type {SpriteFrame}* @example* sprite.spriteFrame = newSpriteFrame;*/spriteFrame: {default: null,type: cc.SpriteFrame},},onLoad() {let renderer = this.node.getComponent(cc.MeshRenderer);if (!renderer) {renderer = this.node.addComponent(cc.MeshRenderer);}renderer.mesh = null;this.renderer = renderer;let builtinMaterial = cc.MaterialVariant.createWithBuiltin("unlit");renderer.setMaterial(0, builtinMaterial);this._applySpriteFrame();this.setMesh();},setMesh(){// 创建 Meshlet mesh = new cc.Mesh();// 计算顶点和 UVlet positions = [];let uvs = [];let indices = [];let colors = [];// 圆心顶点positions.push(cc.v2(0, 0)); // 圆心uvs.push(cc.v2(0.5, 0.5)); // 圆心 UVcolors.push(cc.Color.WHITE); // 圆心颜色// 圆边缘顶点for (let i = 0; i <= this.segments; i++) {let angle = (i / this.segments) * Math.PI * 2; // 计算角度let x = Math.cos(angle) * this.radius; // 计算 x 坐标let y = Math.sin(angle) * this.radius; // 计算 y 坐标positions.push(cc.v2(x, y)); // 添加顶点uvs.push(cc.v2((x / this.radius + 1) / 2, 1-(y / this.radius + 1) / 2)); // 添加 UVcolors.push(cc.Color.WHITE); // 添加颜色}// 设置索引(三角形扇)for (let i = 1; i <= this.segments; i++) {indices.push(0); // 圆心indices.push(i); // 当前顶点indices.push(i + 1); // 下一个顶点}mesh.init(new gfx.VertexFormat([{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },{ name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },]), positions.length, true);mesh.setVertices(gfx.ATTR_POSITION, positions);mesh.setVertices(gfx.ATTR_UV0, uvs);mesh.setIndices(indices);this.renderer.mesh = mesh;},// 更新图片_applySpriteFrame() {// cc.log('_applySpriteFrame');if (this.spriteFrame) {const renderer = this.renderer;let material = renderer._materials[0];// Reset materiallet texture = this.spriteFrame.getTexture();material.define("USE_DIFFUSE_TEXTURE", true);material.setProperty('diffuseTexture', texture);}}
});
这个js组件,绑定到节点上,把要渲染的spriteFrame挂在上面,运行就可以了,这种方式只适合单独图片,不适合图集中的图片

运行效果,下面是对比了这个图片
说明:这种方式是直
接修改图片的mesh网格结构,使用meshRenderer组件,不能挂载sprite组件,使用shader也可以达到效果,但是shader是在Gpu层修改显示,图片形状没有变,这个是运行的时候直接修改形状,而且shader修改的话会有问题,例如打断动态合批,如果项目勾选了动态合批或者图片在图集中,shader修改是无效的
这种方式可以降低mask增加的drawcall
2.工具式的,直接调用,升级版,可以修改图集中的某个图片的显示
const { ccclass, property } = cc._decorator;const gfx = cc.gfx;
cc.Class({extends: cc.Component,properties: {radius: 100, // 圆的半径segments: 32, // 圆的细分段数(顶点数)/*** !#en The sprite frame of the sprite.* !#zh 精灵的精灵帧* @property spriteFrame* @type {spriteFrame}*/spriteFrame: {default: null,type: cc.spriteFrame,},},/**设置数据显示 需要等spriteFrame加载完成后调用,可以拿到实际的图片* radius: 半径* segments: 圆细分段数,越多会越圆滑,但是性能消耗会更大* node:节点,这里需要使用mesheRenderer组件,所以需要把sprite剔除* isAtlas:是否是图集中的图片*/setDataShow(node, radius, segments, isAtlas) {// MeshRendererlet renderer = this.node.getComponent(cc.MeshRenderer);if (!renderer) {renderer = this.node.addComponent(cc.MeshRenderer);}renderer.mesh = null;this.renderer = renderer;let builtinMaterial = cc.MaterialVariant.createWithBuiltin("unlit");renderer.setMaterial(0, builtinMaterial);renderer.enabled = false;this.radius = radius;this.segments = segments;let sp = node.getComponent(cc.Sprite);if (sp) {this.spriteFrame = sp.spriteFrame;node.removeComponent(cc.Sprite);}// 把图片加载到renderer上的材质this.applySpriteFrame();// 设置meshif (isAtlas) {// 大图集中的texturethis.setMeshByAtlas();} else {// 单个图片this.setMesh();}// 这里必须延迟一帧,不然不会刷新mesh,显示不出来图片setTimeout(() => {if(cc.isValid(renderer)){renderer.enabled = true;}}, 100);},/**更新mesh,在图集中的 */setMeshByAtlas() {let uv = this.spriteFrame.uv;// 创建 Meshlet mesh = new cc.Mesh();// 计算顶点和 UVlet positions = [];let uvs = [];let indices = [];let colors = [];// 圆心顶点positions.push(cc.v2(0, 0)); // 圆心uvs.push(cc.v2((uv[6] + uv[0]) / 2, (uv[7] + uv[1]) / 2)); // 圆心 UV(取中心点)colors.push(cc.Color.WHITE); // 圆心颜色// 圆边缘顶点for (let i = 0; i <= this.segments; i++) {let angle = (i / this.segments) * Math.PI * 2; // 计算角度let x = Math.cos(angle) * this.radius; // 计算 x 坐标let y = Math.sin(angle) * this.radius; // 计算 y 坐标positions.push(cc.v2(x, y)); // 添加顶点// 计算 UV 坐标(根据图集的 UV 信息进行映射)let u = (x / this.radius + 1) / 2; // 归一化到 [0, 1]let v = (y / this.radius + 1) / 2; // 归一化到 [0, 1]let uvX = uv[0] + (uv[2] - uv[0]) * u; // 根据图集 UV 计算实际 UVlet uvY = uv[1] + (uv[5] - uv[1]) * v; // 根据图集 UV 计算实际 UVuvs.push(cc.v2(uvX, uvY)); // 添加 UVcolors.push(cc.Color.WHITE); // 添加颜色}// 设置索引(三角形扇)for (let i = 1; i <= this.segments; i++) {indices.push(0); // 圆心indices.push(i); // 当前顶点indices.push(i + 1); // 下一个顶点}mesh.init(new gfx.VertexFormat([{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },{ name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },]), positions.length, true);mesh.setVertices(gfx.ATTR_POSITION, positions);mesh.setVertices(gfx.ATTR_UV0, uvs);mesh.setIndices(indices);this.renderer.mesh = mesh;},// 更新mesh,单独图片的setMesh() {// 创建 Meshlet mesh = new cc.Mesh();// 计算顶点和 UVlet positions = [];let uvs = [];let indices = [];let colors = [];// 圆心顶点positions.push(cc.v2(0, 0)); // 圆心uvs.push(cc.v2(0.5, 0.5)); // 圆心 UVcolors.push(cc.Color.WHITE); // 圆心颜色// 圆边缘顶点for (let i = 0; i <= this.segments; i++) {let angle = (i / this.segments) * Math.PI * 2; // 计算角度let x = Math.cos(angle) * this.radius; // 计算 x 坐标let y = Math.sin(angle) * this.radius; // 计算 y 坐标positions.push(cc.v2(x, y)); // 添加顶点uvs.push(cc.v2((x / this.radius + 1) / 2, (y / this.radius + 1) / 2)); // 添加 UVcolors.push(cc.Color.WHITE); // 添加颜色}// 设置索引(三角形扇)for (let i = 1; i <= this.segments; i++) {indices.push(0); // 圆心indices.push(i); // 当前顶点indices.push(i + 1); // 下一个顶点}mesh.init(new gfx.VertexFormat([{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },{ name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },]), positions.length, true);mesh.setVertices(gfx.ATTR_POSITION, positions);mesh.setVertices(gfx.ATTR_UV0, uvs);mesh.setIndices(indices);this.renderer.mesh = mesh;},// 更新图片applySpriteFrame() {// cc.log('_applySpriteFrame');if (this.spriteFrame) {const renderer = this.renderer;let material = renderer._materials[0];// Reset materialmaterial.define("USE_DIFFUSE_TEXTURE", true);material.setProperty('diffuseTexture', this.spriteFrame.getTexture());}},});
外部调用这个组件的方法,setDataShow传对应的参数就可以,节点上需要挂sprite组件,sprite更新图片或者初始化加载的时候,调用这个方法setDataShow,同时兼容删除节点的sprite组件,如果不想挂载sprite组件,默认直接挂上meshRenderer组件,需要自己修改下代码,把参数node直接改成传对应的spriteFrame图片

Cocos Creator 的纹理坐标系(UV 坐标系)的 Y 轴方向是 从上到下 的,如果结果图片y是反向的,可以设代码修改uvs中的y的取值
-
将
v的计算改为1 - (y / radius + 1) / 2,即对 Y 方向取反。
相关文章:
cocos creator使用mesh修改图片为圆形,减少使用mask,j减少drawcall,优化性能
cocos creator版本2.4.11 一个mask占用drawcall 3个以上,针对游戏中技能图标,cd,以及多玩家头像,是有很大优化空间 1.上代码,只适合单独图片的,不适合在图集中的图片 const { ccclass, property } cc._decorator;c…...
C++ Qt开发成长之路,从入门到企业级实战项目,保姆级学习路线
Qt 介绍 Qt是一个跨平台的C图形用户界面应用程序开发框架,最初由挪威的Trolltech公司开发,后来被诺基亚收购,现在由Qt公司维护。它提供了丰富的工具和类库,使开发者能够轻松地创建各种类型的应用程序,包括桌面应用、移…...
JavaWeb后端基础(7)AOP
AOP是Spring框架的核心之一,那什么是AOP?AOP:Aspect Oriented Programming(面向切面编程、面向方面编程),其实说白了,面向切面编程就是面向特定方法编程。AOP是一种思想,而在Spring框…...
Uniapp实现地图获取定位功能
摘要:本文将手把手教你如何在Uniapp项目中集成地图功能、实现定位获取,并解决微信小程序、APP、H5三端的兼容性问题🚀🚀🚀 一、环境准备 地图平台选择 微信小程序:腾讯地图(强制使用)…...
批量将 Excel 转换 PDF/Word/CSV以及图片等其它格式
Excel 格式转换是我们工作过程当中非常常见的一个需求,我们通常需要将 Excel 转换为其他各种各样的格式。比如将 Excel 转换为 PDF、比如说将 Excel 转换为 Word、再比如说将 Excel文档转换为图片等等。 这些操作对我们来讲都不难,因为我们通过 Office 都…...
Flutter:StatelessWidget vs StatefulWidget 深度解析
目录 1. 引言 2. StatelessWidget(无状态组件) 2.1 定义与特点 2.2 代码示例 3. StatefulWidget(有状态组件) 3.1 定义与特点 3.2 代码示例 4. StatelessWidget vs StatefulWidget 对比 5. StatefulWidget 生命周期 5.1…...
Stream流学习
Stream流 把数据放进stream流水线,对数据进行一系列操作(中间方法),最后封装(终结方法)。 Stream.of()允许传入任何参数 常见中间方法 可以对数据进行链式(流水线)操作,但…...
多视图几何--恢复相机位姿/内参的几种方法
恢复相机位姿的几种方法 1分解投影矩阵 1.1投影矩阵分解为相机内外参矩阵的完整解析 投影矩阵(Projection Matrix)是计算机视觉中将三维世界点映射到二维像素坐标的核心工具,其本质是相机内参矩阵(Intrinsic Matrix)…...
[数据结构]堆详解
目录 一、堆的概念及结构 二、堆的实现 1.堆的定义 2堆的初始化 3堆的插入 编辑 4.堆的删除 5堆的其他操作 6代码合集 三、堆的应用 (一)堆排序(重点) (二)TOP-K问题 一、堆的概念及结构 堆的…...
领域驱动设计(DDD)与MVC架构:理念对比与架构选择
领域驱动设计(DDD)与MVC架构:理念对比与架构选择 一、架构之争的本质:业务复杂度驱动技术演进 在软件开发领域,没有银弹式的完美架构,只有适合当前业务场景的合理选择。MVC与DDD的区别本质上是业务复杂度与…...
牛客周赛:84:B:JAVA
链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 题目描述 import java.util.ArrayList; import java.util.Arrays; import java.util.Scanner; public class Main {public static void main(String[] args) {Scanner scanner new Scanner(S…...
【理想解法学习笔记】
目录 理想解法原理简介算法步骤属性值规范化方法代码示例 理想解法 原理简介 TOPSIS(Technique for Order Preference by Simi larity to IdealSolution)法是一种逼近理想解的排序方法。其基本的处理思路是:首先建立初始化决策矩阵,而后基于规范化后的初…...
CI/CD—Jenkins配置一次完整的jar自动化发布流程
背景: 实现设想: 要创建自动化发布,需要准备一台测试服务器提前安装好java运行所需的环境,JDK版本最好和Windows开发机器上的版本一致,在Jenkins上配置将构建好的jar上传到测试服务器上,测试服务器自动启动…...
Magento2根据图片文件包导入产品图片
图片包给的图片文件是子产品的图片,如下图:A104255是主产品的sku <?php/*** 根据图片包导入产品图片,包含子产品和主产品* 子产品是作为主图,主产品是作为附加图片*/use Magento\Framework\App\Bootstrap;include(../app/boot…...
从零开始的python学习(五)P71+P72+P73+P74
本文章记录观看B站python教程学习笔记和实践感悟,视频链接:【花了2万多买的Python教程全套,现在分享给大家,入门到精通(Python全栈开发教程)】 https://www.bilibili.com/video/BV1wD4y1o7AS/?p6&share_sourcecopy_web&v…...
OpenHarmony5.0分布式系统源码实现分析—软总线
一、引言 OpenHarmony 作为一款面向万物互联的操作系统,其分布式软总线(Distributed SoftBus)是实现设备间高效通信和协同的核心技术之一。分布式软总线通过构建一个虚拟的总线网络,使得不同设备能够无缝连接、通信和协同工作。本…...
基于SpringBoot实现旅游酒店平台功能六
一、前言介绍: 1.1 项目摘要 随着社会的快速发展和人民生活水平的不断提高,旅游已经成为人们休闲娱乐的重要方式之一。人们越来越注重生活的品质和精神文化的追求,旅游需求呈现出爆发式增长。这种增长不仅体现在旅游人数的增加上࿰…...
代码随想录算法训练营第六十一天 | 108. 冗余连接 109. 冗余连接II
108. 冗余连接 题目链接:KamaCoder 文档讲解:代码随想录 状态:AC Java代码: import java.util.*;class Main {public static int[] father;public static void main(String[] args) {Scanner scan new Scanner(System.in);int n…...
RoboVQA:机器人多模态长范围推理
23 年 11 月来自 Google Deepmind 的论文“RoboVQA: Multimodal Long-Horizon Reasoning for Robotics”。 本文提出一种可扩展、自下而上且本质多样化的数据收集方案,该方案可用于长期和中期的高级推理,与传统的狭窄自上而下的逐步收集相比,…...
TCP/IP原理详细解析
前言 TCP/IP是一种面向连接,可靠的传输,传输数据大小无限制的。通常情况下,系统与系统之间的http连接需要三次握手和四次挥手,这个执行过程会产生等待时间。这方面在日常开发时需要注意一下。 TCP/IP 是互联网的核心协议族&…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
自然语言处理——文本分类
文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益(IG) 分类器设计贝叶斯理论:线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别, 有单标签多类别文本分类和多…...
