[engine] 多纹理渲染 - 支持 cc.Label(not char cache mode)、cc.RichText、cc.Sprite、cc.MotionStreak 组件

This commit is contained in:
SmallMain
2022-06-25 00:43:02 +08:00
parent 7d0519ed68
commit 1b236db58e
32 changed files with 1438 additions and 141 deletions

View File

@@ -192,7 +192,7 @@ let Label = cc.Class({
editor: CC_EDITOR && {
menu: 'i18n:MAIN_MENU.component.renderers/Label',
help: 'i18n:COMPONENT.help_url.label',
inspector: 'packages://inspector/inspectors/comps/label.js',
inspector: 'packages://service-pack/inspectors/comps/label.js',
},
properties: {
@@ -578,6 +578,11 @@ let Label = cc.Class({
},
tooltip: CC_DEV && 'i18n:COMPONENT.label.underline_height',
},
autoSwitchMaterial: {
type: RenderComponent.EnableType,
default: RenderComponent.EnableType.GLOBAL,
},
},
statics: {
@@ -782,7 +787,25 @@ let Label = cc.Class({
}
if (!this._frame) return;
material && material.setProperty('texture', this._frame._texture);
if (material) {
// 根据材质更新 uniform
const isMultiMaterial = material.material.isMultiSupport();
if (isMultiMaterial) {
// 贴图在 updateRenderData 才确定下来
// if (texture) this._updateMultiTexId(material, texture);
this._texIdDirty = true;
} else {
material.setProperty('texture', this._frame._texture);
}
// 根据材质更新 assembler
if (this._assembler) {
if ((isMultiMaterial && !this._assembler.isMulti) || !isMultiMaterial && this._assembler.isMulti) {
RenderComponent.prototype._resetAssembler.call(this);
}
}
}
BlendFunc.prototype._updateMaterial.call(this);
},

View File

@@ -161,6 +161,10 @@ var MotionStreak = cc.Class({
if (this._texture === value) return;
this._texture = value;
// 自动切换材质
this._checkSwitchMaterial();
this._updateMaterial();
},
type: cc.Texture2D,
@@ -210,6 +214,25 @@ var MotionStreak = cc.Class({
},
animatable: false,
tooltip: CC_DEV && 'i18n:COMPONENT.motionStreak.fastMode'
},
autoSwitchMaterial: {
type: RenderComponent.EnableType,
default: RenderComponent.EnableType.GLOBAL,
},
},
__preload() {
this._super();
this._checkSwitchMaterial();
},
_checkSwitchMaterial() {
if (this._assembler) {
const material = this._materials[0];
if (!material) return;
if (!this._texture) return;
this._assembler.checkAndSwitchMaterial(this, this._texture, material);
}
},
@@ -220,7 +243,32 @@ var MotionStreak = cc.Class({
_updateMaterial () {
let material = this.getMaterial(0);
material && material.setProperty('texture', this._texture);
// 根据材质更新 uniform
const isMultiMaterial = material.material.isMultiSupport();
if (isMultiMaterial) {
if (!this._texture) return;
this._updateMultiTexId(material, this._texture);
} else {
const textureImpl = this._texture && this._texture.getImpl();
if (material.getProperty('texture') !== textureImpl) {
material.setProperty('texture', this._texture);
}
}
// 根据材质更新 assembler
if (this._assembler) {
if ((isMultiMaterial && !this._assembler.isMulti) || !isMultiMaterial && this._assembler.isMulti) {
this._resetAssembler();
}
}
// texId
if (isMultiMaterial && this._texIdDirty && this._assembler) {
if (!this._texture) return;
this._assembler.updateTexId(this);
this._texIdDirty = false;
}
BlendFunc.prototype._updateMaterial.call(this);
},

View File

@@ -33,6 +33,32 @@ const Material = require('../assets/material/CCMaterial');
let _temp_color = new Color();
/**
* !#en enable type
* !#zh 启用类型
* @enum RenderComponent.EnableType
*/
var EnableType = cc.Enum({
/**
* !#en Global.
* !#zh 使用全局值
* @property {Number} GLOBAL
*/
GLOBAL: 0,
/**
* !#en Enable.
* !#zh 开启
* @property {Number} ENABLE
*/
ENABLE: 1,
/**
* !#en Disable.
* !#zh 关闭
* @property {Number} DISABLE
*/
DISABLE: 2,
});
/**
* !#en
* Base class for components which supports rendering features.
@@ -51,6 +77,10 @@ let RenderComponent = cc.Class({
disallowMultiple: true
},
statics: {
EnableType: EnableType,
},
properties: {
_materials: {
default: [],
@@ -78,12 +108,16 @@ let RenderComponent = cc.Class({
ctor () {
this._vertsDirty = true;
this._texIdDirty = true;
this._texId = 0;
this._assembler = null;
},
_resetAssembler () {
Assembler.init(this);
this._updateColor();
// 切换 Assembler 时texId 与 vDatas 数据不同步
this._texId = 0;
this.setVertsDirty();
},
@@ -252,7 +286,43 @@ let RenderComponent = cc.Class({
renderer.material = material;
renderer.cullingMask = cullingMask;
}
}
},
_updateMultiTexId(material, texture) {
const multi = material.material.getMultiHandler();
const spTexture = texture;
const nSpTexture = spTexture.getImpl();
// 快速检查插槽上的贴图是否相同
// 如果是当作普通材质使用multi.getTexture(this._texId) !== nSpTexture 会一直为 true
const same = this._texId === 0
? material.getProperty('texture') !== nSpTexture
: multi.getTexture(this._texId) !== nSpTexture;
if (same) {
// 如果材质变体被修改了,则直接跳过位置检查
const isChanged = Object.prototype.hasOwnProperty.call(material._effect._passes['0']._properties, 'texture');
const texId = isChanged ? -1 : multi.getIndex(nSpTexture);
if (texId !== -1) {
// 插槽位置不对,则更新位置
this._texId = texId;
this._texIdDirty = true;
} else {
// 插槽根本没有该纹理,则修改变体的 texture
material.setProperty('texture', spTexture);
if (this._texId !== 0) {
this._texId = 0;
this._texIdDirty = true;
}
// cc.warn('renderComponent use multi-material but not has valid property.');
}
} else {
this._texIdDirty = false;
}
},
});
cc.RenderComponent = module.exports = RenderComponent;

View File

@@ -28,6 +28,7 @@ const js = require('../platform/js');
const macro = require('../platform/CCMacro');
const textUtils = require('../utils/text-utils');
const HtmlTextParser = require('../utils/html-text-parser');
import MaterialVariant from '../assets/material/material-variant';
const _htmlTextParser = new HtmlTextParser();
const HorizontalAlign = macro.TextAlignment;
@@ -36,6 +37,8 @@ const RichTextChildName = "RICHTEXT_CHILD";
const RichTextChildImageName = "RICHTEXT_Image_CHILD";
const CacheMode = cc.Label.CacheMode;
const RenderComponent = require('./CCRenderComponent');
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
@@ -130,7 +133,7 @@ let RichText = cc.Class({
editor: CC_EDITOR && {
menu: 'i18n:MAIN_MENU.component.renderers/RichText',
help: 'i18n:COMPONENT.help_url.richtext',
inspector: 'packages://inspector/inspectors/comps/richtext.js',
inspector: 'packages://service-pack/inspectors/comps/richtext.js',
executeInEditMode: true
},
@@ -347,6 +350,30 @@ let RichText = cc.Class({
this.handleTouchEvent ? this._addEventListeners() : this._removeEventListeners();
}
}
},
autoSwitchMaterial: {
type: RenderComponent.EnableType,
default: RenderComponent.EnableType.GLOBAL,
notify: function (oldValue) {
if (this.autoSwitchMaterial === oldValue) return;
for (let i = 0; i < this._labelSegments.length; i++) {
const labelComponent = this._labelSegments[i].getComponent(cc.Label);
if (labelComponent) {
labelComponent.autoSwitchMaterial = this.autoSwitchMaterial;
}
const spriteComponent = this._labelSegments[i].getComponent(cc.Sprite);
if (spriteComponent) {
spriteComponent.autoSwitchMaterial = this.autoSwitchMaterial;
}
}
for (let i = 0; i < this._labelSegmentsCache.length; i++) {
const labelComponent = this._labelSegmentsCache[i].getComponent(cc.Label);
if (labelComponent) {
labelComponent.autoSwitchMaterial = this.autoSwitchMaterial;
}
}
}
}
},
@@ -653,6 +680,8 @@ let RichText = cc.Class({
let spriteNode = new cc.PrivateNode(RichTextChildImageName);
spriteNode._objFlags |= cc.Object.Flags.DontSave;
let spriteComponent = spriteNode.addComponent(cc.Sprite);
spriteComponent.autoSwitchMaterial = this.autoSwitchMaterial;
switch (richTextElement.style.imageAlign)
{
case 'top':
@@ -945,6 +974,7 @@ let RichText = cc.Class({
labelComponent.cacheMode = this.cacheMode;
labelComponent.autoSwitchMaterial = this.autoSwitchMaterial;
let isAsset = this.font instanceof cc.Font;
if (isAsset && !this._isSystemFontUsed) {
labelComponent.font = this.font;

View File

@@ -160,7 +160,7 @@ var Sprite = cc.Class({
editor: CC_EDITOR && {
menu: 'i18n:MAIN_MENU.component.renderers/Sprite',
help: 'i18n:COMPONENT.help_url.sprite',
inspector: 'packages://inspector/inspectors/comps/sprite.js',
inspector: 'packages://service-pack/inspectors/comps/sprite.js',
},
properties: {
@@ -386,7 +386,12 @@ var Sprite = cc.Class({
animatable: false,
type: SizeMode,
tooltip: CC_DEV && 'i18n:COMPONENT.sprite.size_mode'
}
},
autoSwitchMaterial: {
type: RenderComponent.EnableType,
default: RenderComponent.EnableType.GLOBAL,
},
},
statics: {
@@ -465,9 +470,25 @@ var Sprite = cc.Class({
if (oldDefine !== undefined && !oldDefine) {
material.define('USE_TEXTURE', true);
}
let textureImpl = texture && texture.getImpl();
if (material.getProperty('texture') !== textureImpl) {
material.setProperty('texture', texture);
// 根据材质更新 uniform
const isMultiMaterial = material.material.isMultiSupport();
if (isMultiMaterial) {
// 在 assembler 中进行更新性能会更好,不需要每次 setSpriteFrame 都更新,并且动态图集会导致两次触发
// if (texture) this._updateMultiTexId(material, texture);
this._texIdDirty = true;
} else {
const textureImpl = texture && texture.getImpl();
if (material.getProperty('texture') !== textureImpl) {
material.setProperty('texture', texture);
}
}
// 根据材质更新 assembler
if (this._assembler) {
if ((isMultiMaterial && !this._assembler.isMulti) || !isMultiMaterial && this._assembler.isMulti) {
this._resetAssembler();
}
}
}