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

cocoscreator性能优化4-Sprite颜色数据去除

前言

 

Sprite是游戏内容的一个基本组成元素,包括ui、道具、立绘等各种地方都会用到。大部分情况下美术会帮我们调好图片颜色,我们只要把图片直接放到游戏里就行了。Sprite默认的渲染顶点数据中包含了颜色数据,由于我们并不需要去修改颜色,某些情况下这似乎是一个不必要的东西。

去年底的时候,由于希望在性能优化方面做一些研究,在论坛找到了江南百景图研发负责人的技术分享文章,其中提到:

优化 Shader 的输入数据

由于《江南百景图》的图片资源中不会用到 Color 这个属性,因此在材质中,我们将原有的 Color 数据去除掉。

将原有的 Color 数据去除掉。用来存放项目中所需要的其它信息,这样做可以减少 CPU 与 GPU 互相传输的数据量。

本文参照文章中的思路实现了这个优化。

开发环境

浏览器:Chrome

开发语言:JavaScript

引擎版本:CocosCreator 2.4.3

词语缩写对照

顶点格式:顶点数据格式。

研究过程

按照思路,需要改动Sprite渲染相关代码,以及修改对应的材质。

翻源码找出,Sprite对应的assembler是SimpleSpriteAssembler(渲染模式为simple时)

源码位于:cocos2d\core\renderer\webgl\assemblers\sprite\2d\simple.js

其继承关系为:cc.Assembler->cc.Assembler2D->SimpleSpriteAssembler。

缕清关系后,我们要找出顶点数据格式是在哪定义的。assembler用于填充顶点数据,所以我们到Assembler.js中找找。

import { vfmtPosUvColor } from './webgl/vertex-format';
export default class Assembler {getVfmt () {return vfmtPosUvColor;}
}

找到了!默认顶点格式就是这个vfmtPosUvColor

var vfmtPosUvColor = 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 },{ name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
]);

从vfmtPosUvColor的定义可以看出,顶点数据中含有三个数据(括号里的英文对应材质中的输入变量名):

  1. ATTR_POSITION(a_position 位置)
  2. ATTR_UV0(a_uv0 uv)
  3. ATTR_COLOR(a_color 颜色)

很明显ATTR_COLOR就是我们今天的目标

弄清楚顶点格式后,下一步是找到填充这些数据的地方。

顶点数据保存于RenderData,这三个数据是分开填充的,避免有些时候只需要更新其中一个(如只是移动了位置),却要全部跑一遍。顶点数据填充时,是按定义好的顺序填充的,此处引用论坛文章的图:

由于我们只是去除最后的color,所以位置和uv的填充函数是不需要修改的(在一个顶点数据中的相对位置没有发生改变)。

找出颜色填充函数,updateColor函数声明于assembler-2d.js。

updateColor (comp, color) {let uintVerts = this._renderData.uintVDatas[0];if (!uintVerts) return;color = color != null ? color : comp.node.color._val;let floatsPerVert = this.floatsPerVert;let colorOffset = this.colorOffset;for (let i = colorOffset, l = uintVerts.length; i < l; i += floatsPerVert) {uintVerts[i] = color;}
}

函数中将颜色值填充在每个顶点数据的末尾(position和uv之后)。我们需要修改updateColor函数,因为不再需要填充颜色值了

实现思路

看完又是要改源码了。不过还是可以通过继承相关类实现。继承方案相对来说会比较麻烦,但在实验阶段需要频繁修改时会更方便快速。

我们需要自定义Sprite、Assembler、Material、Effect。分别命名为NoColorSprite、NoColorSpriteAssembler、noColorMaterial、noColorEffect。

需求可拆分为如下实现步骤:

  1. 新建noColorEffect及noColorMaterial,在内置的代码基础上,去除颜色相关内容。
  2. 新建NoColorSpriteAssembler,新建顶点格式,并重写/实现渲染数据填充的相关函数。
  3. 新建NoColorSprite,将默认的assembler改为我们自己的NoColorSpriteAssembler。

代码

第一步是effect和material,主要工作是删代码(颜色相关的)... 新建的material只要将effect引用改为noColorEffect即可。

// 删除颜色相关输入输出处理
CCProgram vs %{precision highp float;#include <cc-global>#include <cc-local>in vec3 a_position;#if USE_TEXTUREin vec2 a_uv0;out vec2 v_uv0;#endifvoid main () {vec4 pos = vec4(a_position, 1);#if CC_USE_MODELpos = cc_matViewProj * cc_matWorld * pos;#elsepos = cc_matViewProj * pos;#endif#if USE_TEXTUREv_uv0 = a_uv0;#endifgl_Position = pos;}
}%// 删除颜色相关输入处理 输出颜色直接取像素颜色
CCProgram fs %{precision highp float;#include <alpha-test>#include <texture>#if USE_TEXTUREin vec2 v_uv0;uniform sampler2D texture;#endifvoid main () {vec4 o = vec4(1, 1, 1, 1);#if USE_TEXTURECCTexture(texture, v_uv0, o);#endifALPHA_TEST(o);gl_FragColor = o;}
}%

接着,创建NoColorSpriteAssembler.js,自定义顶点格式,去掉默认的颜色字段

let gfx = cc.gfx;
let vfmtNoColor = 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 },        // texture纹理uv
]);

我们只是想去除颜色,可以通过继承cc.Assembler实现noColorMaterial,其他渲染相关代码则可以从Assembler2D及SimpleSpriteAssembler中复制。这里贴出主要的代码。

因为我们修改了顶点格式,需要同步修改相关值。这里重写构造函数进行修改。

floatsPerVert是顶点格式数据长度(用浮点数计算),原本是5个浮点数,这里去掉了颜色,所以改为4。其他数据照抄Assembler2D中的值即可。

export default class NoColorAssembler extends cc.Assembler {constructor () {super();// uv在顶点数据中的偏移位置(前面有两个float的值表示position)this.uvOffset = 2;// 每个顶点的浮点数数量(position 2浮点数,uv 2浮点数)this.floatsPerVert = 4;// 顶点数量 (可以用4个点来表示两个三角形)this.verticesCount = 4;// 顶点索引数量 (两个三角形共6个顶点索引) 这个部分可以看链接中的文章有说明。this.indicesCount = 6;this.initData();this.initLocal();}
}

修改顶点数据格式后,我们需要一个不一样的RenderData来存储这些数据,模仿Assembler2D实现initData函数,在里面按我们定义的格式创建RenderData

/**
* 初始化this._renderData 仿照Assembler2D.initData 创建自定义格式的renderData
*/
initData () {let data = this._renderData = new cc.RenderData();this._renderData.init(this);// 按我们自己的格式创建RenderDatadata.createFlexData(0, this.verticesCount, this.indicesCount, this.getVfmt());// createFlexData不会填充顶点索引信息,手动补充一下 仿照cc.RenderData.initQuadIndiceslet indices = data.iDatas[0];let count = indices.length / 6;for (let i = 0, idx = 0; i < count; i++) {let vertextID = i * 4;indices[idx++] = vertextID;indices[idx++] = vertextID+1;indices[idx++] = vertextID+2;indices[idx++] = vertextID+1;indices[idx++] = vertextID+3;indices[idx++] = vertextID+2;}
}

再之后是本文的重点,把颜色的填充功能去掉

/**
* 更新颜色 啥也不干😆
*/
updateColor () {
}

最后,改动顶点数据格式后还有一些需要同步修改的地方。

/**
* 获得存放自定义顶点数据的buffer
* @returns {cc.MeshBuffer}
*/
getBuffer() {return cc.renderer._handle.getBuffer("mesh", this.getVfmt());
}
/**
* 获得顶点数据格式
* 重写 返回自定义的顶点数据格式
* @returns {cc.gfx.VertexFormat}
*/
getVfmt () {return vfmtNoColor;
}

代码有点长,没有全部贴出来。可以在后面的源码附件中查看,其他函数基本是从Assembler2D及SimpleSpriteAssembler复制出来的。

最最最后,如果产生一些如继承、函数为空之类的报错,可以在creator.d.ts文件中增加以下声明。

declare namespace cc {export class Assembler {public _renderComp: cc.RenderComponent;public init(comp: cc.RenderComponent);public getVfmt();static public register(renderCompCtor, assembler);}export class RenderData {init(assembler: cc.Assembler);createQuadData(index, verticesFloats, indicesCount);createFlexData(index, verticesFloats, indicesCount, vfmt): cc.FlexBuffer;initQuadIndices(idata);vDatas;uintVDatas;iDatas;meshCount: number;_infos;_flexBuffer;}
}

效果对比

测试案例

一个sprite,复制200次。分别使用默认的cc.Sprite和我们实现的NoColorSprite。

使用console.time函数结合cc.Director中的EVENT_BEFORE_UPDATE、EVENT_AFTER_UPDATE、EVENT_AFTER_DRAW事件统计前两百帧的游戏逻辑耗时及渲染耗时。

耗时对比如下:

绿色线为优化前,蓝色线为优化后。可以看出均有一定程度的减少。

render耗时由于前几帧较高,图表看起来比较奇怪,再贴一张去掉前三帧的对比图。

总结

简单来说,少了1/5的数据传输量,material中也不需要计算颜色,优化效果是可想而知的。

本优化并不适用于所有项目,由于颜色数据被去除了,透明度作为颜色值的其中一项,也不再生效了。图片本身的透明度会被保留,但无法再通过修改节点的透明度进行动态修改。

相关文章:

cocoscreator性能优化4-Sprite颜色数据去除

前言 Sprite是游戏内容的一个基本组成元素&#xff0c;包括ui、道具、立绘等各种地方都会用到。大部分情况下美术会帮我们调好图片颜色&#xff0c;我们只要把图片直接放到游戏里就行了。Sprite默认的渲染顶点数据中包含了颜色数据&#xff0c;由于我们并不需要去修改颜色&…...

系统接口幂等性设计探究

前言&#xff1a; 刚开始工作的时候写了一个带UI页面的工具&#xff0c;需要设计登录功能&#xff0c;登录功能也很简单&#xff0c;输入用户名密码点击登录&#xff0c;触发后台查询并比对密码&#xff0c;如果登录成功则返回消息给前端&#xff0c;前端把消息弹出提示一下。…...

C learning_7

目录 1.for循环 1.虽然while循环和for循环本质上都可以实现循环&#xff0c;但是它们在使用方法和场合上还是有一些区别的。 2.while循环中存在循环的三个必须条件&#xff0c;但是由于风格的问题使得三个部分很可能偏离较远&#xff0c;这样 查找修改就不够集中和方便。所以…...

PageRank算法介绍

互联网上有数百亿个网页&#xff0c;可以分为这么几类&#xff1a;不含有用信息的&#xff0c;比如垃圾邮件&#xff1b;少数人比较感兴趣的&#xff0c;但范围不是很广的&#xff0c;比如个人博客、婚礼公告或家庭像册&#xff1b;很多人感兴趣的并且十分有用的&#xff0c;比…...

springboot+vue职称评审管理系统(源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的职称评审管理系统。项目源码请联系风歌&#xff0c;文末附上联系信息 。 目前有各类成品java毕设&#xff0c;需要请看文末联系方式 …...

腾讯云4核8G轻量服务器12M支持多少访客同时在线?并发数怎么算?

腾讯云轻量4核8G12M轻量应用服务器支持多少人同时在线&#xff1f;通用型-4核8G-180G-2000G&#xff0c;2000GB月流量&#xff0c;系统盘为180GB SSD盘&#xff0c;12M公网带宽&#xff0c;下载速度峰值为1536KB/s&#xff0c;即1.5M/秒&#xff0c;假设网站内页平均大小为60KB…...

图片英文翻译成中文转换器-中文翻译英文软件

您正在准备一份重要的英文资料或文件&#xff0c;但是您还不是很熟练地掌握英文&#xff0c;需要翻译才能完成您的任务吗&#xff1f;哪个软件能够免费把英文文档翻译成中文&#xff1f;让我们带您了解如何使用我们的翻译软件来免费翻译英文文档为中文。 我们的翻译软件是一款功…...

月薪10k和40k的程序员差距有多大?

程序员的薪资一直是大家关注的焦点&#xff0c;相较于其他行业&#xff0c;程序员的高薪也是有目共睹的&#xff0c;而不同等级的程序员处理问题的方式与他们的薪资直接挂钩。 接下来就一起看一下月薪10k、20k、30k、40k的程序员面对问题都是怎么处理的吧&#xff01; 场景一 …...

gateway整合knife4j(微服务在线文档)

文章目录 knife4j 微服务整合一、微服务与单体项目文档整合的区别二、开始整合1. 搭建一个父子maven模块的微服务,并引入gateway2.开始整合文档 总结 knife4j 微服务整合 由于单个服务的knife4j 整合之前已经写过了,那么由于效果比较好,然后微服务的项目中也想引入,所以开始微…...

ASP.NET 记录 HttpRequest HttpResponse HttpServerUtility

纯属个人记录,会有错误 HttpRequest Browser是获取客户端浏览器的信息 Cookies是获取客户端的Cookies QueryString是获取客户端提交的数据 ServerVariables是获取服务器端或客户端的环境变量信息 Browser 语法格式: Request.Browser[“浏览器特性名”] 常见的特性名 名称说…...

Python 人工智能:11~15

原文&#xff1a;Artificial Intelligence with Python 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 不要担心自己的形象&#xff0c;只关心如何…...

辉煌优配|军工板块逆市上涨,16只概念股已披露一季度业绩预喜

今日&#xff0c;军工股逆市上涨。 4月21日&#xff0c;A股三大股指低开低走&#xff0c;半导体、AI使用、信创工业、软件等科技属性概念领跌&#xff0c;国防军工、食品饮料和电力设备等板块上涨。 工业互联网中心工业规模超1.2万亿元 据央视新闻报道&#xff0c;本年是《工业…...

看板与 Scrum:有什么区别?

看板和Scrum是项目管理方法论&#xff0c;以小增量完成项目任务并强调持续改进。但是他们用来实现这些目标的过程是不同的。看板以可视化任务和连续流程为中心&#xff0c;而Scrum更多是关于为每个交付周期实施时间表和分配设定角色。 在看板和Scrum之间做出选择并不总是必要…...

零代码是什么?零代码平台适合谁用?

随着信息技术的发展&#xff0c;软件开发领域也不断发生变革&#xff0c;零代码&#xff08;No-Code&#xff09;开发模式越来越受到关注。 零代码到底是什么&#xff0c;能不能用通俗的话来说&#xff1f;这就来给大家讲一讲&#xff01; 01 零代码为什么出现&#xff1f; 随…...

CNStack 云服务云组件:打造丰富的云原生技术中台生态

作者&#xff1a;刘裕惺 CNStack 相关阅读&#xff1a; CNStack 多集群服务&#xff1a;基于OCM 打造完善的集群管理能力 CNStack 虚拟化服务&#xff1a;实现虚拟机和容器资源的共池管理 CNStack 云边协同平台&#xff1a;实现原生边缘竟能如此简单 01 前言 CNStack 2.0…...

#PythonPytorch 1.如何入门深度学习模型

我之前也写过一篇关于Keras的深度学习入门blog&#xff0c;#Python&Keras 1.如何从无到有在自己的数据集上实现深度学习模型&#xff08;入门&#xff09;&#xff0c;里面也有介绍了一下一点点机器学习的概念和理解深度学习的输入&#xff0c;如果对这方面有疑惑的朋友可以…...

[API]节点流和处理流字节流和字符流(七)

java将流分为节点流和处理流两类&#xff1a; 节点流&#xff1a;也称为低级流&#xff0c;是真实连接程序和另一端的"管道"&#xff0c;负责实际读写数据的流&#xff0c;读写一定是建立在节点流的基础之上进行的。节点流好比家里的"自来水管"&#xff0c…...

开心档之C++ 模板

C 模板 目录 C 模板 函数模板 实例 类模板 实例 模板是泛型编程的基础&#xff0c;泛型编程即以一种独立于任何特定类型的方式编写代码。 模板是创建泛型类或函数的蓝图或公式。库容器&#xff0c;比如迭代器和算法&#xff0c;都是泛型编程的例子&#xff0c;它们都使用…...

拥抱还是革命,ChatGPT时代 AI专家给出15条科研生存之道

来源&#xff1a;专知 微信号&#xff1a;Quan_Zhuanzhi 你是学术机构的人工智能研究员吗?你是否担心自己无法应对当前人工智能的发展步伐?您是否觉得您没有(或非常有限)访问人工智能研究突破所需的计算和人力资源?你并不孤单; 我们有同样的感觉。越来越多的人工智能学者不…...

python算法中的数学算法(详解下)

目录 一. 学习目标: 二. 学习内容: Ⅰ. 数值优化 ①、均值 ②、方差 ③、协方差...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...