[engine] service pack 命名空间、多纹理渲染基础

This commit is contained in:
SmallMain 2022-06-25 00:29:47 +08:00
parent f31cb598e3
commit 7d0519ed68
8 changed files with 432 additions and 2 deletions

View File

@ -80,8 +80,50 @@ var builtins = {
} }
this._loadBuiltins('effect', () => { this._loadBuiltins('effect', () => {
this._loadBuiltins('material', cb); this._loadBuiltins('material', () => {
this._loadBuiltinsSP(cb);
}); });
});
},
_loadBuiltinsSP(cb) {
cc.sp.MAX_MULTITEXTURE_NUM = 8;
// cc.renderer.device.caps.maxTextureUnits
this._loadMultiEffect('multi-2d-sprite', (effect) => {
cc.sp.multi2dSpriteEffectAsset = effect;
effect.addRef();
cc.sp.inited = true;
cc.sp.multiBatcher.init();
cb();
});
},
_loadMultiEffect(name, cb) {
if (CC_EDITOR) {
cc.assetManager.loadAny(Editor.assetdb.remote.urlToUuid('db://service-pack-resources/sp/effects/' + name + '.effect'), function (err, effect) {
if (err) {
return Editor.error(err);
} else {
cb(effect);
}
});
} else {
cc.assetManager.loadBundle('sp', (err, bundle) => {
if (err) {
cc.error(err);
} else {
bundle.load('effects/' + name, cc.EffectAsset, (err, effect) => {
if (err) {
cc.error(err);
} else {
cb(effect);
}
});
}
});
}
}, },
/** /**

View File

@ -470,6 +470,9 @@ var Texture2D = cc.Class({
if (CC_EDITOR) { if (CC_EDITOR) {
this._exportedExts = null; this._exportedExts = null;
} }
// multi batcher
this._multiMaterial = null;
}, },
/** /**
@ -688,6 +691,8 @@ var Texture2D = cc.Class({
} }
this._packable && cc.dynamicAtlasManager && cc.dynamicAtlasManager.deleteAtlasTexture(this); this._packable && cc.dynamicAtlasManager && cc.dynamicAtlasManager.deleteAtlasTexture(this);
this.unlinkMaterial();
this._image = null; this._image = null;
this._texture && this._texture.destroy(); this._texture && this._texture.destroy();
this._super(); this._super();
@ -1054,7 +1059,43 @@ var Texture2D = cc.Class({
else { else {
cb(); cb();
} }
},
linkMaterial(material, index) {
const handler = material.getMultiHandler();
if (handler) {
if (index == null) {
if (handler.autoSetTexture(this) === -1) {
return false;
} }
} else {
handler.setTexture(index, this);
}
this.unlinkMaterial();
this._multiMaterial = material;
return true;
} else {
return false;
}
},
unlinkMaterial() {
if (this._multiMaterial) {
const handler = this._multiMaterial.getMultiHandler();
const _texture = this.getImpl();
handler.removeTexture(_texture);
this._multiMaterial = null;
}
},
getLinkedMaterial() {
return this._multiMaterial;
},
hasLinkedMaterial() {
return !!this._multiMaterial;
},
}); });
/** /**

View File

@ -72,6 +72,7 @@ let Material = cc.Class({
this._manualHash = false; this._manualHash = false;
this._dirty = true; this._dirty = true;
this._effect = null; this._effect = null;
this._multiHandler = null;
}, },
properties: { properties: {
@ -124,6 +125,8 @@ let Material = cc.Class({
} }
this._effect = this._effectAsset.getInstantiatedEffect(); this._effect = this._effectAsset.getInstantiatedEffect();
this.updateMultiSupport();
} }
}, },
@ -140,6 +143,7 @@ let Material = cc.Class({
set (v) { set (v) {
this._techniqueIndex = v; this._techniqueIndex = v;
this._effect.switchTechnique(v); this._effect.switchTechnique(v);
this.updateMultiSupport();
} }
} }
}, },
@ -401,7 +405,39 @@ let Material = cc.Class({
} }
} }
this.updateMultiSupport();
if (this._multiHandler) this._multiHandler.syncTextures();
}, },
updateMultiSupport() {
const passes = this._effect.technique.passes;
if (passes.length > 0 && passes[0].getDefine("USE_MULTI_TEXTURE")) {
this.setMultiSupport(true);
} else {
this.setMultiSupport(false);
}
},
isMultiSupport() {
return !!this._multiHandler;
},
setMultiSupport(bool) {
if (bool) {
if (this._multiHandler) {
this._multiHandler.syncTextures();
} else {
this._multiHandler = new cc.sp.MultiHandler(this);
}
} else if (!bool) {
this._multiHandler = null;
}
},
getMultiHandler() {
return this._multiHandler;
},
}); });
export default Material; export default Material;

View File

@ -40,6 +40,8 @@ if (!CC_EDITOR || !Editor.isMainProcess) {
require('./physics'); require('./physics');
require('./camera/CCCamera'); require('./camera/CCCamera');
require('./geom-utils'); require('./geom-utils');
require('./sp');
} }
require('./mesh'); require('./mesh');

View File

@ -0,0 +1,3 @@
require('./sp');
require('./multi-handler');
require('./multi-batcher');

View File

@ -0,0 +1,74 @@
import { MultiHandler } from "./multi-handler";
/**
*
*/
export class MultiBatcher {
/**
*
*/
handlers: MultiHandler[] = [];
/**
*
*/
nextHandler!: MultiHandler;
/**
*
*/
init() {
const handler = new MultiHandler();
this.handlers.push(handler);
this.nextHandler = handler;
}
/**
* cc.Texture2D
*/
requsetMaterial(texture: any) {
if (!texture._multiMaterial) {
let handler = this.nextHandler;
let index = handler.getEmptyIndex();
if (index === -1) {
// 没有空位,尝试在已有 handlers 里查找
for (const _handler of this.handlers) {
index = _handler.getEmptyIndex();
if (index !== -1) {
handler = _handler;
this.nextHandler = handler;
break;
}
}
// 已有的没有空位,创建新材质
if (index === -1) {
handler = new MultiHandler();
this.handlers.push(handler);
this.nextHandler = handler;
index = 0;
}
}
texture.linkMaterial(handler.material, index);
}
return texture._multiMaterial;
}
/**
* 使
*/
reset() {
this.handlers.length = 0;
}
}
cc.sp.multiBatcher = new MultiBatcher();
cc.sp.MultiBatcher = MultiBatcher;

View File

@ -0,0 +1,146 @@
/**
* Material
*/
export class MultiHandler {
/**
*
*/
material: any;
/**
* Texture
*
* cc.Texture2D
*/
protected textures: any[] = [];
/**
*
*/
protected hasEmptySlot: boolean = false;
constructor(material?) {
if (material) {
this.material = material;
} else {
this.material = (cc.Material as any).create(cc.sp.multi2dSpriteEffectAsset);
this.material.name = "multi-2d-sprite";
this.material.define('USE_TEXTURE', true);
this.material.define('USE_MULTI_TEXTURE', true);
}
this.material._multiHandler = this;
this.syncTextures();
}
/**
* Material
*
*
*/
syncTextures() {
const effect = this.material['effect'];
const properties = effect.passes[0]._properties;
this.textures[0] = properties.texture.value;
this.textures[1] = properties.texture2.value;
this.textures[2] = properties.texture3.value;
this.textures[3] = properties.texture4.value;
this.textures[4] = properties.texture5.value;
this.textures[5] = properties.texture6.value;
this.textures[6] = properties.texture7.value;
this.textures[7] = properties.texture8.value;
// refresh has empty slot state
this.hasEmptySlot = true;
this.getEmptyIndex();
}
/**
* cc.Texture2D
*/
setTexture(index: number, texture: any) {
this.textures[index] = texture ? texture.getImpl() : null;
this.material.setProperty(cc.sp.propertyIndex2Name(index), texture);
if (texture == null) this.hasEmptySlot = true;
}
/**
*
*
* cc.Texture2D
*/
removeTexture(texture: any) {
const index = this.getIndex(texture);
if (index !== -1) {
this.setTexture(index, null);
}
}
/**
*
*
* cc.Texture2D
*/
hasTexture(texture: any) {
return this.textures.indexOf(texture) !== -1;
}
/**
* Index -1
*
* cc.Texture2D
*/
getIndex(texture: any) {
return this.textures.indexOf(texture);
}
/**
* index
*
* cc.Texture2D
*/
getTexture(index: number) {
return this.textures[index];
}
/**
* Index -1
*/
getEmptyIndex() {
if (!this.hasEmptySlot) return -1;
const index = this.textures.indexOf(null);
if (index !== -1) {
return index;
} else {
this.hasEmptySlot = false;
return -1;
}
}
/**
* -1 cc.Texture2D
*/
autoSetTexture(texture: any) {
const index = this.getEmptyIndex();
if (index === -1) {
return -1;
}
this.setTexture(index, texture);
return index;
}
}
cc.sp.MultiHandler = MultiHandler;

View File

@ -0,0 +1,86 @@
cc.sp = {
/**
* 是否初始化完成
*/
inited: false,
/**
* 版本号
*/
version: "1.0.0",
/**
* 最大纹理插槽数量
*
* 固定为 8
*/
MAX_MULTITEXTURE_NUM: -1,
/**
* 渲染组件是否默认自动切换至贴图关联的材质
*/
autoSwitchMaterial: true,
/**
* 渲染组件是否默认参与动态合图
*/
allowDynamicAtlas: true,
/**
* Label 组件是否默认启用渲染时进行缩放以适配高 DPI 屏幕
*/
enableLabelRetina: true,
/**
* Label 组件渲染时进行缩放的缩放比例
*/
labelRetinaScale: 1,
/**
* Char 图集会进行自动多纹理合批的数量
*/
charAtlasAutoBatchCount: 1,
/**
* Char 图集是否在场景切换时清空
*/
charAtlasAutoResetBeforeSceneLoad: true,
/**
* 内置的多纹理合批 Effect Asset
*/
multi2dSpriteEffectAsset: null,
/**
* property index to name map
*/
i2nMap: ['texture'],
/**
* property name to index map
*/
n2iMap: { texture: 0 },
/**
* property index to name
*/
propertyIndex2Name(index) {
return this.i2nMap[index];
},
/**
* property name to index
*/
propertyName2Index(name) {
return this.n2iMap[name];
},
};
// 初始化
for (let i = 1; i < 8; i++) {
const name = "texture" + (i + 1);
cc.sp.i2nMap[i] = name;
cc.sp.n2iMap[name] = i;
}