当前位置: 首页 > 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 是互联网的核心协议族&…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

LRU 缓存机制详解与实现(Java版) + 力扣解决

&#x1f4cc; LRU 缓存机制详解与实现&#xff08;Java版&#xff09; 一、&#x1f4d6; 问题背景 在日常开发中&#xff0c;我们经常会使用 缓存&#xff08;Cache&#xff09; 来提升性能。但由于内存有限&#xff0c;缓存不可能无限增长&#xff0c;于是需要策略决定&am…...

多模态图像修复系统:基于深度学习的图片修复实现

多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...