Attaching FPS hands with a gun to player node

I have FPS camera attach to a Player Node using CameraNode. that work find.
Now I have a model of Hands with a gun and I want to attach it to player node. But it doesn’t appear in front of the player. the player node has no geometry and just used by the character control and it has one child which is the camernode.

I do the following to attach the gun also to the player node.

[java]
Node gun = (Node) assiss.loadModel(…);
gun.scale (0.02f); // scale it because it to big
gun.translate(0.0f, 2, 5f);
playNode.attachChild(gun);
[/java]

but when I attach the model to the world it appear at the location i set.

[java]
Node gun = (Node) assiss.loadModel(…);
gun.scale (0.02f); // scale it because it to big
gun.translate(0.0f, 2f, 5f);
world.attachChild(gun);
[/java]

what I am doing wrong?

1 Like

Are you sure it is outside the near frusturm?

anyway the normal approach for this si to use a secondary viewport only for the view model of the weapons, to prevent clipping with the world.

1 Like

I personally used a cameranode for the camera and attached the gun to that. It has the added benefit of following it in all axes, you just set the position and boom.

I didn’t check the frustum and I haven’t change it, thus must be the default values 1…1000.
and as you see the local transformation for gun 0,2,5 which must be outside the frustum.

here is my code
[java]
package mygame;

import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.LoopMode;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.SceneGraphVisitor;
import com.jme3.scene.SceneGraphVisitorAdapter;
import com.jme3.scene.Spatial;
import com.jme3.scene.UserData;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.CameraControl;
import java.util.logging.Level;
import java.util.logging.Logger;
import mygame.newpackage.input.CameraRotateState;
import mygame.newpackage.input.DpadCharacterMotion;
import mygame.newpackage.input.InputHandler;

/**

  • Sample 3 - how to load an OBJ model, and OgreXML model, a material/texture,

  • or text.
    */
    public class Main extends SimpleApplication {

    private static final Logger logger = Logger.getLogger(Main.class.getName());
    private String mainCharacterName = “Jaime”;
    //camera
    boolean left = false, right = false, up = false, down = false;
    private BulletAppState bulletAppState;
    private RigidBodyControl landscape;
    private BetterCharacterControl player;

    public static void main(String[] args) {
    Main app = new Main();
    app.start();
    }
    private Node playerNode;
    private CameraNode camNode;
    private DpadCharacterMotion dbCharacterMotion = null;
    private InputHandler inputHandler = null;

    @Override
    public void simpleInitApp() {
    //cam.setFrustumPerspective(45, (float)cam.getWidth()/(float)cam.getHeight(), .01f, 100);
    bulletAppState = new BulletAppState();
    stateManager.attach(bulletAppState);

     Node world = (Node) assetManager.loadModel("Scenes/Scene.j3o");
            
     player = new BetterCharacterControl(1.5f, 3f, 30f);
     player.setJumpForce(new Vector3f(0, 300, 0));
     player.setGravity(new Vector3f(0, -10, 0));
     Node gun = (Node) assetManager.loadModel("Models/colt45/HUD.mesh.j3o");
     gun.scale(0.02f);
     Quaternion quat = new Quaternion();
     quat.lookAt(new Vector3f(0, 0, -1), Vector3f.UNIT_Y);
     gun.setLocalRotation(quat);
     gun.setLocalTranslation(new Vector3f(0, -1f, -5));
     AnimControl control = gun.getControl(AnimControl.class);
     AnimChannel channel = control.createChannel();
     channel.setAnim("Idle");
     channel.setLoopMode(LoopMode.Loop);
    
     Node gunNode = new Node("the gun");
     //gunNode.attachChild(gun);
     gun.addControl(new GunControl(gun));
    
     playerNode = new Node("the player");
     playerNode.setLocalTranslation(new Vector3f(0, 2, -20));
    
    
     //playerNode.attachChild(gun);
    
     // 4. Add the player control to the PhysicsSpace
     playerNode.addControl(player);
    
     rootNode.attachChild(world);
     rootNode.attachChild(playerNode);
     //rootNode.attachChild(gunNode);
     initCamera();
     camNode.attachChild(gun);
     dbCharacterMotion = new DpadCharacterMotion(player, playerNode);
     dbCharacterMotion.setCamera(cam);
     //dbCharacterMotion.setUseCameraRotation(true);
     stateManager.attach(dbCharacterMotion);
     inputHandler = new InputHandler();
     stateManager.attach(inputHandler);
     inputHandler.addInputActionListener(dbCharacterMotion);
    
     CameraRotateState cameraRotateState = new CameraRotateState(player, playerNode);
     stateManager.attach(cameraRotateState);
     inputHandler.addInputActionListener(cameraRotateState);
     //bulletAppState.getPhysicsSpace().add(landscape);
     createIndivMeshRigidBodies(bulletAppState.getPhysicsSpace(), world, 0, true);
     bulletAppState.getPhysicsSpace().add(player);
     gun.setCullHint(Spatial.CullHint.Never); // always drawn
    

    }

    /**

    • CameraNode depends on playerNode. The camera follows the player.
      */
      private void initCamera() {
      camNode = new CameraNode(“CamNode”, cam);
      camNode.setControlDir(CameraControl.ControlDirection.SpatialToCamera);
      camNode.setLocalTranslation(new Vector3f(0, 2, 0));
      Quaternion quat = new Quaternion();
      quat.lookAt(Vector3f.UNIT_Z, Vector3f.UNIT_Y);
      camNode.setLocalRotation(quat);
      playerNode.attachChild(camNode);
      camNode.setEnabled(true);
      flyCam.setEnabled(false);

    }

    public synchronized static void createIndivMeshRigidBodies(
    final PhysicsSpace physicsSpace, final Spatial spatial, final float mass,
    final boolean enableLogging) {

     SceneGraphVisitorAdapter v = new SceneGraphVisitorAdapter() {
         @Override
         public void visit(Node node) {
             // Skip creating rigid body of Nodes, only do the Geometries
             // Allows bullet to take advantage of broadphase
         }
    
         @Override
         public void visit(Geometry geometry) {
             Boolean bool = geometry.getUserData(UserData.JME_PHYSICSIGNORE);
             if (bool != null && bool.booleanValue()) {
                 logger.log(Level.INFO, "rigid body skipped for {0}", geometry.getName());
                 return;
             }
    
             CollisionShape colShape;
             if (mass > 0) {
                 colShape = CollisionShapeFactory.createDynamicMeshShape(geometry);
             } else {
                 colShape = CollisionShapeFactory.createMeshShape(geometry);
             }
    
             RigidBodyControl rigidBodyControl = new RigidBodyControl(colShape, mass);
             geometry.addControl(rigidBodyControl);
             physicsSpace.add(rigidBodyControl);
             logger.log(Level.INFO, "Added rigid body to {0}", geometry.getName());
             logger.log(Level.INFO, "Created Physics Control: {0}, in PhysicsSpace: {1}",
                     new Object[]{rigidBodyControl, physicsSpace});
         }
     };
    

// spatial.breadthFirstTraversal(v);
spatial.depthFirstTraversal(v);
}

private class GunControl extends AbstractControl {

    private final Node gun;

    private GunControl(Node gun) {
        this.gun = gun;
    }

    @Override
    protected void controlUpdate(float tpf) {
        
        logger.log(Level.INFO, "player node: {0}", gun.getWorldTranslation());

// final Vector3f clone = playerNode.getWorldTranslation().clone();
// Quaternion rotation = playerNode.getLocalRotation().clone();
// // Location:
// Vector3f vecDiff = playerNode.getWorldTranslation().subtract(spatial.getWorldTranslation());
// logger.log(Level.INFO, “gun node diff: {0}”, vecDiff);
// spatial.setLocalTranslation(spatial.getLocalTranslation().addLocal(vecDiff));
// logger.log(Level.INFO, “spatial node: {0}”, spatial.getWorldTranslation());
// // Rotation:
// Quaternion worldDiff = playerNode.getWorldRotation().subtract(spatial.getWorldRotation());
// spatial.setLocalRotation(spatial.getLocalRotation().addLocal(worldDiff));
}

    @Override
    protected void controlRender(RenderManager rm, ViewPort vp) {
        // do nothing
    }
}

}

[/java]

when I attach the gun to camera node and it will not be displayed. but if attach it to world it got displayed.

please note that code is just for debugging thus look ugly :S

gun.setLocalTranslation(new Vector3f(0, -1f, -5));

…looks like the gun is 5 units behind and one unit below the camera. I wouldn’t expect it to be visible.

I tried a lot of translation. for example

gun.setLocalTranslation(new Vector3f(0, 0f, 5));
or
gun.setLocalTranslation(new Vector3f(0, 0f, 15));
or
gun.setLocalTranslation(new Vector3f(0, 1f, 5));

but no effect

I will try today another tactic by attaching a box to and see if it is appear and also may a line from the center of gun to see where is it’s location

You could also add some debug printlns (or set a breakpoint) to dump the current world location of the gun every frame or so. Assuming the box doesn’t show up.