If you decide to use the control to keep the spatial updated then yes you need to keep track of the bone translation and rotation. You would have to pass the bone as an argument in the control’s constructor.
If you use the attachment node, you don’t need to keep track.
The reason why it says in that thread to use a control is because using an attachment node is kinda buggy when hardware skinning is enabled. You can always use software skinning instead but you lose some performance gain.
I want to use a control to attach a gun to a person’s hand but I guess I’m doing it wrong because when the person jumps, the gun doesn’t exactly move with the bone of the hand. I use the world translation of the bone’s attachment node.
The reason that other thread had to match things up with a control was because the attached thing was animated. That confuses the animation system to have one skeleton control for the whole hierarchy.
If the thing you are attaching isn’t skeleton animated then you shouldn’t need to worry about that. Just attach the gun to the attachment node like everyone else does.
Isn’t this the same as simply setting the local translation and rotation of the gun to be that of the attachment node? Because either way if I move the mesh to which I attach another spatial, the child spatial appears to be behind.
Well, I can’t see where you are doing that as you haven’t shown the code for your control.
I only see where you are doing weird stuff like: control.setBonePos(meshRigControl.getAttachmentsNode(“handIK.R”).getWorldTranslation()); control.setBoneRot(meshRigControl.getAttachmentsNode(“handIK.R”).getWorldRotation());
…which is very strange. Like, I don’t know why you don’t just set the node instead of praying that those Vector3f/Quaternion instances don’t change underneath you. Very bad practice to save these and rely on them when you can just grab them again any time from the node itself.
But anyway, you may be becoming victim to update ordering issues. Now is the time where some debugging will come into play. Either step through the code or put some printlns in to see what order things are running. That’s why I suggested doing the position update on controlRender() instead of controlUpdate().
Hello @domas
If you want to attach a gun to the players hand, I recommend to create an “attachmentBone” for your model in blender. All you have to do is open your model in Blender, select a bone near the hand and press e to extract a bone. It neither matters in which direction the bone is stretched nor how long it is. Now, rename that bone to something like “AttachmentBone”. Lastly export your model with ogre, convert it and attach your weapon to that new bone.
I made it this way and it worked perfectly. The problem when you attach the gun directly to the hand bone for example might be that the gun for different animations appears at different locations. If you have one bone which local transform is not changed by animations you can be sure the gun appears at the same location for all animations.
Hopefully I could help you!
Ups, I have overlooked that. No, the weapon wasn’t animated.
Is it possible to create a control which refreshes translation, rotation, scale of the gun by getting the transformation via “AttachmentBone”. The gun would not be attached to “AttachmentNode” then. It should be attached to root node or so.
Hey @domas, I quickly wrote a test app for you. It just shall show you how to place your gun to the players hand. It might be that you have to adjust your gun with an extra node, so that the gun fits perfectly into the hands.
Here the TestApp:
public class Main extends SimpleApplication {
public static void main(String[] args) throws IOException {
Main app = new Main();
app.start();
}
@Override
public void simpleInitApp() {
cam.setLocation(Vector3f.UNIT_Z);
Spatial player = assetManager.loadModel("Models/Player/Player.j3o");
rootNode.attachChild(player);
AnimControl animControl = player.getControl(AnimControl.class);
AnimChannel channel = animControl.createChannel();
Collection<String> anims = animControl.getAnimationNames();
Iterator i = anims.iterator();
channel.setAnim((String) i.next());
animControl.addListener(new AnimEventListener() {
@Override
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
if (i.hasNext()) {
channel.setAnim((String) i.next());
}
}
@Override
public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {}
});
SkeletonControl skeletonControl = player.getControl(SkeletonControl.class);
Bone attachmentBone = skeletonControl.getSkeleton().getBone("YOUR_ATTACHMENT_BONE");
WeaponAttachmentControl control = new WeaponAttachmentControl(skeletonControl, attachmentBone.getName());
Spatial gun = assetManager.loadModel("Models/cube.j3o");
gun.scale(0.1f);
gun.addControl(control);
rootNode.attachChild(gun);
AmbientLight ambient = new AmbientLight();
ambient.setColor(ColorRGBA.White);
rootNode.addLight(ambient);
}
@Override
public void simpleUpdate(float tpf) {
}
@Override
public void simpleRender(RenderManager rm) {
}
}
Here the simple control:
public class WeaponAttachmentControl extends AbstractControl {
private final Node attachmentNode;
public WeaponAttachmentControl(Node attachmentNode) {
this.attachmentNode = attachmentNode;
}
public WeaponAttachmentControl(SkeletonControl skeletonControl, String bone) {
if (skeletonControl != null && bone != null) {
attachmentNode = skeletonControl.getAttachmentsNode(bone);
} else {
attachmentNode = null;
}
}
@Override
protected void controlUpdate(float tpf) {
if (spatial == null || attachmentNode == null) {
return;
}
spatial.setLocalTranslation(attachmentNode.getWorldTranslation());
spatial.setLocalRotation(attachmentNode.getWorldRotation());
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
}
If I were you, I would create several controls, one for keeping the gun at the correct position, one to take care of animations, and so on …
It should be no problem to execute animations of the gun anymore.
If you are missing something, feel free to tell us.