继续分享些邪修的
当场景中大量使用BmFont时候, 经常会发现 fillMeshVertices3D 方法占比很高
正常
修改引擎代码, 展开颜色, 分正交和透视, 大部分情况下不需要运算 透视
export function fillMeshVertices3D (node: Node, renderer: IBatcher, renderData: RenderData | null, color: Color): void {
if (!renderData) return;
const chunk = renderData.chunk;
const dataList = renderData.data;
const vData = chunk.vb;
const vertexCount = renderData.vertexCount;
const m = node.worldMatrix;
const m00 = m.m00; const m01 = m.m01; const m02 = m.m02; const m03 = m.m03;
const m04 = m.m04; const m05 = m.m05; const m06 = m.m06; const m07 = m.m07;
const m12 = m.m12; const m13 = m.m13; const m14 = m.m14; const m15 = m.m15;
// 预计算颜色,避免每次循环都转换
const colR = color.r / 255;
const colG = color.g / 255;
const colB = color.b / 255;
const colA = color.a / 255;
// 检查是否需要透视除法(优化常见情况)
const needsPerspective = m03 !== 0 || m07 !== 0 || m15 !== 1;
let vertexOffset = 0;
if (needsPerspective) {
// 透视投影路径
for (let i = 0; i < vertexCount; ++i) {
const vert = dataList[i];
const x = vert.x;
const y = vert.y;
let rhw = m03 * x + m07 * y + m15;
// 优化:避免条件判断,使用数学技巧
// 如果 rhw 接近 0,设为一个很小的数避免除零
rhw = 1 / (rhw + (rhw === 0 ? 1e-10 : 0));
vData[vertexOffset] = (m00 * x + m04 * y + m12) * rhw;
vData[vertexOffset + 1] = (m01 * x + m05 * y + m13) * rhw;
vData[vertexOffset + 2] = (m02 * x + m06 * y + m14) * rhw;
vData[vertexOffset + 5] = colR;
vData[vertexOffset + 6] = colG;
vData[vertexOffset + 7] = colB;
vData[vertexOffset + 8] = colA;
vertexOffset += renderData.floatStride;
}
} else {
// 正交投影快速路径(大多数 2D 情况)
for (let i = 0; i < vertexCount; ++i) {
const vert = dataList[i];
const x = vert.x;
const y = vert.y;
vData[vertexOffset] = m00 * x + m04 * y + m12;
vData[vertexOffset + 1] = m01 * x + m05 * y + m13;
vData[vertexOffset + 2] = m02 * x + m06 * y + m14;
vData[vertexOffset + 5] = colR;
vData[vertexOffset + 6] = colG;
vData[vertexOffset + 7] = colB;
vData[vertexOffset + 8] = colA;
vertexOffset += renderData.floatStride;
}
}
// fill index data
const vid = chunk.vertexOffset;
const meshBuffer = chunk.meshBuffer;
const ib = meshBuffer.iData;
let indexOffset = meshBuffer.indexOffset;
// 优化索引填充(展开循环)
const quadCount = vertexCount >> 2; // 除以4
for (let i = 0; i < quadCount; i++) {
const start = vid + (i << 2); // i * 4
ib[indexOffset] = start;
ib[indexOffset + 1] = start + 1;
ib[indexOffset + 2] = start + 2;
ib[indexOffset + 3] = start + 1;
ib[indexOffset + 4] = start + 3;
ib[indexOffset + 5] = start + 2;
indexOffset += 6;
}
meshBuffer.indexOffset += renderData.indexCount;
meshBuffer.setDirty();
}
邪修
合并函数, 透视, Z轴统统不考虑! 不对Color A 做Float32转换, 直接用node._uiProps.opacity, 更偏激的点 我们可以把rgb Color, 直接用ArrayBuffer 缓存 Float32的RGBA
fillBuffers(comp: Label, renderer: IBatcher): void {
const node = comp.node;
// 临时颜色,保持与原来逻辑(color.a 使用 node._uiProps.opacity)
const renderData = comp.renderData;
if (!renderData) return;
const chunk = renderData.chunk;
const dataList = renderData.data;
const vData = chunk.vb; // 顶点缓冲 Float32Array
const vertexCount = renderData.vertexCount;
const floatStride = renderData.floatStride; // 顶点步长(float 数)
const m = node.worldMatrix;
// 缓存世界矩阵分量(只需要正交变换分量)
const m00 = m.m00; const m01 = m.m01;
const m04 = m.m04; const m05 = m.m05;
const m12 = m.m12; const m13 = m.m13;
// 对于 2D 正交路径,m03,m07,m15 不参与透视除法(如果你的节点有 3D 变换请谨慎)
// 这里不做透视,直接使用仿射变换 (x,y,1) * matrix
const color = comp.color;
// 预计算颜色(归一化到 0..1,写入顶点颜色槽)
const colR = color.r / 255;
const colG = color.g / 255;
const colB = color.b / 255;
const colA = node._uiProps.opacity;
// 顶点写入起始偏移
let vertexOffset = 0;
// 为性能,把常用量缓存为局部变量引用
const list = dataList;
const stride = floatStride;
// 主循环:遍历每个顶点并写入位置与颜色
for (let i = 0; i < vertexCount; ++i) {
const vert = list[i];
const x = vert.x;
const y = vert.y;
// 写入变换后的位置(仿射 2D 变换)
vData[vertexOffset] = m00 * x + m04 * y + m12; // x'
vData[vertexOffset + 1] = m01 * x + m05 * y + m13; // y'
// vData[vertexOffset + 2] = m02 * x + m06 * y + m14; // z' (如果不使用可忽略)
// 保持原先顶点布局中 u,v 或其他槽位(如果需要写 uv,请在此处写入)
// 例如原版可能在 offset 3,4 写入 uv,这里保持不变(如果 renderData 已经填好了 uv,这里可以跳过)
// 写入颜色到假定的偏移 +5..+8(与原代码一致)
vData[vertexOffset + 5] = colR;
vData[vertexOffset + 6] = colG;
vData[vertexOffset + 7] = colB;
vData[vertexOffset + 8] = colA;
vertexOffset += stride;
}
// 填充索引
const vid = chunk.vertexOffset; // 顶点基址(vertex index 起始值)
const meshBuffer = chunk.meshBuffer;
const ib = meshBuffer.iData; // Uint16Array 或 Uint32Array
let indexOffset = meshBuffer.indexOffset;
// quadCount = vertexCount / 4
const quadCount = vertexCount >> 2;
for (let q = 0; q < quadCount; ++q) {
const start = vid + (q << 2); // q * 4
ib[indexOffset] = start;
ib[indexOffset + 1] = start + 1;
ib[indexOffset + 2] = start + 2;
ib[indexOffset + 3] = start + 1;
ib[indexOffset + 4] = start + 3;
ib[indexOffset + 5] = start + 2;
indexOffset += 6;
}
// 更新 meshBuffer 状态
meshBuffer.indexOffset += renderData.indexCount;
meshBuffer.setDirty();
}


