fix(wireframe): 扫描结果按字段路径缓存并每帧合并,补齐炮塔与车体漏采
This commit is contained in:
1 parent
41b94ef0f9
commit
aa3bcba363
3 files changed
+114
-24
No files matched your search
@@ -2051,11 +2051,41 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
// 扫描结果按「组件字段路径」缓存(不缓存节点对象:引擎会重建节点树,
|
||||
// 但字段名与组件实例稳定,路径每次都能解析到当前节点)
|
||||
var NodeSrcCache = new WeakMap(); // entity -> [{ Comp, Path: [K1, K2, K3] }]
|
||||
var ScanTick = 0;
|
||||
|
||||
function ResolveSrc(Src) {
|
||||
var V = Src.Comp;
|
||||
for (var i = 0; i < Src.Path.length; i++) {
|
||||
if (!V || typeof V !== 'object') return null;
|
||||
V = V[Src.Path[i]];
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
||||
function ScanMeshNodes(tank, nodes, stats, Seen) {
|
||||
Seen = Seen || new WeakSet();
|
||||
function Try(V) {
|
||||
// ① 有缓存路径:直接解析(开销极小);每 300 帧强制重扫一次,捡起后加载的部件
|
||||
ScanTick++;
|
||||
var NeedRescan = (ScanTick % 300) === 0;
|
||||
var Cached = NodeSrcCache.get(tank);
|
||||
if (!NeedRescan && Cached && Cached.length) {
|
||||
var AllOk = true;
|
||||
for (var c = 0; c < Cached.length; c++) {
|
||||
var V0 = ResolveSrc(Cached[c]);
|
||||
if (!IsSceneNode(V0)) { AllOk = false; break; }
|
||||
if (!Seen.has(V0)) CollectMeshNodes(V0, nodes, 0, 'scan', stats, Seen);
|
||||
}
|
||||
if (AllOk) return;
|
||||
}
|
||||
// ② 缓存失效或首次:全量扫描并重建路径表
|
||||
var Srcs = [];
|
||||
function Try(V, Comp, Path) {
|
||||
if (!IsSceneNode(V) || Seen.has(V)) return;
|
||||
CollectMeshNodes(V, nodes, 0, 'scan', stats, Seen);
|
||||
Srcs.push({ Comp: Comp, Path: Path });
|
||||
}
|
||||
try {
|
||||
tank.qz1_1.s2a_1.forEach(function (VL) {
|
||||
@@ -2064,22 +2094,23 @@
|
||||
for (var K in comp) {
|
||||
var V = comp[K];
|
||||
if (!IsPlainObj(V)) continue;
|
||||
if (IsSceneNode(V)) { Try(V); continue; }
|
||||
if (IsSceneNode(V)) { Try(V, comp, [K]); continue; }
|
||||
// 深度 2/3:节点常包在皮肤对象/包装对象里(如 skin.h159_1、weaponSkin.e11p_1.a17q_1)
|
||||
try {
|
||||
for (var K2 in V) {
|
||||
var V2 = V[K2];
|
||||
if (!IsPlainObj(V2)) continue;
|
||||
if (IsSceneNode(V2)) { Try(V2); continue; }
|
||||
if (IsSceneNode(V2)) { Try(V2, comp, [K, K2]); continue; }
|
||||
for (var K3 in V2) {
|
||||
var V3 = V2[K3];
|
||||
if (IsPlainObj(V3)) Try(V3);
|
||||
if (IsPlainObj(V3)) Try(V3, comp, [K, K2, K3]);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
} catch (e) {}
|
||||
NodeSrcCache.set(tank, Srcs);
|
||||
}
|
||||
|
||||
// 结果级去重:同一 mesh 资源 + 同一节点名,只保留一份
|
||||
@@ -2137,10 +2168,9 @@
|
||||
});
|
||||
} catch(e) {}
|
||||
}
|
||||
// ③ 仍然为空才做组件字段扫描(不加节流:节流会导致「这帧有模型、下帧只有点」的闪烁)
|
||||
if (nodes.length === 0) {
|
||||
try { ScanMeshNodes(tank, nodes, stats ? stats.scan : null, Seen); } catch (e) {}
|
||||
}
|
||||
// ③ 结构扫描:无条件补充漏采(车身根/部件表往往只覆盖一部分)
|
||||
// 重复实例(皮肤树/场景树同 tp 同名)由 DedupNodes 收掉,不会再出现"两个身体"
|
||||
try { ScanMeshNodes(tank, nodes, stats ? stats.scan : null, Seen); } catch (e) {}
|
||||
// ④ 炮塔(独立于车身根;重复实例由 DedupNodes 收掉)
|
||||
var turretNode = GetTurretNode(tank);
|
||||
if (stats) stats.turretComp = !!turretNode;
|
||||
|
||||
+38
-8
@@ -2051,11 +2051,41 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
// 扫描结果按「组件字段路径」缓存(不缓存节点对象:引擎会重建节点树,
|
||||
// 但字段名与组件实例稳定,路径每次都能解析到当前节点)
|
||||
var NodeSrcCache = new WeakMap(); // entity -> [{ Comp, Path: [K1, K2, K3] }]
|
||||
var ScanTick = 0;
|
||||
|
||||
function ResolveSrc(Src) {
|
||||
var V = Src.Comp;
|
||||
for (var i = 0; i < Src.Path.length; i++) {
|
||||
if (!V || typeof V !== 'object') return null;
|
||||
V = V[Src.Path[i]];
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
||||
function ScanMeshNodes(tank, nodes, stats, Seen) {
|
||||
Seen = Seen || new WeakSet();
|
||||
function Try(V) {
|
||||
// ① 有缓存路径:直接解析(开销极小);每 300 帧强制重扫一次,捡起后加载的部件
|
||||
ScanTick++;
|
||||
var NeedRescan = (ScanTick % 300) === 0;
|
||||
var Cached = NodeSrcCache.get(tank);
|
||||
if (!NeedRescan && Cached && Cached.length) {
|
||||
var AllOk = true;
|
||||
for (var c = 0; c < Cached.length; c++) {
|
||||
var V0 = ResolveSrc(Cached[c]);
|
||||
if (!IsSceneNode(V0)) { AllOk = false; break; }
|
||||
if (!Seen.has(V0)) CollectMeshNodes(V0, nodes, 0, 'scan', stats, Seen);
|
||||
}
|
||||
if (AllOk) return;
|
||||
}
|
||||
// ② 缓存失效或首次:全量扫描并重建路径表
|
||||
var Srcs = [];
|
||||
function Try(V, Comp, Path) {
|
||||
if (!IsSceneNode(V) || Seen.has(V)) return;
|
||||
CollectMeshNodes(V, nodes, 0, 'scan', stats, Seen);
|
||||
Srcs.push({ Comp: Comp, Path: Path });
|
||||
}
|
||||
try {
|
||||
tank.qz1_1.s2a_1.forEach(function (VL) {
|
||||
@@ -2064,22 +2094,23 @@
|
||||
for (var K in comp) {
|
||||
var V = comp[K];
|
||||
if (!IsPlainObj(V)) continue;
|
||||
if (IsSceneNode(V)) { Try(V); continue; }
|
||||
if (IsSceneNode(V)) { Try(V, comp, [K]); continue; }
|
||||
// 深度 2/3:节点常包在皮肤对象/包装对象里(如 skin.h159_1、weaponSkin.e11p_1.a17q_1)
|
||||
try {
|
||||
for (var K2 in V) {
|
||||
var V2 = V[K2];
|
||||
if (!IsPlainObj(V2)) continue;
|
||||
if (IsSceneNode(V2)) { Try(V2); continue; }
|
||||
if (IsSceneNode(V2)) { Try(V2, comp, [K, K2]); continue; }
|
||||
for (var K3 in V2) {
|
||||
var V3 = V2[K3];
|
||||
if (IsPlainObj(V3)) Try(V3);
|
||||
if (IsPlainObj(V3)) Try(V3, comp, [K, K2, K3]);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
} catch (e) {}
|
||||
NodeSrcCache.set(tank, Srcs);
|
||||
}
|
||||
|
||||
// 结果级去重:同一 mesh 资源 + 同一节点名,只保留一份
|
||||
@@ -2137,10 +2168,9 @@
|
||||
});
|
||||
} catch(e) {}
|
||||
}
|
||||
// ③ 仍然为空才做组件字段扫描(不加节流:节流会导致「这帧有模型、下帧只有点」的闪烁)
|
||||
if (nodes.length === 0) {
|
||||
try { ScanMeshNodes(tank, nodes, stats ? stats.scan : null, Seen); } catch (e) {}
|
||||
}
|
||||
// ③ 结构扫描:无条件补充漏采(车身根/部件表往往只覆盖一部分)
|
||||
// 重复实例(皮肤树/场景树同 tp 同名)由 DedupNodes 收掉,不会再出现"两个身体"
|
||||
try { ScanMeshNodes(tank, nodes, stats ? stats.scan : null, Seen); } catch (e) {}
|
||||
// ④ 炮塔(独立于车身根;重复实例由 DedupNodes 收掉)
|
||||
var turretNode = GetTurretNode(tank);
|
||||
if (stats) stats.turretComp = !!turretNode;
|
||||
|
||||
@@ -526,11 +526,41 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
// 扫描结果按「组件字段路径」缓存(不缓存节点对象:引擎会重建节点树,
|
||||
// 但字段名与组件实例稳定,路径每次都能解析到当前节点)
|
||||
var NodeSrcCache = new WeakMap(); // entity -> [{ Comp, Path: [K1, K2, K3] }]
|
||||
var ScanTick = 0;
|
||||
|
||||
function ResolveSrc(Src) {
|
||||
var V = Src.Comp;
|
||||
for (var i = 0; i < Src.Path.length; i++) {
|
||||
if (!V || typeof V !== 'object') return null;
|
||||
V = V[Src.Path[i]];
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
||||
function ScanMeshNodes(tank, nodes, stats, Seen) {
|
||||
Seen = Seen || new WeakSet();
|
||||
function Try(V) {
|
||||
// ① 有缓存路径:直接解析(开销极小);每 300 帧强制重扫一次,捡起后加载的部件
|
||||
ScanTick++;
|
||||
var NeedRescan = (ScanTick % 300) === 0;
|
||||
var Cached = NodeSrcCache.get(tank);
|
||||
if (!NeedRescan && Cached && Cached.length) {
|
||||
var AllOk = true;
|
||||
for (var c = 0; c < Cached.length; c++) {
|
||||
var V0 = ResolveSrc(Cached[c]);
|
||||
if (!IsSceneNode(V0)) { AllOk = false; break; }
|
||||
if (!Seen.has(V0)) CollectMeshNodes(V0, nodes, 0, 'scan', stats, Seen);
|
||||
}
|
||||
if (AllOk) return;
|
||||
}
|
||||
// ② 缓存失效或首次:全量扫描并重建路径表
|
||||
var Srcs = [];
|
||||
function Try(V, Comp, Path) {
|
||||
if (!IsSceneNode(V) || Seen.has(V)) return;
|
||||
CollectMeshNodes(V, nodes, 0, 'scan', stats, Seen);
|
||||
Srcs.push({ Comp: Comp, Path: Path });
|
||||
}
|
||||
try {
|
||||
tank.qz1_1.s2a_1.forEach(function (VL) {
|
||||
@@ -539,22 +569,23 @@
|
||||
for (var K in comp) {
|
||||
var V = comp[K];
|
||||
if (!IsPlainObj(V)) continue;
|
||||
if (IsSceneNode(V)) { Try(V); continue; }
|
||||
if (IsSceneNode(V)) { Try(V, comp, [K]); continue; }
|
||||
// 深度 2/3:节点常包在皮肤对象/包装对象里(如 skin.h159_1、weaponSkin.e11p_1.a17q_1)
|
||||
try {
|
||||
for (var K2 in V) {
|
||||
var V2 = V[K2];
|
||||
if (!IsPlainObj(V2)) continue;
|
||||
if (IsSceneNode(V2)) { Try(V2); continue; }
|
||||
if (IsSceneNode(V2)) { Try(V2, comp, [K, K2]); continue; }
|
||||
for (var K3 in V2) {
|
||||
var V3 = V2[K3];
|
||||
if (IsPlainObj(V3)) Try(V3);
|
||||
if (IsPlainObj(V3)) Try(V3, comp, [K, K2, K3]);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
} catch (e) {}
|
||||
NodeSrcCache.set(tank, Srcs);
|
||||
}
|
||||
|
||||
// 结果级去重:同一 mesh 资源 + 同一节点名,只保留一份
|
||||
@@ -612,10 +643,9 @@
|
||||
});
|
||||
} catch(e) {}
|
||||
}
|
||||
// ③ 仍然为空才做组件字段扫描(不加节流:节流会导致「这帧有模型、下帧只有点」的闪烁)
|
||||
if (nodes.length === 0) {
|
||||
try { ScanMeshNodes(tank, nodes, stats ? stats.scan : null, Seen); } catch (e) {}
|
||||
}
|
||||
// ③ 结构扫描:无条件补充漏采(车身根/部件表往往只覆盖一部分)
|
||||
// 重复实例(皮肤树/场景树同 tp 同名)由 DedupNodes 收掉,不会再出现"两个身体"
|
||||
try { ScanMeshNodes(tank, nodes, stats ? stats.scan : null, Seen); } catch (e) {}
|
||||
// ④ 炮塔(独立于车身根;重复实例由 DedupNodes 收掉)
|
||||
var turretNode = GetTurretNode(tank);
|
||||
if (stats) stats.turretComp = !!turretNode;
|
||||
|
||||
Reference in new issue
Block a user