更新README,添加2025-10-27更新日志;优化层级渲染算法,支持多级分层渲染,修复虚拟列表相关bug;修改LevelRender组件以启用层级渲染;

This commit is contained in:
spe
2025-10-27 10:28:18 +08:00
parent 02dfcbbd73
commit 432cd56542
5 changed files with 485 additions and 167 deletions

View File

@@ -25,122 +25,149 @@ export default class CCCExtension {
}
private static _extendRender3_x() {
const batch2d = cclegacy[`internal`][`Batcher2D`];
let __renderQueue: Node[][] = [];
const Batcher2D = this.getBatcher2D();
const batchQueue: Node[][] = [];
const levelSplit = (node: 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 processNode = (batcher2D, node: Node) => {
node["__levelRenderFlag"] = true;
batcher2D.walk(node, 0);
node["__levelRenderFlag"] = false;
}
Object.defineProperty(batch2d.prototype, "walk", {
value: function (node: Node, level = 0) {
if (!node[`activeInHierarchy`]) {
return;
}
const children = node.children;
const uiProps = node._uiProps;
const render = uiProps.uiComp as UIRenderer;
// Save opacity
let parentOpacity = this._pOpacity === undefined ? 1 : this._pOpacity;
if (node.parent) {
parentOpacity = node.parent._uiProps.opacity;
}
let opacity = parentOpacity;
// TODO Always cascade ui property's local opacity before remove it
const selfOpacity = render && render.color ? render.color.a / 255 : 1;
this._pOpacity = opacity = opacity * selfOpacity * uiProps.localOpacity;
// TODO Set opacity to ui property's opacity before remove it
if (uiProps[`setOpacity`]) {
uiProps[`setOpacity`](opacity);
}
uiProps[`_opacity`] = opacity;
if (!approx(opacity, 0, EPSILON)) {
if (uiProps.colorDirty) {
// Cascade color dirty state
this._opacityDirty++;
}
// Render assembler update logic
if (render && render.enabledInHierarchy) {
render.fillBuffers(this);// for rendering
}
// Update cascaded opacity to vertex buffer
if (this._opacityDirty && render && !render.useVertexOpacity && render.renderData && render.renderData.vertexCount > 0) {
// HARD COUPLING
updateOpacity(render.renderData, opacity);
const buffer = render.renderData.getMeshBuffer();
if (buffer) {
buffer.setDirty();
}
}
if (children.length > 0 && !node._static) {
if (!node[`__levelRender`]) {
__renderQueue = [];
for (let i = 0; i < children.length; ++i) {
const child = children[i];
if (node.parent)
child._uiProps.colorDirty = child._uiProps.colorDirty || node.parent._uiProps.colorDirty;
const enableLevelRender = node[`__enableLevelRender`];
if (!enableLevelRender) {
this.walk(child, level);
} else {
levelSplit(child, 0, i);
}
}
for (let i = 0; i < __renderQueue.length; ++i) {
const list = __renderQueue[i];
for (let j = 0; j < list.length; ++j) {
const n = list[j];
this.walk(n, level);
}
}
__renderQueue = [];
}
}
if (uiProps.colorDirty) {
// Reduce cascaded color dirty state
this._opacityDirty--;
// Reset color dirty
uiProps.colorDirty = false;
}
}
// Restore opacity
this._pOpacity = parentOpacity;
// Post render assembler update logic
// ATTENTION: Will also reset colorDirty inside postUpdateAssembler
if (render && render.enabledInHierarchy) {
render.postUpdateAssembler(this);
if ((render.stencilStage as any === Stage.ENTER_LEVEL || render.stencilStage as any === Stage.ENTER_LEVEL_INVERTED)
&& (StencilManager.sharedManager!.getMaskStackSize() > 0)) {
this.autoMergeBatches(this._currComponent!);
this.resetRenderStates();
StencilManager.sharedManager!.exitMask();
}
}
level += 1;
//入队
const enqueue = (node: Node, layer = 0) => {
if (!batchQueue[layer]) {
batchQueue[layer] = [];
}
});
if (node["__levelRender"]) {
node["__levelLayer"] = layer;
} else {
if (node.parent && node.parent["__levelLayer"]) {
layer = node.parent["__levelLayer"] + 1;
}
}
if (node.activeInHierarchy) {
const queue = batchQueue[layer];
queue.push(node);
}
layer++;
for (let i = 0; i < node.children.length; ++i) {
const child = node.children[i];
layer = enqueue(child, layer);
}
return layer;
}
//出队
const dequeue = (batcher2D) => batchQueue.forEach(queue => queue.forEach(n => processNode(batcher2D, n)));
// 层级渲染
const levelRender = (batcher2D, node: Node, layer = 0) => {
if (!node) {
return;
}
processNode(batcher2D, node);
node.children.forEach(children => {
enqueue(children, layer)
})
dequeue(batcher2D);
batchQueue.forEach(q => q.length = 0);
}
Batcher2D.prototype.walk = function (node: Node, level = 0) {
if (!node.activeInHierarchy) {
return;
}
const children = node.children;
const uiProps = node._uiProps;
const render = uiProps.uiComp as UIRenderer;
// Save opacity
let parentOpacity = this._pOpacity;
if (node.parent) {
parentOpacity = node.parent._uiProps.opacity;
}
let opacity = parentOpacity;
// TODO Always cascade ui property's local opacity before remove it
const selfOpacity = render && render.color ? render.color.a / 255 : 1;
this._pOpacity = opacity *= selfOpacity * uiProps.localOpacity;
// TODO Set opacity to ui property's opacity before remove it
if (uiProps[`setOpacity`]) {
uiProps[`setOpacity`](opacity);
}
uiProps[`_opacity`] = opacity;
if (!approx(opacity, 0, EPSILON)) {
if (uiProps.colorDirty) {
// Cascade color dirty state
this._opacityDirty++;
}
// Render assembler update logic
if (render && render.enabledInHierarchy) {
render.fillBuffers(this);// for rendering
}
// Update cascaded opacity to vertex buffer
if (this._opacityDirty && render && !render.useVertexOpacity && render.renderData && render.renderData.vertexCount > 0) {
// HARD COUPLING
updateOpacity(render.renderData, opacity);
const buffer = render.renderData.getMeshBuffer();
if (buffer) {
buffer.setDirty();
}
}
const isLevelRender = node["__levelRender"] || node["__levelRenderFlag"];
if (!isLevelRender) {
if (children.length > 0 && !node._static) {
for (let i = 0; i < children.length; ++i) {
const child = children[i];
this.walk(child, level);
}
}
} else {
if (!node["__levelRenderFlag"]) {
levelRender(this, node, 0);
return;
}
}
if (uiProps.colorDirty) {
// Reduce cascaded color dirty state
this._opacityDirty--;
// Reset color dirty
uiProps.colorDirty = false;
}
}
// Restore opacity
this._pOpacity = parentOpacity;
// Post render assembler update logic
// ATTENTION: Will also reset colorDirty inside postUpdateAssembler
if (render && render.enabledInHierarchy) {
render.postUpdateAssembler(this);
if ((render.stencilStage as any === Stage.ENTER_LEVEL || render.stencilStage as any === Stage.ENTER_LEVEL_INVERTED)
&& (StencilManager.sharedManager!.getMaskStackSize() > 0)) {
this.autoMergeBatches(this._currComponent!);
this.resetRenderStates();
StencilManager.sharedManager!.exitMask();
}
}
level += 1;
}
}
private static getBatcher2D() {
return cclegacy["internal"]["Batcher2D"];
}
private static _extendEditBoxTemp() {