diff --git a/blight-assets/src/main/resources/animations/clips/idle.j3o b/blight-assets/src/main/resources/animations/clips/idle.j3o index a3c91f9..7eab74f 100644 Binary files a/blight-assets/src/main/resources/animations/clips/idle.j3o and b/blight-assets/src/main/resources/animations/clips/idle.j3o differ diff --git a/blight-assets/src/main/resources/animations/clips/sit_down.j3o b/blight-assets/src/main/resources/animations/clips/sit_down.j3o index 8753809..ed565f9 100644 Binary files a/blight-assets/src/main/resources/animations/clips/sit_down.j3o and b/blight-assets/src/main/resources/animations/clips/sit_down.j3o differ diff --git a/blight-assets/src/main/resources/animations/clips/sitting.j3o b/blight-assets/src/main/resources/animations/clips/sitting.j3o index 460dd45..470b091 100644 Binary files a/blight-assets/src/main/resources/animations/clips/sitting.j3o and b/blight-assets/src/main/resources/animations/clips/sitting.j3o differ diff --git a/blight-assets/src/main/resources/animations/clips/sitting_floor.j3o b/blight-assets/src/main/resources/animations/clips/sitting_floor.j3o index c0360e9..47bf788 100644 Binary files a/blight-assets/src/main/resources/animations/clips/sitting_floor.j3o and b/blight-assets/src/main/resources/animations/clips/sitting_floor.j3o differ diff --git a/blight-assets/src/main/resources/animations/clips/standup.j3o b/blight-assets/src/main/resources/animations/clips/standup.j3o index 305a0ae..46bd9f6 100644 Binary files a/blight-assets/src/main/resources/animations/clips/standup.j3o and b/blight-assets/src/main/resources/animations/clips/standup.j3o differ diff --git a/blight-editor/src/main/java/de/blight/editor/EditorApp.java b/blight-editor/src/main/java/de/blight/editor/EditorApp.java index 8d3a854..6f09330 100644 --- a/blight-editor/src/main/java/de/blight/editor/EditorApp.java +++ b/blight-editor/src/main/java/de/blight/editor/EditorApp.java @@ -45,6 +45,7 @@ import java.nio.ByteBuffer; import java.nio.file.*; import java.util.Comparator; import java.util.HashMap; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; diff --git a/blight-game/src/main/java/de/blight/game/animation/AnimationLibrary.java b/blight-game/src/main/java/de/blight/game/animation/AnimationLibrary.java index 5aba7f7..dae3098 100644 --- a/blight-game/src/main/java/de/blight/game/animation/AnimationLibrary.java +++ b/blight-game/src/main/java/de/blight/game/animation/AnimationLibrary.java @@ -259,7 +259,7 @@ public class AnimationLibrary extends BaseAppState { /** Loggt alle Tracks eines Clips: Bone-Name, hat Translation (T), Rotation (R), Scale (S). */ private void dumpClipTracks(com.jme3.anim.AnimClip clip) { - log.info("[ClipDump] '{}' length={:.3f}s tracks={}", + log.info("[ClipDump] '{}' length={}s tracks={}", clip.getName(), clip.getLength(), clip.getTracks().length); int tracksWithTranslation = 0; for (com.jme3.anim.AnimTrack t : clip.getTracks()) { @@ -272,7 +272,7 @@ public class AnimationLibrary extends BaseAppState { tracksWithTranslation++; com.jme3.math.Vector3f t0 = tt.getTranslations()[0]; com.jme3.math.Vector3f tN = tt.getTranslations()[tt.getTranslations().length - 1]; - log.info("[ClipDump] TRANSLATE '{}' frames={} start=({:.3f},{:.3f},{:.3f}) end=({:.3f},{:.3f},{:.3f}) deltaY={:.4f}", + log.info("[ClipDump] TRANSLATE '{}' frames={} start=({},{},{}) end=({},{},{}) deltaY={}", target, tt.getTranslations().length, t0.x, t0.y, t0.z, tN.x, tN.y, tN.z, tN.y - t0.y); } else { diff --git a/blight-game/src/main/java/de/blight/game/animation/RetargetingSystem.java b/blight-game/src/main/java/de/blight/game/animation/RetargetingSystem.java index 676b41c..f7e1877 100644 --- a/blight-game/src/main/java/de/blight/game/animation/RetargetingSystem.java +++ b/blight-game/src/main/java/de/blight/game/animation/RetargetingSystem.java @@ -451,4 +451,60 @@ public final class RetargetingSystem { } return null; } + + /** + * Entfernt Root-Motion aus dem Wurzel-Knochen (Tiefe 0) des Clips. + * + * Koordinatensystem dieses Rigs (Blender Z-Up-Export): + * bone-local X → Welt-X (seitliche Drift) → auf Frame-0-Wert fixieren + * bone-local Y → Welt-Z (Vorwärtsbewegung) → auf Frame-0-Wert fixieren + * bone-local Z → Welt-Y (Höhe / sit_down / Jump) → NIEMALS anfassen + * + * Erstellt neue TransformTrack-Objekte, damit BinaryExporter die Änderung serialisiert. + */ + public static AnimClip stripRootXZTranslations(AnimClip clip, Armature armature) { + if (clip == null || armature == null) return clip; + log.info("[Strip] Clip '{}' – {} Tracks", clip.getName(), clip.getTracks().length); + List> newTracks = new ArrayList<>(); + for (AnimTrack track : clip.getTracks()) { + if (!(track instanceof TransformTrack tt) || !(tt.getTarget() instanceof Joint j)) { + newTracks.add(track); + continue; + } + if (jointDepth(j) != 0) { newTracks.add(track); continue; } + Vector3f[] translations = tt.getTranslations(); + if (translations == null || translations.length == 0) { newTracks.add(track); continue; } + + // Ersten Frame als Ruheposition verwenden (verhindert Mesh-Sprünge) + float fx = translations[0].x; + float fy = translations[0].y; + + float maxDriftX = 0, maxDriftY = 0, maxDriftZ = 0; + for (Vector3f v : translations) { + maxDriftX = Math.max(maxDriftX, Math.abs(v.x - fx)); + maxDriftY = Math.max(maxDriftY, Math.abs(v.y - fy)); + maxDriftZ = Math.max(maxDriftZ, Math.abs(v.z - translations[0].z)); + } + log.info("[Strip] '{}' depth=0 driftX={} driftY={} driftZ(Höhe,unberührt)={}", + j.getName(), maxDriftX, maxDriftY, maxDriftZ); + + Vector3f[] stripped = new Vector3f[translations.length]; + for (int i = 0; i < translations.length; i++) { + // X und Y auf Frame-0 fixieren; Z (= Welt-Höhe) komplett frei lassen + stripped[i] = new Vector3f(fx, fy, translations[i].z); + } + newTracks.add(new TransformTrack(j, tt.getTimes(), stripped, tt.getRotations(), tt.getScales())); + log.info("[Strip] ✓ '{}' X+Y fixiert auf ({},{}), Z frei", j.getName(), fx, fy); + } + AnimClip result = new AnimClip(clip.getName()); + result.setTracks(newTracks.toArray(new AnimTrack[0])); + return result; + } + + private static int jointDepth(Joint j) { + int d = 0; + Joint p = j.getParent(); + while (p != null) { d++; p = p.getParent(); } + return d; + } }