Usually there are multiple AnimComposer animations in a single J3O file, and usually I just need to use
control =model1.getChild(0).getControl(AnimComposer.class);
control.setCurrentAction("Walk");
control.setGlobalSpeed(0.5f);
I can play it.
But now I have a problem
I now have many J3o files with animations, how do I load the animations in multiple J3o files and play the animations correctly.
Maybe there is something wrong with me , I need to get the animation of both files to load and play. I can load one file correctly but not both files at the same time.
There isn’t anything wrong with you haha- Yes so your walk just has an animation and then your stand has those two animation clips, both prolly the same one?
Let me clarify, however
Are you wanting to have one file with multiple animations?
Or do you want multiple files and be able to play an animation off each one?
If option two can you give the game context or gaming goal that you are after? for example are you trying to animate two different npcs?
By the way, in the code snippet, I posted on that topic, the “convert to in-place” part is dirty code. Better to use the function I posted here which is also integrated into the Wes library.
Edit:
Here it is updated to use the new “in-place animation” method:
Note that you must rename “root.x” to the root bone name on your model. In my case, I am using Auto Rig Pro addon to rig all my characters and the root bone name is “root.x” that is why I have hardcoded it in code.
import com.jme3.anim.*;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.util.SafeArrayList;
/**
* @author Ali-RS
*/
public class AnimUtils {
public static SkinningControl findSkinningControl(Spatial model) {
Spatial s = getAnimRoot(model);
SkinningControl ac = s == null ? null : s.getControl(SkinningControl.class);
return ac;
}
public static AnimComposer findAnimComposer(Spatial model) {
Spatial s = getAnimRoot(model);
AnimComposer ac = s == null ? null : s.getControl(AnimComposer.class);
return ac;
}
protected static Spatial getAnimRoot(Spatial model) {
// Find spatial with the composer
// For the moment, we'll guess
// Spatial animRoot = ((Node) model).getChild("root");
// if (animRoot == null) {
// // Have to find it the hard way
// animRoot = findAnimRoot(model);
// }
return findAnimRoot(model);
}
protected static Spatial findAnimRoot(Spatial s) {
if (s.getControl(AnimComposer.class) != null) {
return s;
}
if (s instanceof Node) {
for (Spatial child : ((Node) s).getChildren()) {
Spatial result = findAnimRoot(child);
if (result != null) {
return result;
}
}
}
return null;
}
public static AnimClip retargetClip(AnimClip sourceClip, Spatial target, boolean inPlace, String newClipName) {
Spatial animRoot = getAnimRoot(target);
if (animRoot == null) {
System.err.println("Anim root is null!");
return null;
}
SkinningControl sc = animRoot.getControl(SkinningControl.class);
if (target.getUserData("hasInitialPose") == null) {
sc.getArmature().applyBindPose();
sc.getArmature().saveInitialPose();
target.setUserData("hasInitialPose", Boolean.TRUE);
}
SafeArrayList<AnimTrack> tracks = new SafeArrayList<>(AnimTrack.class);
for (AnimTrack animTrack : sourceClip.getTracks()) {
if (animTrack instanceof TransformTrack) {
TransformTrack sourceTrack = (TransformTrack) animTrack;
Joint sourceJoint = (Joint) sourceTrack.getTarget();
// I am using a standard humanoid rig for all my characters so joint
// names are the same on all rigs
Joint targetJoint = sc.getArmature().getJoint(sourceJoint.getName());
if (targetJoint == null) {
System.err.println( "Joint with name " + sourceJoint.getName() + " not fount on target");
continue;
}
// Only Rotations are cloned
TransformTrack targetTrack = new TransformTrack(targetJoint, sourceTrack.getTimes(), null, sourceTrack.getRotations(), null);//sourceTrack.jmeClone();
targetTrack.setTarget(targetJoint);
if (targetJoint.getName().equals("root.x")) {
System.out.println("Transferring root motion...");
// Modify translations to fit in target rig
if (sourceTrack.getTranslations() != null) {
Vector3f[] translations = new Vector3f[sourceTrack.getTimes().length];
//boolean convertToInPlace = false;
/*Vector3f start = new Vector3f(sourceTrack.getTranslations()[0]);
Vector3f end = new Vector3f(sourceTrack.getTranslations()[sourceTrack.getTranslations().length - 1]);
start.y = 0;
end.y = 0;
if (start.distance(end) > 0.30f) {
convertToInPlace = true;
System.out.println("Converting to InPlace:" + sourceClip.getName());
}*/
float scale = targetJoint.getInitialTransform().getTranslation().getY() / sourceJoint.getInitialTransform().getTranslation().getY();
System.out.println("Scale factor= " + scale);
for (int i = 0; i < sourceTrack.getTranslations().length; i++) {
// delta translation = track translation - bind translation
Vector3f deltaTranslation = sourceTrack.getTranslations()[i].subtract(sourceJoint.getLocalTranslation());
deltaTranslation.multLocal(scale);
/*if (convertToInPlace) {
deltaTranslation.x = 0f;
deltaTranslation.z = 0f;
}*/
Vector3f targetTranslation = new Vector3f(targetJoint.getInitialTransform().getTranslation());
targetTranslation.addLocal(deltaTranslation);
translations[i] = targetTranslation;
}
if (inPlace) {
convertToInPlace(translations);
}
targetTrack.setKeyframesTranslation(translations);
}
}
tracks.add(targetTrack);
}
}
AnimClip targetClip = new AnimClip(newClipName);
targetClip.setTracks(tracks.getArray());
return targetClip;
}
private static void convertToInPlace(Vector3f[] translations) {
Vector3f start = translations[0];
Vector3f end = translations[translations.length - 1];
Vector3f delta = end.subtract(start);
Vector3f factor = delta.divide(translations.length - 1);
Vector3f vTemp = new Vector3f();
for (int index = 0; index < translations.length; index++) {
Vector3f translation = translations[index];
vTemp.set(factor).multLocal(index);
translation.subtractLocal(vTemp);
}
}
}
I added the “Walk” animation to the “Stand” and made the model very small and I tried to scale it and it didn’t show up properly
The “Stand” animation will be normal, so if I load “Stand” first and then play “Walk” then it will be normal https://youtu.be/srr-pHL_xbQ
As shown in the video, the “Walk” model I loaded first appeared very small
Using Wes for the first time
Could you give me a hint SkeletonMapping mapWhat value should map be passed in?
Or where the SkeletonMapping came from?
Sorry to trouble you Reading the comments in the code I know that I should need the new SkeletonMapping but I don't know how I should create this object No documentation found in GitHub
You need it to tell which bone from the source armature should be mapped to which bone on the target armature by specifying the joint names. In your case because they are using the same skeleton then the source and target joint names are the same so you can do something like this:
When donuts and pspeed helped me equip a weapon donuts shared that when you attach a weapon to a hand it almost always shrinks unless everything has a local scale of 1. Might not be helpful at at but perhaps you could look into the scales of all these different pieces and for example try increasing the scale of the Walk file. Or what did you do to try to increase its scale?