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

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个以上&#xff0c;针对游戏中技能图标&#xff0c;cd,以及多玩家头像&#xff0c;是有很大优化空间 1.上代码&#xff0c;只适合单独图片的&#xff0c;不适合在图集中的图片 const { ccclass, property } cc._decorator;c…...

C++ Qt开发成长之路,从入门到企业级实战项目,保姆级学习路线

Qt 介绍 Qt是一个跨平台的C图形用户界面应用程序开发框架&#xff0c;最初由挪威的Trolltech公司开发&#xff0c;后来被诺基亚收购&#xff0c;现在由Qt公司维护。它提供了丰富的工具和类库&#xff0c;使开发者能够轻松地创建各种类型的应用程序&#xff0c;包括桌面应用、移…...

JavaWeb后端基础(7)AOP

AOP是Spring框架的核心之一&#xff0c;那什么是AOP&#xff1f;AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程、面向方面编程&#xff09;&#xff0c;其实说白了&#xff0c;面向切面编程就是面向特定方法编程。AOP是一种思想&#xff0c;而在Spring框…...

Uniapp实现地图获取定位功能

摘要&#xff1a;本文将手把手教你如何在Uniapp项目中集成地图功能、实现定位获取&#xff0c;并解决微信小程序、APP、H5三端的兼容性问题&#x1f680;&#x1f680;&#x1f680; 一、环境准备 地图平台选择 微信小程序&#xff1a;腾讯地图&#xff08;强制使用&#xff09…...

批量将 Excel 转换 PDF/Word/CSV以及图片等其它格式

Excel 格式转换是我们工作过程当中非常常见的一个需求&#xff0c;我们通常需要将 Excel 转换为其他各种各样的格式。比如将 Excel 转换为 PDF、比如说将 Excel 转换为 Word、再比如说将 Excel文档转换为图片等等。 这些操作对我们来讲都不难&#xff0c;因为我们通过 Office 都…...

Flutter:StatelessWidget vs StatefulWidget 深度解析

目录 1. 引言 2. StatelessWidget&#xff08;无状态组件&#xff09; 2.1 定义与特点 2.2 代码示例 3. StatefulWidget&#xff08;有状态组件&#xff09; 3.1 定义与特点 3.2 代码示例 4. StatelessWidget vs StatefulWidget 对比 5. StatefulWidget 生命周期 5.1…...

Stream流学习

Stream流 把数据放进stream流水线&#xff0c;对数据进行一系列操作&#xff08;中间方法&#xff09;&#xff0c;最后封装&#xff08;终结方法&#xff09;。 Stream.of()允许传入任何参数 常见中间方法 可以对数据进行链式&#xff08;流水线&#xff09;操作&#xff0c;但…...

多视图几何--恢复相机位姿/内参的几种方法

恢复相机位姿的几种方法 1分解投影矩阵 1.1投影矩阵分解为相机内外参矩阵的完整解析 投影矩阵&#xff08;Projection Matrix&#xff09;是计算机视觉中将三维世界点映射到二维像素坐标的核心工具&#xff0c;其本质是相机内参矩阵&#xff08;Intrinsic Matrix&#xff09…...

[数据结构]堆详解

目录 一、堆的概念及结构 二、堆的实现 1.堆的定义 2堆的初始化 3堆的插入 ​编辑 4.堆的删除 5堆的其他操作 6代码合集 三、堆的应用 &#xff08;一&#xff09;堆排序&#xff08;重点&#xff09; &#xff08;二&#xff09;TOP-K问题 一、堆的概念及结构 堆的…...

领域驱动设计(DDD)与MVC架构:理念对比与架构选择

领域驱动设计&#xff08;DDD&#xff09;与MVC架构&#xff1a;理念对比与架构选择 一、架构之争的本质&#xff1a;业务复杂度驱动技术演进 在软件开发领域&#xff0c;没有银弹式的完美架构&#xff0c;只有适合当前业务场景的合理选择。MVC与DDD的区别本质上是业务复杂度与…...

牛客周赛:84:B:JAVA

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 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)法是一种逼近理想解的排序方法。其基本的处理思路是&#xff1a;首先建立初始化决策矩阵&#xff0c;而后基于规范化后的初…...

CI/CD—Jenkins配置一次完整的jar自动化发布流程

背景&#xff1a; 实现设想&#xff1a; 要创建自动化发布&#xff0c;需要准备一台测试服务器提前安装好java运行所需的环境&#xff0c;JDK版本最好和Windows开发机器上的版本一致&#xff0c;在Jenkins上配置将构建好的jar上传到测试服务器上&#xff0c;测试服务器自动启动…...

Magento2根据图片文件包导入产品图片

图片包给的图片文件是子产品的图片&#xff0c;如下图&#xff1a;A104255是主产品的sku <?php/*** 根据图片包导入产品图片&#xff0c;包含子产品和主产品* 子产品是作为主图&#xff0c;主产品是作为附加图片*/use Magento\Framework\App\Bootstrap;include(../app/boot…...

从零开始的python学习(五)P71+P72+P73+P74

本文章记录观看B站python教程学习笔记和实践感悟&#xff0c;视频链接&#xff1a;【花了2万多买的Python教程全套&#xff0c;现在分享给大家&#xff0c;入门到精通(Python全栈开发教程)】 https://www.bilibili.com/video/BV1wD4y1o7AS/?p6&share_sourcecopy_web&v…...

OpenHarmony5.0分布式系统源码实现分析—软总线

一、引言 OpenHarmony 作为一款面向万物互联的操作系统&#xff0c;其分布式软总线&#xff08;Distributed SoftBus&#xff09;是实现设备间高效通信和协同的核心技术之一。分布式软总线通过构建一个虚拟的总线网络&#xff0c;使得不同设备能够无缝连接、通信和协同工作。本…...

基于SpringBoot实现旅游酒店平台功能六

一、前言介绍&#xff1a; 1.1 项目摘要 随着社会的快速发展和人民生活水平的不断提高&#xff0c;旅游已经成为人们休闲娱乐的重要方式之一。人们越来越注重生活的品质和精神文化的追求&#xff0c;旅游需求呈现出爆发式增长。这种增长不仅体现在旅游人数的增加上&#xff0…...

代码随想录算法训练营第六十一天 | 108. 冗余连接 109. 冗余连接II

108. 冗余连接 题目链接&#xff1a;KamaCoder 文档讲解&#xff1a;代码随想录 状态&#xff1a;AC Java代码&#xff1a; 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”。 本文提出一种可扩展、自下而上且本质多样化的数据收集方案&#xff0c;该方案可用于长期和中期的高级推理&#xff0c;与传统的狭窄自上而下的逐步收集相比&#xff0c…...

TCP/IP原理详细解析

前言 TCP/IP是一种面向连接&#xff0c;可靠的传输&#xff0c;传输数据大小无限制的。通常情况下&#xff0c;系统与系统之间的http连接需要三次握手和四次挥手&#xff0c;这个执行过程会产生等待时间。这方面在日常开发时需要注意一下。 TCP/IP 是互联网的核心协议族&…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

ubuntu22.04有线网络无法连接,图标也没了

今天突然无法有线网络无法连接任何设备&#xff0c;并且图标都没了 错误案例 往上一顿搜索&#xff0c;试了很多博客都不行&#xff0c;比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动&#xff0c;重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...