fix(3d): rewrite wrl fallback parser to maintain hierarchy and fix phase extraction

This commit is contained in:
2026-09-24 17:47:45 +00:00
parent b226fc09fe
commit bfb2464c03
+51 -19
View File
@@ -191,30 +191,52 @@ function parseVrmlDirectFallback(
const group = new THREE.Group(); const group = new THREE.Group();
group.name = 'WRL_Direct_Fallback_Root'; group.name = 'WRL_Direct_Fallback_Root';
const defRegex = /DEF\s+([^\s\{\[\(\)]+)[\s\S]*?(?:point\s*\[([\s\S]*?)\])[\s\S]*?(?:coordIndex\s*\[([\s\S]*?)\])/gi; const tokenRegex = /(DEF\s+([^\s\{\[\(\)]+))|(\{)|(\})|(point\s*\[([\s\S]*?)\])|(coordIndex\s*\[([\s\S]*?)\])/gi;
let match: RegExpExecArray | null; let match: RegExpExecArray | null;
const stack: { name: string; group: THREE.Group }[] = [{ name: 'ROOT', group }];
let currentGroup = group;
let lastDef: string | null = null;
let currentPoints: number[] | null = null;
let count = 0; let count = 0;
while ((match = defRegex.exec(vrmlText)) !== null) { while ((match = tokenRegex.exec(vrmlText)) !== null) {
count++; if (match[1]) {
const rawDefName = match[1].trim(); lastDef = match[2];
const originalName = nameMap.get(rawDefName) || rawDefName; } else if (match[3]) {
const pointStr = match[2]; const newGroup = new THREE.Group();
const indexStr = match[3]; if (lastDef) {
newGroup.name = nameMap.get(lastDef) || lastDef;
lastDef = null;
} else {
newGroup.name = 'Unnamed_Group';
}
currentGroup.add(newGroup);
stack.push({ name: newGroup.name, group: newGroup });
currentGroup = newGroup;
} else if (match[4]) {
if (stack.length > 1) {
stack.pop();
currentGroup = stack[stack.length - 1].group;
}
} else if (match[5]) {
const rawCoords = match[6].trim().split(/[\s,]+/).filter(Boolean).map(Number);
if (rawCoords.length >= 9) {
currentPoints = rawCoords;
}
} else if (match[7]) {
if (!currentPoints) continue;
const rawCoords = pointStr.trim().split(/[\s,]+/).filter(Boolean).map(Number); const indexStr = match[8];
if (rawCoords.length < 9) continue; const rawIndices = indexStr.trim().split(/[\s,]+/).filter(Boolean).map(Number);
const vertices: [number, number, number][] = []; const vertices: [number, number, number][] = [];
for (let i = 0; i < rawCoords.length; i += 3) { for (let i = 0; i < currentPoints.length; i += 3) {
if (!isNaN(rawCoords[i]) && !isNaN(rawCoords[i + 1]) && !isNaN(rawCoords[i + 2])) { if (!isNaN(currentPoints[i]) && !isNaN(currentPoints[i + 1]) && !isNaN(currentPoints[i + 2])) {
vertices.push([rawCoords[i], rawCoords[i + 1], rawCoords[i + 2]]); vertices.push([currentPoints[i], currentPoints[i + 1], currentPoints[i + 2]]);
} }
} }
if (vertices.length === 0) continue;
const rawIndices = indexStr.trim().split(/[\s,]+/).filter(Boolean).map(Number);
const triangleIndices: number[] = []; const triangleIndices: number[] = [];
let currentPoly: number[] = []; let currentPoly: number[] = [];
@@ -245,17 +267,27 @@ function parseVrmlDirectFallback(
if (v) positions.push(v[0], v[1], v[2]); if (v) positions.push(v[0], v[1], v[2]);
} }
if (positions.length === 0) continue; if (positions.length > 0) {
const geometry = new THREE.BufferGeometry(); const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
geometry.computeVertexNormals(); geometry.computeVertexNormals();
const mesh = new THREE.Mesh(geometry); const mesh = new THREE.Mesh(geometry);
mesh.name = originalName;
let meshName = `PECA-${++count}`;
for (let i = stack.length - 1; i >= 0; i--) {
if (stack[i].name && stack[i].name !== 'Unnamed_Group' && stack[i].name !== 'ROOT') {
meshName = stack[i].name;
break;
}
}
mesh.name = meshName;
mesh.castShadow = true; mesh.castShadow = true;
mesh.receiveShadow = true; mesh.receiveShadow = true;
group.add(mesh);
currentGroup.add(mesh);
}
}
} }
if (count === 0) { if (count === 0) {