/** * 重写引擎方法,进行一些功能扩展 */ const { ccclass } = cc._decorator; @ccclass export default class LevelExtend extends cc.Component{ protected onLoad(): void { CCCExtend.init(); } } class CCCExtend { /** 初始化扩展 */ static init() { this._extendRenderFlow(); } /** 扩展渲染流,新增层级渲染 */ private static _extendRenderFlow() { let FlagOfset = 0; const DONOTHING = 1 << FlagOfset++; const BREAK_FLOW = 1 << FlagOfset++; const LOCAL_TRANSFORM = 1 << FlagOfset++; const WORLD_TRANSFORM = 1 << FlagOfset++; const TRANSFORM = LOCAL_TRANSFORM | WORLD_TRANSFORM; const UPDATE_RENDER_DATA = 1 << FlagOfset++; const OPACITY = 1 << FlagOfset++; const COLOR = 1 << FlagOfset++; const OPACITY_COLOR = OPACITY | COLOR; const RENDER = 1 << FlagOfset++; const CHILDREN = 1 << FlagOfset++; const POST_RENDER = 1 << FlagOfset++; const FINAL = 1 << FlagOfset++; const renderFlow = cc["RenderFlow"]; const _batcher = renderFlow.getBachther(); let __levelBatcher: { worldMatDirty: number, parentOpacityDirty }[] = []; let __renderQueue: cc.Node[][] = []; Object.defineProperty(renderFlow.prototype, "_opacity", { value: function (node) { _batcher.parentOpacityDirty++; if (node["__levelRender"] && __levelBatcher[node["__itemIndex"]]) { __levelBatcher[node["__itemIndex"]].parentOpacityDirty = 1; } this._next._func(node); node._renderFlag &= ~OPACITY; if (node["__levelRender"] && __levelBatcher[node["__itemIndex"]] && node["__lastChildren"]) { __levelBatcher[node.__itemIndex].parentOpacityDirty = 0; } _batcher.parentOpacityDirty--; } }) Object.defineProperty(renderFlow.prototype, "_worldTransform", { value: function (node) { _batcher.worldMatDirty++; if (node["__levelRender"] && __levelBatcher[node["__itemIndex"]]) { __levelBatcher[node["__itemIndex"]].worldMatDirty = 1; } let t = node._matrix; let trs = node._trs; let tm = t.m; tm[12] = trs[0]; tm[13] = trs[1]; tm[14] = trs[2]; node._mulMat(node._worldMatrix, node._parent._worldMatrix, t); node._renderFlag &= ~WORLD_TRANSFORM; this._next._func(node); if (node["__levelRender"] && __levelBatcher[node["__itemIndex"]] && node["__lastChildren"]) { __levelBatcher[node.__itemIndex].worldMatDirty = 0; } _batcher.worldMatDirty--; } }); const levelSplit = (node: cc.Node, lv: number, itemIndex) => { if (!__renderQueue[lv]) { __renderQueue[lv] = []; } __renderQueue[lv].push(node); lv++; node["__renderLv"] = lv; node["__levelRender"] = true; node["__itemIndex"] = itemIndex; const cs = node.children; for (let i = 0; i < cs.length; ++i) { const c = cs[i]; if (!__renderQueue[lv]) { __renderQueue[lv] = []; } lv = levelSplit(c, lv, itemIndex); } return lv; } const checkLevelRender = (levelRenderNode: cc.Node) => { const cs = levelRenderNode.children; let rootOpacityInHierarchy = levelRenderNode["opacity"] / 255; __levelBatcher = []; for (let i = 0; i < cs.length; ++i) { __levelBatcher.push({ worldMatDirty: 0, parentOpacityDirty: 0 }); levelSplit(cs[i], 0, i); } while (__renderQueue.length > 0) { const list = __renderQueue.shift(); if (list.length > 0) { while (list.length > 0) { const n = list.shift(); n["__lastChildren"] = __renderQueue.length == 0; n["__levelRender"] = true; let opacityInHierarchy = n.parent["__opacityInHierarchy"]; if (opacityInHierarchy === undefined) { opacityInHierarchy = rootOpacityInHierarchy; } let opacity = (opacityInHierarchy * (n["_opacity"] / 255)); n["__opacityInHierarchy"] = opacity; let cullingMask = n["_cullingMask"]; let worldMatDirty = 0; if (__levelBatcher[n["__itemIndex"]]) { worldMatDirty = __levelBatcher[n["__itemIndex"]].worldMatDirty || 0; } let parentOpacityDirty = 0; if (__levelBatcher[n["__itemIndex"]]) { parentOpacityDirty = __levelBatcher[n["__itemIndex"]].parentOpacityDirty || 0; } let worldTransformFlag = (worldMatDirty || _batcher.worldMatDirty) ? WORLD_TRANSFORM : 0; let worldOpacityFlag = (parentOpacityDirty || _batcher.parentOpacityDirty) ? OPACITY_COLOR : 0; let worldDirtyFlag = worldTransformFlag | worldOpacityFlag; n["_renderFlag"] |= worldDirtyFlag; if (!n["_activeInHierarchy"]) continue; n["_cullingMask"] = n.groupIndex === 0 ? cullingMask : 1 << n.groupIndex; // TODO: Maybe has better way to implement cascade opacity let colorVal = n["_color"]._val; n["_color"]._fastSetA(n["_opacity"] * opacity); renderFlow.flows[n["_renderFlag"]]._func(n); n["_color"]._val = colorVal; } } } } Object.defineProperty(renderFlow.prototype, "_children", { value: function (node) { if (node.__levelRender) return; let cullingMask = node._cullingMask; let enableLevelRender = node["__enableLevelRender"]; const parentOpacityInHierarchy = node.parent ? node.parent["__opacityInHierarchy"] : undefined; let parentOpacity = parentOpacityInHierarchy !== undefined ? parentOpacityInHierarchy : _batcher.parentOpacity; if (!enableLevelRender && !node.__levelRender) { let opacity = (parentOpacity *= (node._opacity / 255)); node["__opacityInHierarchy"] = opacity; let worldTransformFlag = _batcher.worldMatDirty ? WORLD_TRANSFORM : 0; let worldOpacityFlag = _batcher.parentOpacityDirty ? OPACITY_COLOR : 0; let worldDirtyFlag = worldTransformFlag | worldOpacityFlag; let children = node._children; for (let i = 0, l = children.length; i < l; i++) { let c = children[i]; // Advance the modification of the flag to avoid node attribute modification is invalid when opacity === 0. c._renderFlag |= worldDirtyFlag; c["__opacityInHierarchy"] = c._opacity * opacity / 255; if (!c._activeInHierarchy || c._opacity === 0) continue; c._cullingMask = c.groupIndex === 0 ? cullingMask : 1 << c.groupIndex; // TODO: Maybe has better way to implement cascade opacity let colorVal = c._color._val; c._color._fastSetA(c._opacity * opacity); renderFlow.flows[c._renderFlag]._func(c) c._color._val = colorVal; } } else { checkLevelRender(node); } _batcher.parentOpacity = parentOpacity; this._next._func(node); } }) } }