Translate joint imported from skinned mesh

Hi friends,
I’d like to programmatically adjust the translation of a joint on a skinned mesh imported in gltf format. I can get the joint as a Spatial correctly. But no effect shown after I modify localTranslation on the spatial/joint.
I 've tried calling updateGeometricState() on my node. Didn’t seem to work.
My question is, is it allowed to translate imported joint on a skinned mesh while keeping the skin deformation? If so, what am I missing?

I 'm not using the GUI of JME, just SDK.
Any suggestion is appreciated!

Have you tried these on Joint:

And this is unclear to me, a Joint is not a Spatial so do not know what you mean by this. Maybe you are referring to joint attachment node?

Yes. The joint I see is an attachment joint.
May I ask what’s attachment joint? Apologies that it is the first time I dive into jme with skin weights + joints.
Does it still maintain the skinweight on the imported model?
How can I deform my model from joint translation?

If you attach a model into a joint’s attachment node the model will follow the joint movement. For example when you attach a sword model into the player’s hand joint attachment node, the sword will follow the hand movement.

That’s how animation works. A joint is like a bone if you transform the bone the part of the model skinned to that bone will also move.

After your explanation, I don’t think an attachment joint is intentionally created by me, or needed. My follow up question is
why is my joint converted to attachment joint? I just want my joint hierarchy the same and keep the skinweight data I had from the gltf model.

How can I deform my model from joint translation?

I 've used Unity before. What I would do in Unity is to change the localTranslation on a joint. and the skinned mesh will deform. I did the same in jME, but nothing happened on my model.
So I 'd like to learn about what I’m missing for jME. For example, is there a class needed that I should attach to my model node that handles skin deformation?

I know it is a basic feature in animation world, but for some reason I couldn’t find the missing puzzle…
Thank you Ali_RS for your help and patience!

Can you post your code?

val renderable = loadModelFromGltf(MODEL_PATH)
val node = Node("CarNode")
node.attachChild(renderable)    
(node.getChild(0) as Node).getChild("front_jnt_attachnode")?.run {
        this.localTranslation= Vector3f(10f, 10f, 10f)
        this.localRotation = Quaternion().fromAngles(0f, 0f, 90f)
}

Btw, the code is in Kotlin not Java, hope it 's not too confusing.

My intention is to translate front_jnt end_jnt to adjust the car length.


Selected joint is front_jnt

This is the hierarchy I have in Maya:
image
The gltf model has the same hierarchy.
front_jnt and end_jnt carry the skinweight.
front_jnt_end and end_jnt_end are added leaf joints. In case jme trim them, no impact on my model skinweights. (I tried a version where I didn’t have these two leaf joints in my model, jme trimmed 2 more joints and left me root only lol)

The hierarchy I see in engine:


It looks like front_jnt and end_jnt are converted / replaced by attachment joints. and they are parented under “CarNode” which is a Node I use to wrap the gltf model.
Now I suspect it is the reason why my model won’t deform, since front_jnt and end_jnt are the joints that carry the skinweights and they don’t exist any more.

Hope it clarifies a bit more.
(Sorry I can only upload one picture in one post as a super new user.)

In JME you should do it like this

SkinningControl sc = findAnimRoot(carModel).getControl(SkinningControl.class);
Joint front_jnt = sc.getArmature().getJoint("front_jnt");
Joint end_jnt = sc.getArmature().getJoint("end_jnt");

front_jnt.setLocalTransform(...);
end_jnt.setLocalTransform(...);


protected Spatial findAnimRoot(Spatial s) {
    if (s.getControl(SkinningControl.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;
}

You need to get SkinningControl from model and get desired joint, then you can modify joint transform.

1 Like

Thanks for the direction and code snippet. I will try it and post the results!

1 Like

To better understand how jme works, I’ve tried importing several versions of car model bound to slightly different joint chains, such as with root joint and without root joint; with leaf joint and without leaf joint, etc.
However, after checking in engine, I failed draw conclusions on when jme will

  • replace my joints with attachment joint
  • trim my leaf joints (they don’t seem to be trimmed every time)

As a result, I haven’t been successful at getting the skinningControl component.

My car model is skinned to at least 2 joints : front_jnt and end_jnt
Either of these 2 joints has 100% skinweight on half of the vertices.
My goal is to keep these two joints and the skinweight.

Is there a standard for jme when it comes to construct joint hierarchy?

What version of JME are you using? JME 3.3 or 3.2?

Edit: if you are on JME 3.2 then you should try looking for SkeletonControl instead.

Bone front_jnt = skeletonControl.getSkeleton().getBone("front_jnt");

It does not, those attachment nodes are not a “Joint” and they are not what you are looking for. In JME joints are not a Spatial so not visible in the scene hierarchy. The only way to get a joint in JME is to use either SkeletonControl or SkinningControl .

Please correct me if my understanding is wrong.
Attachment joints are purely sockets for other models to be attached to. and they are generated for each joint imported.

In that case, I think my problem is jme didn’t find skinningControl on my model.
jme didn’t report errors loading the model. I double checked the gltf model by importing it back to a gltf viewer(three.js) and it is skinned.
Do you happen to have any suggestions for debugging skinningControl? :sweat_smile:

Right

Yes, but you first need to answer my question so I can help.

Also, I can not comment until I see the code.

1 Like