Phase 1.1-1.3 : bridge GLB → SkinnedMesh
Premier jalon Phase 1 : conversion d'un GltfData (format legacy 11-joints PlayerAnimator) vers SkinnedMesh Epic Fight (biped ~20 joints). Files : - rig/bridge/GlbJointAliasTable.java : table mapping statique PlayerAnimator → biped EF (body/torso→Chest, leftUpperArm→Arm_L, leftLowerArm→Elbow_L, etc). Fallback Root pour inconnus. Bypass si nom déjà biped (Root/Torso/Chest/Head ou suffixe _R/_L). - rig/bridge/GltfToSkinnedMesh.java : convert(GltfData, AssetAccessor<Armature>) → SkinnedMesh. Pré-calcule jointIdMap, boucle vertices (pos/normal/uv + drop 4th joint à plus faible poids + renormalise 3 restants), groupe indices par primitive (material) en VanillaMeshPartDefinition. Note : animations GLB ignorées (scope Phase 4 JSON EF authored). Compile BUILD SUCCESSFUL maintenu.
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.bridge;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* Table d'alias runtime pour mapper les noms de joints des GLB legacy TiedUp
|
||||
* (riggés via PlayerAnimator / bendy-lib avec noms type {@code leftUpperArm})
|
||||
* vers le skeleton biped Epic Fight utilisé par RIG ({@code Arm_L}, etc.).
|
||||
*
|
||||
* <p>Voir {@code docs/plans/rig/ARCHITECTURE.md §6.3} pour la source de vérité
|
||||
* du mapping. Tout joint inconnu après lookup doit être loggé WARN par le
|
||||
* caller et fallback sur {@code Root}.</p>
|
||||
*
|
||||
* <p><b>Cas spécial "body/torso"</b> — le GLB legacy a souvent un unique joint
|
||||
* couvrant l'ensemble du torse. On le mappe sur {@code Chest} par défaut
|
||||
* (meilleur fit pour les items bondage majoritairement attachés au haut du
|
||||
* corps : harnais, menottes de poitrine, collier). Si un item a besoin
|
||||
* d'attachement à {@code Torso} (ceinture), le modeler devra renommer son
|
||||
* joint en {@code waist} explicitement.</p>
|
||||
*/
|
||||
public final class GlbJointAliasTable {
|
||||
|
||||
/**
|
||||
* Mapping direct PlayerAnimator → biped EF. Les clés sont la forme
|
||||
* lowercase EXACTE des noms exportés par les GLB legacy.
|
||||
*/
|
||||
private static final Map<String, String> ALIAS = ImmutableMap.<String, String>builder()
|
||||
// Torso region
|
||||
.put("body", "Chest")
|
||||
.put("torso", "Chest")
|
||||
.put("chest", "Chest")
|
||||
.put("waist", "Torso")
|
||||
.put("hip", "Torso")
|
||||
|
||||
// Head
|
||||
.put("head", "Head")
|
||||
|
||||
// Arms left
|
||||
.put("leftshoulder", "Shoulder_L")
|
||||
.put("leftupperarm", "Arm_L")
|
||||
.put("leftarm", "Arm_L")
|
||||
.put("leftlowerarm", "Elbow_L")
|
||||
.put("leftforearm", "Elbow_L")
|
||||
.put("leftelbow", "Elbow_L")
|
||||
.put("lefthand", "Hand_L")
|
||||
|
||||
// Arms right
|
||||
.put("rightshoulder", "Shoulder_R")
|
||||
.put("rightupperarm", "Arm_R")
|
||||
.put("rightarm", "Arm_R")
|
||||
.put("rightlowerarm", "Elbow_R")
|
||||
.put("rightforearm", "Elbow_R")
|
||||
.put("rightelbow", "Elbow_R")
|
||||
.put("righthand", "Hand_R")
|
||||
|
||||
// Legs left
|
||||
.put("leftupperleg", "Thigh_L")
|
||||
.put("leftleg", "Thigh_L")
|
||||
.put("leftlowerleg", "Knee_L")
|
||||
.put("leftknee", "Knee_L")
|
||||
.put("leftfoot", "Leg_L")
|
||||
|
||||
// Legs right
|
||||
.put("rightupperleg", "Thigh_R")
|
||||
.put("rightleg", "Thigh_R")
|
||||
.put("rightlowerleg", "Knee_R")
|
||||
.put("rightknee", "Knee_R")
|
||||
.put("rightfoot", "Leg_R")
|
||||
|
||||
// Root fallback (déjà nommé Root dans GLB modernes)
|
||||
.put("root", "Root")
|
||||
.put("armature", "Root")
|
||||
.build();
|
||||
|
||||
private GlbJointAliasTable() {}
|
||||
|
||||
/**
|
||||
* Traduit un nom de joint GLB legacy vers le nom biped EF équivalent.
|
||||
* Case-insensitive. Les noms déjà au format biped EF (ex: {@code Arm_L}) sont
|
||||
* retournés tels quels après vérification.
|
||||
*
|
||||
* @param gltfJointName nom tel qu'exporté dans le GLB (jointNames[])
|
||||
* @return nom biped EF (ex: {@code Arm_L}), ou null si inconnu
|
||||
*/
|
||||
@Nullable
|
||||
public static String mapGltfJointName(String gltfJointName) {
|
||||
if (gltfJointName == null || gltfJointName.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Direct hit sur le biped EF (GLB moderne déjà bien rigged).
|
||||
if (isBipedJointName(gltfJointName)) {
|
||||
return gltfJointName;
|
||||
}
|
||||
|
||||
return ALIAS.get(gltfJointName.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si un nom est déjà au format biped EF. Utilisé pour court-circuiter
|
||||
* l'alias lookup sur les GLB modernes.
|
||||
*/
|
||||
public static boolean isBipedJointName(String name) {
|
||||
// Heuristique : les noms biped EF sont en PascalCase avec suffixe _R/_L,
|
||||
// ou parmi {Root, Torso, Chest, Head}.
|
||||
return switch (name) {
|
||||
case "Root", "Torso", "Chest", "Head" -> true;
|
||||
default -> name.endsWith("_R") || name.endsWith("_L");
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user