Root-Bone XZ in-memory einfrieren beim Clip-Apply (kein Drift mehr ingame)
Beim Anwenden eines Clips auf ein Modell (AnimationLibrary.applyTo) wird der Root-Joint-Track jetzt in-memory gepatcht: X und Z werden auf Frame-0-Wert eingefroren, Y (Höhenachse) bleibt vollständig frei. Damit bleibt das Mesh immer über der Physik-Kapsel, sit_down/Jump/Bounce laufen korrekt weiter. J3O-Dateien werden nicht verändert. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,8 @@ import com.jme3.scene.Spatial;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.jme3.math.Vector3f;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -115,6 +117,7 @@ public class AnimationLibrary extends BaseAppState {
|
||||
return false;
|
||||
}
|
||||
|
||||
target = snapRootBoneXZ(target, sc.getArmature());
|
||||
ac.addAnimClip(target);
|
||||
log.info("[AnimLib] Clip '{}' zu AnimComposer von '{}' hinzugefügt", clipName, model.getName());
|
||||
if (clipName.equals("sit_down")) {
|
||||
@@ -257,6 +260,46 @@ public class AnimationLibrary extends BaseAppState {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Friert X und Z des Root-Knochens (kein Eltern-Joint) auf den Wert von Frame 0 ein.
|
||||
* Y (Höhenachse, JME3 Y-Up) bleibt vollständig erhalten — sit_down / Jump / Bounce laufen korrekt.
|
||||
* Erstellt einen neuen in-memory-Clip; J3O-Dateien bleiben unverändert.
|
||||
*/
|
||||
private static AnimClip snapRootBoneXZ(AnimClip clip, Armature armature) {
|
||||
if (clip == null || armature == null) return clip;
|
||||
List<AnimTrack<?>> newTracks = new ArrayList<>();
|
||||
boolean modified = false;
|
||||
for (AnimTrack<?> track : clip.getTracks()) {
|
||||
if (!(track instanceof TransformTrack tt) || !(tt.getTarget() instanceof Joint j)) {
|
||||
newTracks.add(track);
|
||||
continue;
|
||||
}
|
||||
if (j.getParent() != null) {
|
||||
newTracks.add(track);
|
||||
continue;
|
||||
}
|
||||
Vector3f[] translations = tt.getTranslations();
|
||||
if (translations == null || translations.length == 0) {
|
||||
newTracks.add(track);
|
||||
continue;
|
||||
}
|
||||
float f0x = translations[0].x;
|
||||
float f0z = translations[0].z;
|
||||
Vector3f[] snapped = new Vector3f[translations.length];
|
||||
for (int i = 0; i < translations.length; i++) {
|
||||
snapped[i] = new Vector3f(f0x, translations[i].y, f0z);
|
||||
}
|
||||
newTracks.add(new TransformTrack(j, tt.getTimes(), snapped, tt.getRotations(), tt.getScales()));
|
||||
modified = true;
|
||||
log.debug("[AnimLib] '{}': Root-Joint '{}' XZ={},{} eingefroren, Y frei",
|
||||
clip.getName(), j.getName(), f0x, f0z);
|
||||
}
|
||||
if (!modified) return clip;
|
||||
AnimClip result = new AnimClip(clip.getName());
|
||||
result.setTracks(newTracks.toArray(new AnimTrack[0]));
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 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={}s tracks={}",
|
||||
|
||||
Reference in New Issue
Block a user