Animations neu importiert, SLF4J-Format-Bugs gefixt, stripRootXZ als tote Methode für später
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -45,6 +45,7 @@ import java.nio.ByteBuffer;
|
|||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ public class AnimationLibrary extends BaseAppState {
|
|||||||
|
|
||||||
/** Loggt alle Tracks eines Clips: Bone-Name, hat Translation (T), Rotation (R), Scale (S). */
|
/** Loggt alle Tracks eines Clips: Bone-Name, hat Translation (T), Rotation (R), Scale (S). */
|
||||||
private void dumpClipTracks(com.jme3.anim.AnimClip clip) {
|
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);
|
clip.getName(), clip.getLength(), clip.getTracks().length);
|
||||||
int tracksWithTranslation = 0;
|
int tracksWithTranslation = 0;
|
||||||
for (com.jme3.anim.AnimTrack<?> t : clip.getTracks()) {
|
for (com.jme3.anim.AnimTrack<?> t : clip.getTracks()) {
|
||||||
@@ -272,7 +272,7 @@ public class AnimationLibrary extends BaseAppState {
|
|||||||
tracksWithTranslation++;
|
tracksWithTranslation++;
|
||||||
com.jme3.math.Vector3f t0 = tt.getTranslations()[0];
|
com.jme3.math.Vector3f t0 = tt.getTranslations()[0];
|
||||||
com.jme3.math.Vector3f tN = tt.getTranslations()[tt.getTranslations().length - 1];
|
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,
|
target, tt.getTranslations().length,
|
||||||
t0.x, t0.y, t0.z, tN.x, tN.y, tN.z, tN.y - t0.y);
|
t0.x, t0.y, t0.z, tN.x, tN.y, tN.z, tN.y - t0.y);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -451,4 +451,60 @@ public final class RetargetingSystem {
|
|||||||
}
|
}
|
||||||
return null;
|
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<AnimTrack<?>> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user