retrabalho muscular

This commit is contained in:
Rodrigo Bertoldo de Sousa Martins committed 2026-09-11 21:22:34 -03:00
1 parent e3521ca494
commit 086befc148
1 file changed
+87 -8
+87 -8
View File
@@ -34,6 +34,78 @@ function hexToRgb(hex) {
return [((n >> 16) & 255) / 255, ((n >> 8) & 255) / 255, (n & 255) / 255, 1];
}
function hexToHsl(hex) {
const [r, g, b] = hexToRgb(hex);
const max = Math.max(r, g, b), min = Math.min(r, g, b);
const l = (max + min) / 2;
if (max === min) return [0, 0, l];
const d = max - min;
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
let h;
if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
else if (max === g) h = ((b - r) / d + 2) / 6;
else h = ((r - g) / d + 4) / 6;
return [h, s, l];
}
function hslToHex(h, s, l) {
h = ((h % 1) + 1) % 1; // normaliza pra [0,1) mesmo se ficou negativo
s = Math.min(1, Math.max(0, s));
l = Math.min(1, Math.max(0, l));
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
};
let r, g, b;
if (s === 0) {
r = g = b = l;
} else {
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
const toHex = (v) => Math.round(v * 255).toString(16).padStart(2, "0");
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
// Hash determinístico simples (não precisa ser criptográfico, só estável
// entre execuções) — usado pra variar a cor de cada músculo sempre do
// MESMO jeito, sem depender de sorte/aleatoriedade a cada rodada do
// pipeline.
function stringHash(s) {
let h = 0;
for (let i = 0; i < s.length; i++) {
h = (h * 31 + s.charCodeAt(i)) | 0;
}
return h >>> 0;
}
// O sistema muscular real do Z-Anatomy tem uma limitação: no tronco
// (peitoral, oblíquos, reto do abdome, serrátil), a malha em si é um
// "casco" externo liso, sem o relevo 3D que separa um músculo do outro
// (confirmado comparando com a exportação bruta, antes de qualquer
// processamento nosso — não é algo que a simplificação introduziu). Com
// UMA cor lisa pro sistema inteiro (como todo outro sistema usa), músculos
// vizinhos ficam visualmente indistinguíveis um do outro ali, mesmo sendo
// objetos e nomes diferentes por baixo — "parece tudo agrupado". Damos a
// cada músculo (mesma cor nos dois lados esquerdo/direito, já que é o
// MESMO músculo) uma variação pequena e determinística de matiz/luminosidade
// em torno da cor-base do sistema, só o bastante pra criar um limite visível
// entre estruturas vizinhas sem fugir da identidade de cor do sistema.
function muscleColorVariant(baseHex, variantKey) {
const [h, s, l] = hexToHsl(baseHex);
const hash = stringHash(variantKey);
const hueShift = (((hash % 21) - 10) / 360) * 2; // até ±10° de matiz
const lightShift = (((hash >> 8) % 21) - 10) / 100; // até ±10% de luminosidade
return hslToHex(h + hueShift, s, Math.min(0.85, Math.max(0.25, l + lightShift)));
}
const COMBINING_MARKS = new RegExp("[\\u0300-\\u036f]", "g");
function slugify(s) {
@@ -267,17 +339,23 @@ for (const { fbx, key } of SOURCES) {
}
// Um material por sistema alvo deste arquivo (recoloração consistente,
// independente de como a FBX/Unity original colorizava as malhas).
// independente de como a FBX/Unity original colorizava as malhas) — ou,
// quando variantKey é passado (sistema muscular, ver muscleColorVariant),
// um material por músculo, com uma variação de cor em torno da cor-base
// do sistema.
const materialCache = new Map();
function materialFor(systemSlug) {
if (materialCache.has(systemSlug)) return materialCache.get(systemSlug);
function materialFor(systemSlug, variantKey) {
const cacheKey = variantKey ? `${systemSlug}::${variantKey}` : systemSlug;
if (materialCache.has(cacheKey)) return materialCache.get(cacheKey);
const sys = systemBySlug.get(systemSlug);
const baseHex = sys?.colorHex ?? "#cccccc";
const colorHex = variantKey ? muscleColorVariant(baseHex, variantKey) : baseHex;
const mat = doc
.createMaterial(systemSlug)
.setBaseColorFactor(hexToRgb(sys?.colorHex ?? "#cccccc"))
.createMaterial(cacheKey)
.setBaseColorFactor(hexToRgb(colorHex))
.setRoughnessFactor(0.55)
.setMetallicFactor(0.05);
materialCache.set(systemSlug, mat);
materialCache.set(cacheKey, mat);
return mat;
}
@@ -294,7 +372,7 @@ for (const { fbx, key } of SOURCES) {
const uniqueMeshName = n === 1 ? rawName : `${rawName} (${n})`;
node.setName(uniqueMeshName);
let systemSlug, namePt, nameEn, description;
let systemSlug, namePt, nameEn, description, muscleColorKey;
if (key === "skeletal") {
const resolved = resolveSkeletalBone(rawName);
@@ -352,9 +430,10 @@ for (const { fbx, key } of SOURCES) {
: key === "nervous"
? NERVE_DESCRIPTIONS[base.toLowerCase()] ?? ""
: "";
if (key === "muscular") muscleColorKey = base.toLowerCase();
}
const material = materialFor(systemSlug);
const material = materialFor(systemSlug, muscleColorKey);
for (const prim of mesh.listPrimitives()) prim.setMaterial(material);
const sys = systemBySlug.get(systemSlug);