fix(wireframe): 采集改为单路径优先并按 mesh+位置去重,修复重复身体与卡顿
This commit is contained in:
1 parent
af8cde08d2
commit
797f28c8cd
3 files changed
+138
-21
No files matched your search
@@ -2082,7 +2082,44 @@
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 结果级去重:同一 mesh 资源 + 同一世界平移,只保留一份
|
||||
// (引擎里同一逻辑节点可能存在「皮肤树 / 场景树」两套实例,AABB/矩阵更新时机不同,
|
||||
// 两套都画会出现「复制出一个不动的身体,过一会才跟上」)
|
||||
var TpIds = new WeakMap();
|
||||
var TpNextId = 1;
|
||||
function DedupNodes(nodes) {
|
||||
if (nodes.length < 2) return nodes;
|
||||
var Keys = new Set();
|
||||
var Out = [];
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var N = nodes[i];
|
||||
var Tp = N.tp;
|
||||
var Id = TpIds.get(Tp);
|
||||
if (!Id) { Id = TpNextId++; TpIds.set(Tp, Id); }
|
||||
var M = N.node && N.node.p35_1;
|
||||
var Pos = M ? (Math.round(M[12]) + ',' + Math.round(M[13]) + ',' + Math.round(M[14])) : '?';
|
||||
var Key = Id + ':' + N.name + ':' + Pos;
|
||||
if (Keys.has(Key)) continue;
|
||||
Keys.add(Key);
|
||||
Out.push(N);
|
||||
}
|
||||
return Out;
|
||||
}
|
||||
|
||||
// 扫描节流:仅在主路径完全采不到时使用,且同一辆坦克至少间隔 10 帧
|
||||
var ScanTick = 0;
|
||||
var LastScanAt = new WeakMap();
|
||||
function ShouldScanNow(tank) {
|
||||
ScanTick++;
|
||||
var Last = LastScanAt.get(tank) || 0;
|
||||
if (ScanTick - Last < 10) return false;
|
||||
LastScanAt.set(tank, ScanTick);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===== 提取坦克的mesh数据 =====
|
||||
// 采集策略:**单一路径优先**,绝不把两条路径的结果混在一起(混在一起就是"复制身体")
|
||||
// ① 皮肤组件 h159_1(实际渲染树根)→ ② 部件表 → ③ 组件字段扫描(节流兜底)
|
||||
function GetTankMeshData(tank, stats) {
|
||||
var nodes = [];
|
||||
var Seen = new WeakSet();
|
||||
@@ -2092,12 +2129,12 @@
|
||||
stats.hullSource = skin ? 'g159_1' : (skinComp ? '有组件但无皮肤' : '无皮肤组件');
|
||||
stats.hullParts = (skin && typeof skin.g17r_1.e1 === 'function') ? skin.g17r_1.e1() : -1;
|
||||
}
|
||||
// ① 车身根节点:皮肤组件 h159_1 是「所有部件节点」的总根(比逐个部件更完整)
|
||||
// ① 主路径:车身根节点(包含全部部件节点)
|
||||
if (skinComp && skinComp.h159_1) {
|
||||
try { CollectMeshNodes(skinComp.h159_1, nodes, 0, 'hull', stats ? stats.hull : null, Seen); } catch (e) {}
|
||||
}
|
||||
// ② 部件表:某些构建下根节点不完整,仍逐个部件补一遍(Seen 自动去重)
|
||||
if (skin) {
|
||||
// ② 根节点采不到才退回部件表
|
||||
if (nodes.length === 0 && skin) {
|
||||
try {
|
||||
ForEachInList(skin.g17r_1, function (part) {
|
||||
if (!part) return;
|
||||
@@ -2113,16 +2150,18 @@
|
||||
});
|
||||
} catch(e) {}
|
||||
}
|
||||
// ③ 仍然为空才做组件字段扫描(节流,避免每帧全量遍历造成卡顿)
|
||||
if (nodes.length === 0 && ShouldScanNow(tank)) {
|
||||
try { ScanMeshNodes(tank, nodes, stats ? stats.scan : null, Seen); } catch (e) {}
|
||||
}
|
||||
// ④ 炮塔(独立于车身根;重复实例由 DedupNodes 收掉)
|
||||
var turretNode = GetTurretNode(tank);
|
||||
if (stats) stats.turretComp = !!turretNode;
|
||||
if (turretNode) {
|
||||
if (stats) stats.turretRoot = true;
|
||||
try { CollectMeshNodes(turretNode, nodes, 0, 'turret', stats ? stats.turret : null, Seen); } catch(e) {}
|
||||
}
|
||||
// ③ 无条件结构扫描兜底:把组件字段里能看到的 3D 节点全部补进来
|
||||
// (解决「有的坦克只有点」「有的只有头没有身子」——结构字段不完整时漏采)
|
||||
try { ScanMeshNodes(tank, nodes, stats ? stats.scan : null, Seen); } catch (e) {}
|
||||
return nodes;
|
||||
return DedupNodes(nodes);
|
||||
}
|
||||
|
||||
// ===== 残留节点检测(世界矩阵"冻结")→ 拖拽跟随 =====
|
||||
|
||||
+46
-7
@@ -2082,7 +2082,44 @@
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 结果级去重:同一 mesh 资源 + 同一世界平移,只保留一份
|
||||
// (引擎里同一逻辑节点可能存在「皮肤树 / 场景树」两套实例,AABB/矩阵更新时机不同,
|
||||
// 两套都画会出现「复制出一个不动的身体,过一会才跟上」)
|
||||
var TpIds = new WeakMap();
|
||||
var TpNextId = 1;
|
||||
function DedupNodes(nodes) {
|
||||
if (nodes.length < 2) return nodes;
|
||||
var Keys = new Set();
|
||||
var Out = [];
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var N = nodes[i];
|
||||
var Tp = N.tp;
|
||||
var Id = TpIds.get(Tp);
|
||||
if (!Id) { Id = TpNextId++; TpIds.set(Tp, Id); }
|
||||
var M = N.node && N.node.p35_1;
|
||||
var Pos = M ? (Math.round(M[12]) + ',' + Math.round(M[13]) + ',' + Math.round(M[14])) : '?';
|
||||
var Key = Id + ':' + N.name + ':' + Pos;
|
||||
if (Keys.has(Key)) continue;
|
||||
Keys.add(Key);
|
||||
Out.push(N);
|
||||
}
|
||||
return Out;
|
||||
}
|
||||
|
||||
// 扫描节流:仅在主路径完全采不到时使用,且同一辆坦克至少间隔 10 帧
|
||||
var ScanTick = 0;
|
||||
var LastScanAt = new WeakMap();
|
||||
function ShouldScanNow(tank) {
|
||||
ScanTick++;
|
||||
var Last = LastScanAt.get(tank) || 0;
|
||||
if (ScanTick - Last < 10) return false;
|
||||
LastScanAt.set(tank, ScanTick);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===== 提取坦克的mesh数据 =====
|
||||
// 采集策略:**单一路径优先**,绝不把两条路径的结果混在一起(混在一起就是"复制身体")
|
||||
// ① 皮肤组件 h159_1(实际渲染树根)→ ② 部件表 → ③ 组件字段扫描(节流兜底)
|
||||
function GetTankMeshData(tank, stats) {
|
||||
var nodes = [];
|
||||
var Seen = new WeakSet();
|
||||
@@ -2092,12 +2129,12 @@
|
||||
stats.hullSource = skin ? 'g159_1' : (skinComp ? '有组件但无皮肤' : '无皮肤组件');
|
||||
stats.hullParts = (skin && typeof skin.g17r_1.e1 === 'function') ? skin.g17r_1.e1() : -1;
|
||||
}
|
||||
// ① 车身根节点:皮肤组件 h159_1 是「所有部件节点」的总根(比逐个部件更完整)
|
||||
// ① 主路径:车身根节点(包含全部部件节点)
|
||||
if (skinComp && skinComp.h159_1) {
|
||||
try { CollectMeshNodes(skinComp.h159_1, nodes, 0, 'hull', stats ? stats.hull : null, Seen); } catch (e) {}
|
||||
}
|
||||
// ② 部件表:某些构建下根节点不完整,仍逐个部件补一遍(Seen 自动去重)
|
||||
if (skin) {
|
||||
// ② 根节点采不到才退回部件表
|
||||
if (nodes.length === 0 && skin) {
|
||||
try {
|
||||
ForEachInList(skin.g17r_1, function (part) {
|
||||
if (!part) return;
|
||||
@@ -2113,16 +2150,18 @@
|
||||
});
|
||||
} catch(e) {}
|
||||
}
|
||||
// ③ 仍然为空才做组件字段扫描(节流,避免每帧全量遍历造成卡顿)
|
||||
if (nodes.length === 0 && ShouldScanNow(tank)) {
|
||||
try { ScanMeshNodes(tank, nodes, stats ? stats.scan : null, Seen); } catch (e) {}
|
||||
}
|
||||
// ④ 炮塔(独立于车身根;重复实例由 DedupNodes 收掉)
|
||||
var turretNode = GetTurretNode(tank);
|
||||
if (stats) stats.turretComp = !!turretNode;
|
||||
if (turretNode) {
|
||||
if (stats) stats.turretRoot = true;
|
||||
try { CollectMeshNodes(turretNode, nodes, 0, 'turret', stats ? stats.turret : null, Seen); } catch(e) {}
|
||||
}
|
||||
// ③ 无条件结构扫描兜底:把组件字段里能看到的 3D 节点全部补进来
|
||||
// (解决「有的坦克只有点」「有的只有头没有身子」——结构字段不完整时漏采)
|
||||
try { ScanMeshNodes(tank, nodes, stats ? stats.scan : null, Seen); } catch (e) {}
|
||||
return nodes;
|
||||
return DedupNodes(nodes);
|
||||
}
|
||||
|
||||
// ===== 残留节点检测(世界矩阵"冻结")→ 拖拽跟随 =====
|
||||
|
||||
@@ -557,7 +557,44 @@
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 结果级去重:同一 mesh 资源 + 同一世界平移,只保留一份
|
||||
// (引擎里同一逻辑节点可能存在「皮肤树 / 场景树」两套实例,AABB/矩阵更新时机不同,
|
||||
// 两套都画会出现「复制出一个不动的身体,过一会才跟上」)
|
||||
var TpIds = new WeakMap();
|
||||
var TpNextId = 1;
|
||||
function DedupNodes(nodes) {
|
||||
if (nodes.length < 2) return nodes;
|
||||
var Keys = new Set();
|
||||
var Out = [];
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var N = nodes[i];
|
||||
var Tp = N.tp;
|
||||
var Id = TpIds.get(Tp);
|
||||
if (!Id) { Id = TpNextId++; TpIds.set(Tp, Id); }
|
||||
var M = N.node && N.node.p35_1;
|
||||
var Pos = M ? (Math.round(M[12]) + ',' + Math.round(M[13]) + ',' + Math.round(M[14])) : '?';
|
||||
var Key = Id + ':' + N.name + ':' + Pos;
|
||||
if (Keys.has(Key)) continue;
|
||||
Keys.add(Key);
|
||||
Out.push(N);
|
||||
}
|
||||
return Out;
|
||||
}
|
||||
|
||||
// 扫描节流:仅在主路径完全采不到时使用,且同一辆坦克至少间隔 10 帧
|
||||
var ScanTick = 0;
|
||||
var LastScanAt = new WeakMap();
|
||||
function ShouldScanNow(tank) {
|
||||
ScanTick++;
|
||||
var Last = LastScanAt.get(tank) || 0;
|
||||
if (ScanTick - Last < 10) return false;
|
||||
LastScanAt.set(tank, ScanTick);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===== 提取坦克的mesh数据 =====
|
||||
// 采集策略:**单一路径优先**,绝不把两条路径的结果混在一起(混在一起就是"复制身体")
|
||||
// ① 皮肤组件 h159_1(实际渲染树根)→ ② 部件表 → ③ 组件字段扫描(节流兜底)
|
||||
function GetTankMeshData(tank, stats) {
|
||||
var nodes = [];
|
||||
var Seen = new WeakSet();
|
||||
@@ -567,12 +604,12 @@
|
||||
stats.hullSource = skin ? 'g159_1' : (skinComp ? '有组件但无皮肤' : '无皮肤组件');
|
||||
stats.hullParts = (skin && typeof skin.g17r_1.e1 === 'function') ? skin.g17r_1.e1() : -1;
|
||||
}
|
||||
// ① 车身根节点:皮肤组件 h159_1 是「所有部件节点」的总根(比逐个部件更完整)
|
||||
// ① 主路径:车身根节点(包含全部部件节点)
|
||||
if (skinComp && skinComp.h159_1) {
|
||||
try { CollectMeshNodes(skinComp.h159_1, nodes, 0, 'hull', stats ? stats.hull : null, Seen); } catch (e) {}
|
||||
}
|
||||
// ② 部件表:某些构建下根节点不完整,仍逐个部件补一遍(Seen 自动去重)
|
||||
if (skin) {
|
||||
// ② 根节点采不到才退回部件表
|
||||
if (nodes.length === 0 && skin) {
|
||||
try {
|
||||
ForEachInList(skin.g17r_1, function (part) {
|
||||
if (!part) return;
|
||||
@@ -588,16 +625,18 @@
|
||||
});
|
||||
} catch(e) {}
|
||||
}
|
||||
// ③ 仍然为空才做组件字段扫描(节流,避免每帧全量遍历造成卡顿)
|
||||
if (nodes.length === 0 && ShouldScanNow(tank)) {
|
||||
try { ScanMeshNodes(tank, nodes, stats ? stats.scan : null, Seen); } catch (e) {}
|
||||
}
|
||||
// ④ 炮塔(独立于车身根;重复实例由 DedupNodes 收掉)
|
||||
var turretNode = GetTurretNode(tank);
|
||||
if (stats) stats.turretComp = !!turretNode;
|
||||
if (turretNode) {
|
||||
if (stats) stats.turretRoot = true;
|
||||
try { CollectMeshNodes(turretNode, nodes, 0, 'turret', stats ? stats.turret : null, Seen); } catch(e) {}
|
||||
}
|
||||
// ③ 无条件结构扫描兜底:把组件字段里能看到的 3D 节点全部补进来
|
||||
// (解决「有的坦克只有点」「有的只有头没有身子」——结构字段不完整时漏采)
|
||||
try { ScanMeshNodes(tank, nodes, stats ? stats.scan : null, Seen); } catch (e) {}
|
||||
return nodes;
|
||||
return DedupNodes(nodes);
|
||||
}
|
||||
|
||||
// ===== 残留节点检测(世界矩阵"冻结")→ 拖拽跟随 =====
|
||||
|
||||
Reference in new issue
Block a user