retrabalho muscular
This commit is contained in:
1 parent
e3521ca494
commit
086befc148
1 file changed
+87
-8
@@ -34,6 +34,78 @@ function hexToRgb(hex) {
|
|||||||
return [((n >> 16) & 255) / 255, ((n >> 8) & 255) / 255, (n & 255) / 255, 1];
|
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");
|
const COMBINING_MARKS = new RegExp("[\\u0300-\\u036f]", "g");
|
||||||
|
|
||||||
function slugify(s) {
|
function slugify(s) {
|
||||||
@@ -267,17 +339,23 @@ for (const { fbx, key } of SOURCES) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Um material por sistema alvo deste arquivo (recoloração consistente,
|
// 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();
|
const materialCache = new Map();
|
||||||
function materialFor(systemSlug) {
|
function materialFor(systemSlug, variantKey) {
|
||||||
if (materialCache.has(systemSlug)) return materialCache.get(systemSlug);
|
const cacheKey = variantKey ? `${systemSlug}::${variantKey}` : systemSlug;
|
||||||
|
if (materialCache.has(cacheKey)) return materialCache.get(cacheKey);
|
||||||
const sys = systemBySlug.get(systemSlug);
|
const sys = systemBySlug.get(systemSlug);
|
||||||
|
const baseHex = sys?.colorHex ?? "#cccccc";
|
||||||
|
const colorHex = variantKey ? muscleColorVariant(baseHex, variantKey) : baseHex;
|
||||||
const mat = doc
|
const mat = doc
|
||||||
.createMaterial(systemSlug)
|
.createMaterial(cacheKey)
|
||||||
.setBaseColorFactor(hexToRgb(sys?.colorHex ?? "#cccccc"))
|
.setBaseColorFactor(hexToRgb(colorHex))
|
||||||
.setRoughnessFactor(0.55)
|
.setRoughnessFactor(0.55)
|
||||||
.setMetallicFactor(0.05);
|
.setMetallicFactor(0.05);
|
||||||
materialCache.set(systemSlug, mat);
|
materialCache.set(cacheKey, mat);
|
||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +372,7 @@ for (const { fbx, key } of SOURCES) {
|
|||||||
const uniqueMeshName = n === 1 ? rawName : `${rawName} (${n})`;
|
const uniqueMeshName = n === 1 ? rawName : `${rawName} (${n})`;
|
||||||
node.setName(uniqueMeshName);
|
node.setName(uniqueMeshName);
|
||||||
|
|
||||||
let systemSlug, namePt, nameEn, description;
|
let systemSlug, namePt, nameEn, description, muscleColorKey;
|
||||||
|
|
||||||
if (key === "skeletal") {
|
if (key === "skeletal") {
|
||||||
const resolved = resolveSkeletalBone(rawName);
|
const resolved = resolveSkeletalBone(rawName);
|
||||||
@@ -352,9 +430,10 @@ for (const { fbx, key } of SOURCES) {
|
|||||||
: key === "nervous"
|
: key === "nervous"
|
||||||
? NERVE_DESCRIPTIONS[base.toLowerCase()] ?? ""
|
? 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);
|
for (const prim of mesh.listPrimitives()) prim.setMaterial(material);
|
||||||
|
|
||||||
const sys = systemBySlug.get(systemSlug);
|
const sys = systemBySlug.get(systemSlug);
|
||||||
|
|||||||
Reference in new issue
Block a user