经过我们一天的调试,目前发现这个问题的症结在 vb 和 ib 的共享上, Creator 为了优化性能,多个drawcall 之间是会共享同一份 vb 和 ib 的,每个 drawcall 使用一个偏移值在共享的 vb 和 ib 中找到本次渲染的数据,但是经过我们测试后发现,共享 vb 和 ib 会导致在 iOS 14 上性能下降非常严重。
所以修复方式就是,在提交 drawcall 之后,切换 vb 和 ib。
解决方案:
2.2 版本以上:
自定义引擎并手动合并此 pr :
https://github.com/cocos-creator/engine/pull/7415
如果不想自定义引擎的话你也可以在项目脚本最外层手动覆盖这个类型中的方法。
const isIOS14Device = cc.sys.os === cc.sys.OS_IOS && cc.sys.isBrowser && cc.sys.isMobile && /iPhone OS 14/.test(window.navigator.userAgent);
if (isIOS14Device) {
cc.MeshBuffer.prototype.checkAndSwitchBuffer = function (vertexCount) {
if (this.vertexOffset + vertexCount > 65535) {
this.uploadData();
this._batcher._flush();
}
};
cc.MeshBuffer.prototype.forwardIndiceStartToOffset = function () {
this.uploadData();
this.switchBuffer();
}
}
2.1.x 版本
2.1.x 版本原理类似,你依旧需要覆盖 checkAndSwitchBuffer
const isIOS14Device = cc.sys.os === cc.sys.OS_IOS && cc.sys.isBrowser && cc.sys.isMobile && /iPhone OS 14/.test(window.navigator.userAgent);
if (isIOS14Device) {
cc.MeshBuffer.prototype.checkAndSwitchBuffer = function (vertexCount) {
if (this.vertexOffset + vertexCount > 65535) {
this.uploadData();
this._batcher._flush();
}
};
}
但 2.1.x 中没有实现 forwardIndiceStartToOffset,所以你需要以下额外操作:
自定义引擎找到 model-batcher.js,将 _flush 方法中的最后三行改为:
const isIOS14Device = cc.sys.os === cc.sys.OS_IOS && cc.sys.isBrowser && cc.sys.isMobile && /iPhone OS 14/.test(window.navigator.userAgent);
_flush () {
let material = this.material,
buffer = this._buffer,
indiceStart = buffer.indiceStart,
indiceOffset = buffer.indiceOffset,
indiceCount = indiceOffset - indiceStart;
if (!this.walking || !material || indiceCount <= 0) {
return;
}
let effect = material.effect;
if (!effect) return;
// Generate ia
let ia = this._iaPool.add();
ia._vertexBuffer = buffer._vb;
ia._indexBuffer = buffer._ib;
ia._start = indiceStart;
ia._count = indiceCount;
// Generate model
let model = this._modelPool.add();
this._batchedModels.push(model);
model.sortKey = this._sortKey++;
model._cullingMask = this.cullingMask;
model.setNode(this.node);
model.setEffect(effect, this.customProperties);
model.setInputAssembler(ia);
this._renderScene.addModel(model);
if (isIOS14Device) {
buffer.uploadData();
buffer.switchBuffer();
}
else {
buffer.byteStart = buffer.byteOffset;
buffer.indiceStart = buffer.indiceOffset;
buffer.vertexStart = buffer.vertexOffset;
}
},
2.0.x 版本
自定义引擎,并用此文件mesh-buffer.zip (1.5 KB)覆盖引擎中的 mesh-buffer.js. 然后,使用和 2.1.x 版本相同的改动方式修改。
注意: 自定义引擎后需要重新编译引擎才能生效。建议合并后,使用不同手机进行全面测试。