Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Animation retarget: add support for root-bone translations #1

Open
Ali-RS opened this issue Nov 9, 2019 · 6 comments
Open

Animation retarget: add support for root-bone translations #1

Ali-RS opened this issue Nov 9, 2019 · 6 comments

Comments

@Ali-RS
Copy link

Ali-RS commented Nov 9, 2019

Tried to retarget an AnimClip from one model to another, seems it only retargets bone rotations (makes an in-place animation) and does not have support for root motion export.
While in-place animation might be what one needs most of the time, but yet sometimes we might need to have the root motion also. It will be nice to add support for this as well.

@stephengold
Copy link
Owner

stephengold commented Dec 9, 2019

The main difficulty I see is that different models place the root bone differently. For instance, Jaime's root bone is between his feet, while Sinbad's is in his belly. Also, translation introduces the issue of models built at different scales (meter units versus centimeter units, for instance.) For these reasons and others, I think root translation should be handled separately from rotations.

The Maud editor includes support for translating models so that their feet touch the ground without sliding. I believe the relevant code could be added to Wes. Would that serve your need?

@Ali-RS
Copy link
Author

Ali-RS commented Dec 9, 2019

I calculate target track translation by finding delta translation from the source track ( delta translation = source track translation - source joint bind translation) and add it to target joint bind translation. This works fine for me but not sure if it will fit into all cases.

Here is simplified version of my anim retarget script:

AnimClip retargetClip(AnimClip sourceClip, Spatial target) {
    Spatial animRoot = getAnimRoot(target);
    if (animRoot == null) {
        return null;
    }

    SkinningControl sc = animRoot.getControl(SkinningControl.class);
    sc.getArmature().applyBindPose();
    sc.getArmature().saveInitialPose();

    SafeArrayList<AnimTrack> tracks = new SafeArrayList<>(AnimTrack.class);
    for (AnimTrack animTrack : sourceClip.getTracks()) {
        if (animTrack instanceof TransformTrack) {
            TransformTrack sourceTrack = (TransformTrack) animTrack;
            Joint sourceJoint = 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) {
                println "Joint with name " + sourceJoint.getName() + " not fount on target";
                continue;
            }

            // Rotations and Scales are cloned without change
            TransformTrack targetTrack = sourceTrack.jmeClone();
            targetTrack.setTarget(targetJoint);

            // Modify translations to fit in target rig
            if (sourceTrack.getTranslations() != null) {
                Vector3f[] translations = new Vector3f[sourceTrack.getTimes().length];
           
                for (int i = 0; i < sourceTrack.getTranslations().length; i++) {
                    // delta translation = track translation - bind translation
                    Vector3f deltaTranslation = sourceTrack.getTranslations()[i].subtract(sourceJoint.getLocalTranslation());
           
                    Vector3f targetTranslation = new Vector3f(targetJoint.getInitialTransform().getTranslation());
                    targetTranslation.addLocal(deltaTranslation);
                    translations[i] = targetTranslation;
                }
                targetTrack.setKeyframesTranslation(translations);
            }
            tracks.add(targetTrack);
        }
    }

    AnimClip targetClip = new AnimClip(sourceClip.getName());
    targetClip.setTracks(tracks.getArray());
    return targetClip;
}

@stephengold
Copy link
Owner

Is there anything that should be added to the Wes library to support your solution?

@Ali-RS
Copy link
Author

Ali-RS commented Dec 11, 2019

Nothing needed ATM, I need to thoroughly test my solution for different scenarios. I will let you know the outcome.

@stephengold stephengold changed the title Animation retarget: Add supports for root motion export Animation retarget: add support for root-bone translations Apr 2, 2020
@stephengold
Copy link
Owner

@Ali-RS Any news?

@Ali-RS
Copy link
Author

Ali-RS commented Apr 2, 2020

Really sorry, no progress on this yet. I do not think I can come back to this anytime soon. Please feel free to close this if you want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants