fix render3
This commit is contained in:
1 parent
1404db1866
commit
c3af49d3e8
1 file changed
+12
-115
@@ -99,6 +99,18 @@ function resolveSkeletalBone(rawName) {
|
|||||||
// eixo mais longo) — bem diferente de uma estrutura anatômica de verdade
|
// eixo mais longo) — bem diferente de uma estrutura anatômica de verdade
|
||||||
// (mesmo um nervo fino tem curvas/ramificações reais). Isso não depende
|
// (mesmo um nervo fino tem curvas/ramificações reais). Isso não depende
|
||||||
// de nome nenhum, então não arrisca excluir a estrutura errada.
|
// de nome nenhum, então não arrisca excluir a estrutura errada.
|
||||||
|
//
|
||||||
|
// TENTATIVA DESCARTADA: chegamos a tentar ir além e remover, dentro da
|
||||||
|
// MESMA malha de uma estrutura real, só o "pedaço" desconectado que fosse
|
||||||
|
// reto/fino (pra pegar linhas de chamada soldadas junto de uma estrutura
|
||||||
|
// de verdade). Reverted: uma faixa real de pele fina e comprida (ex: bem
|
||||||
|
// em cima da coluna) tem a MESMA assinatura geométrica de uma linha de
|
||||||
|
// chamada (poucos vértices, reta, fina) depois de simplificada — não dá
|
||||||
|
// pra distinguir as duas só pela forma, e a tentativa abriu buracos de
|
||||||
|
// verdade na malha (pele sumindo, esqueleto aparecendo por baixo). Fica
|
||||||
|
// só a classificação por MALHA INTEIRA abaixo, que é mais conservadora:
|
||||||
|
// pode deixar passar algum tracinho residual, mas nunca teve o risco de
|
||||||
|
// apagar uma estrutura real.
|
||||||
const LEADER_LINE_SOURCE_KEYS = new Set(["nervous", "regions"]);
|
const LEADER_LINE_SOURCE_KEYS = new Set(["nervous", "regions"]);
|
||||||
|
|
||||||
function isLeaderLineMesh(mesh) {
|
function isLeaderLineMesh(mesh) {
|
||||||
@@ -175,120 +187,6 @@ function isLeaderLinePointCloud(points) {
|
|||||||
return p90 < axisLen * 0.1;
|
return p90 < axisLen * 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cobre um caso que isLeaderLineMesh() sozinho não pega: quando a linha de
|
|
||||||
// chamada NÃO é um nó separado, e sim geometria extra soldada dentro do
|
|
||||||
// MESMO primitivo de uma estrutura real (ex: a malha de uma região da pele
|
|
||||||
// vem com um "espinho" fino grudado nela desde a exportação do FBX
|
|
||||||
// original). Como a maior parte da malha nesse caso é a estrutura de
|
|
||||||
// verdade (não uma linha), o teste de colinearidade da malha INTEIRA
|
|
||||||
// reprova, e o espinho sobrevive grudado — foi exatamente o que apareceu
|
|
||||||
// como tracinhos saindo do corpo (cabeça, mão, canela) mesmo depois do
|
|
||||||
// filtro por malha. A correção certa é olhar por PEDAÇO CONECTADO da
|
|
||||||
// malha (componentes que não compartilham nenhum vértice entre si), não a
|
|
||||||
// malha toda: cada pedaço geometricamente desconectado é testado
|
|
||||||
// separadamente, e só os que passam no teste de "reto e fino" são
|
|
||||||
// removidos — a estrutura real (um componente só, com volume) nunca é.
|
|
||||||
function stripLeaderLineComponents(mesh) {
|
|
||||||
try {
|
|
||||||
stripLeaderLineComponentsUnsafe(mesh);
|
|
||||||
} catch {
|
|
||||||
// Nunca deixa uma malha atípica derrubar o pipeline inteiro — na
|
|
||||||
// dúvida, mantém a estrutura como veio (mesmo comportamento de antes
|
|
||||||
// desta função existir).
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function stripLeaderLineComponentsUnsafe(mesh) {
|
|
||||||
for (const prim of mesh.listPrimitives()) {
|
|
||||||
const posAccessor = prim.getAttribute("POSITION");
|
|
||||||
const indicesAccessor = prim.getIndices();
|
|
||||||
if (!posAccessor || !indicesAccessor) continue;
|
|
||||||
const indices = indicesAccessor.getArray();
|
|
||||||
const posArr = posAccessor.getArray();
|
|
||||||
if (!indices || !posArr || indices.length < 3) continue;
|
|
||||||
const at = (vi) => [posArr[vi * 3], posArr[vi * 3 + 1], posArr[vi * 3 + 2]];
|
|
||||||
|
|
||||||
// Union-Find simples pra agrupar vértices que compartilham alguma face
|
|
||||||
// (= estão no mesmo pedaço fisicamente conectado da malha).
|
|
||||||
const parent = new Map();
|
|
||||||
function find(x) {
|
|
||||||
let root = x;
|
|
||||||
while (parent.get(root) !== root) root = parent.get(root);
|
|
||||||
while (parent.get(x) !== root) {
|
|
||||||
const next = parent.get(x);
|
|
||||||
parent.set(x, root);
|
|
||||||
x = next;
|
|
||||||
}
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
function union(a, b) {
|
|
||||||
const ra = find(a), rb = find(b);
|
|
||||||
if (ra !== rb) parent.set(ra, rb);
|
|
||||||
}
|
|
||||||
|
|
||||||
const faceCount = Math.floor(indices.length / 3);
|
|
||||||
for (let f = 0; f < faceCount; f++) {
|
|
||||||
const a = indices[f * 3], b = indices[f * 3 + 1], c = indices[f * 3 + 2];
|
|
||||||
if (!parent.has(a)) parent.set(a, a);
|
|
||||||
if (!parent.has(b)) parent.set(b, b);
|
|
||||||
if (!parent.has(c)) parent.set(c, c);
|
|
||||||
union(a, b);
|
|
||||||
union(b, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
const facesByRoot = new Map();
|
|
||||||
for (let f = 0; f < faceCount; f++) {
|
|
||||||
const root = find(indices[f * 3]);
|
|
||||||
if (!facesByRoot.has(root)) facesByRoot.set(root, []);
|
|
||||||
facesByRoot.get(root).push(f);
|
|
||||||
}
|
|
||||||
// Malha inteira é UM pedaço só conectado — nada pra separar/remover.
|
|
||||||
if (facesByRoot.size <= 1) continue;
|
|
||||||
|
|
||||||
// Uma linha de chamada de verdade no app original é um segmento bem
|
|
||||||
// simples (poucos vértices) — bem menor que qualquer pedaço real de
|
|
||||||
// pele/estrutura. Sem esse limite de tamanho, uma faixa real só
|
|
||||||
// COMPRIDA (ex: a pele bem em cima da coluna, entre as costas
|
|
||||||
// esquerda e direita) também passa no teste de "reto e fino" e acaba
|
|
||||||
// sendo apagada por engano, abrindo um buraco de verdade na malha
|
|
||||||
// (foi exatamente o que aconteceu e o usuário reportou). Limitamos a
|
|
||||||
// remoção a pedaços pequenos em termos absolutos E relativos ao resto
|
|
||||||
// da malha.
|
|
||||||
const totalVerts = posAccessor.getCount();
|
|
||||||
const MAX_LEADER_LINE_VERTS = 40;
|
|
||||||
const MAX_LEADER_LINE_SHARE = 0.15;
|
|
||||||
|
|
||||||
const keptFaces = [];
|
|
||||||
let removedAny = false;
|
|
||||||
for (const faceList of facesByRoot.values()) {
|
|
||||||
const vertSet = new Set();
|
|
||||||
for (const f of faceList) {
|
|
||||||
vertSet.add(indices[f * 3]);
|
|
||||||
vertSet.add(indices[f * 3 + 1]);
|
|
||||||
vertSet.add(indices[f * 3 + 2]);
|
|
||||||
}
|
|
||||||
const smallEnough =
|
|
||||||
vertSet.size <= MAX_LEADER_LINE_VERTS && vertSet.size <= totalVerts * MAX_LEADER_LINE_SHARE;
|
|
||||||
if (smallEnough && isLeaderLinePointCloud([...vertSet].map(at))) {
|
|
||||||
removedAny = true;
|
|
||||||
} else {
|
|
||||||
keptFaces.push(...faceList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!removedAny || keptFaces.length === 0) continue;
|
|
||||||
|
|
||||||
keptFaces.sort((x, y) => x - y);
|
|
||||||
const newIndices = new indices.constructor(keptFaces.length * 3);
|
|
||||||
let w = 0;
|
|
||||||
for (const f of keptFaces) {
|
|
||||||
newIndices[w++] = indices[f * 3];
|
|
||||||
newIndices[w++] = indices[f * 3 + 1];
|
|
||||||
newIndices[w++] = indices[f * 3 + 2];
|
|
||||||
}
|
|
||||||
indicesAccessor.setArray(newIndices);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function classifySystem(key, rawName) {
|
function classifySystem(key, rawName) {
|
||||||
const target = SOURCE_TARGETS[key];
|
const target = SOURCE_TARGETS[key];
|
||||||
if (target.system) return target.system;
|
if (target.system) return target.system;
|
||||||
@@ -377,7 +275,6 @@ for (const { fbx, key } of SOURCES) {
|
|||||||
for (const child of node.listChildren()) visit(child);
|
for (const child of node.listChildren()) visit(child);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (LEADER_LINE_SOURCE_KEYS.has(key)) stripLeaderLineComponents(mesh);
|
|
||||||
systemSlug = classifySystem(key, rawName);
|
systemSlug = classifySystem(key, rawName);
|
||||||
// Nomes de muscular/regiões/referências vêm com sufixo ".l"/".r"/
|
// Nomes de muscular/regiões/referências vêm com sufixo ".l"/".r"/
|
||||||
// ".j" (lateralidade) em vez da palavra "Left"/"Right" — sem tirar
|
// ".j" (lateralidade) em vez da palavra "Left"/"Right" — sem tirar
|
||||||
|
|||||||
Reference in new issue
Block a user