Mixamo animated character + physic resulting error [SOLVED]

Firstly, this is what I found: if I export model as .fbx to mixamo and import it to blender and export it as .xbuf the model will be broken on jME. But if I export it as .obj to mixamo the model will be fine. Needs to gnerated material after converting to .j3o (on SDK) and add texture. The animation works fine.

However it’s resulting error when I try with TestWalkingCharacter (with animation). The error (on window) is like this:

Uncaught exception thrown in Thread[jME3 Main,5,main]
NullPointerException

I modify TestWalkingCharacter like this:



/**
 * A walking animated character followed by a 3rd person camera on a terrain with LOD.
 * @author normenhansen
 */
public class CharWalk extends SimpleApplication implements ActionListener, AnimEventListener {

    private BulletAppState bulletAppState;
    //character
    CharacterControl character;
    Node model;
    //temp vectors
    Vector3f walkDirection = new Vector3f();
    //terrain
    TerrainQuad terrain;
    RigidBodyControl terrainPhysicsNode;
    //Materials
    Material matRock;
    Material matBullet;
    //animation
    AnimChannel animationChannel;
    AnimChannel shootingChannel;
    AnimControl animationControl;
    float airTime = 0;
    //camera
    boolean left = false, right = false, up = false, down = false;
    ChaseCamera chaseCam;
    //bullet
    Sphere bullet;
    SphereCollisionShape bulletCollisionShape;
    //explosion
    ParticleEmitter effect;
    //brick wall
    Box brick;
    float bLength = 0.8f;
    float bWidth = 0.4f;
    float bHeight = 0.4f;
    FilterPostProcessor fpp;

    public static void main(String[] args) {
        CharWalk app = new CharWalk();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        bulletAppState = new BulletAppState();
        bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
        stateManager.attach(bulletAppState);
        setupKeys();

        createLight();
        createSky();
        createTerrain();

        createCharacter();
        setupChaseCamera();
        setupAnimationController();
        setupFilter();
    }

    private void setupFilter() {
        FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
        BloomFilter bloom = new BloomFilter(BloomFilter.GlowMode.Objects);
        fpp.addFilter(bloom);
        viewPort.addProcessor(fpp);
    }

    private PhysicsSpace getPhysicsSpace() {
        return bulletAppState.getPhysicsSpace();
    }

    private void setupKeys() {
        inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T));
        inputManager.addListener(this, "wireframe");
        inputManager.addMapping("CharLeft", new KeyTrigger(KeyInput.KEY_A));
        inputManager.addMapping("CharRight", new KeyTrigger(KeyInput.KEY_D));
        inputManager.addMapping("CharUp", new KeyTrigger(KeyInput.KEY_W));
        inputManager.addMapping("CharDown", new KeyTrigger(KeyInput.KEY_S));
        inputManager.addMapping("CharSpace", new KeyTrigger(KeyInput.KEY_RETURN));
        inputManager.addMapping("CharShoot", new KeyTrigger(KeyInput.KEY_SPACE));
        inputManager.addListener(this, "CharLeft");
        inputManager.addListener(this, "CharRight");
        inputManager.addListener(this, "CharUp");
        inputManager.addListener(this, "CharDown");
        inputManager.addListener(this, "CharSpace");
        inputManager.addListener(this, "CharShoot");
    }

    private void createLight() {
        Vector3f direction = new Vector3f(-0.1f, -0.7f, -1).normalizeLocal();
        DirectionalLight dl = new DirectionalLight();
        dl.setDirection(direction);
        dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
        rootNode.addLight(dl);
    }

    private void createSky() {
        rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false));
    }

    private void createTerrain() {
        matRock = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
        matRock.setBoolean("useTriPlanarMapping", false);
        matRock.setBoolean("WardIso", true);
        matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));
        Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/island512.png");
        Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
        grass.setWrap(WrapMode.Repeat);
        matRock.setTexture("DiffuseMap", grass);
        matRock.setFloat("DiffuseMap_0_scale", 64);
        Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/snow.jpg");
        dirt.setWrap(WrapMode.Repeat);
        matRock.setTexture("DiffuseMap_1", dirt);
        matRock.setFloat("DiffuseMap_1_scale", 16);
        Texture rock = assetManager.loadTexture("Textures/Terrain/splat/sand.jpg");
        rock.setWrap(WrapMode.Repeat);
        matRock.setTexture("DiffuseMap_2", rock);
        matRock.setFloat("DiffuseMap_2_scale", 128);
        Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/normal.jpg");
        normalMap0.setWrap(WrapMode.Repeat);
        Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/normal.png");
        normalMap1.setWrap(WrapMode.Repeat);
        Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/normal.png");
        normalMap2.setWrap(WrapMode.Repeat);
        matRock.setTexture("NormalMap", normalMap0);
        matRock.setTexture("NormalMap_1", normalMap2);
        matRock.setTexture("NormalMap_2", normalMap2);

        AbstractHeightMap heightmap = null;
        try {
            heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f);
            heightmap.load();

        } catch (Exception e) {
            e.printStackTrace();
        }

        terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());
        List<Camera> cameras = new ArrayList<Camera>();
        cameras.add(getCamera());
        TerrainLodControl control = new TerrainLodControl(terrain, cameras);
        terrain.addControl(control);
        terrain.setMaterial(matRock);
        terrain.setLocalScale(new Vector3f(2, 2, 2));

        terrainPhysicsNode = new RigidBodyControl(CollisionShapeFactory.createMeshShape(terrain), 0);
        terrain.addControl(terrainPhysicsNode);
        rootNode.attachChild(terrain);
        getPhysicsSpace().add(terrainPhysicsNode);
    }

    private void createCharacter() {
        CapsuleCollisionShape capsule = new CapsuleCollisionShape(3f, 4f);
        character = new CharacterControl(capsule, 0.01f);
        model = (Node) assetManager.loadModel("Models/erika/erika.j3o");
        //model.setLocalScale(0.5f);
        model.addControl(character);
        character.setPhysicsLocation(new Vector3f(-140, 40, -10));
        rootNode.attachChild(model);
        getPhysicsSpace().add(character);
    }

    private void setupChaseCamera() {
        flyCam.setEnabled(false);
        chaseCam = new ChaseCamera(cam, model, inputManager);
    }

    private void setupAnimationController() {
        animationControl = model.getControl(AnimControl.class);
        animationControl.addListener(this);
        animationChannel = animationControl.createChannel();
//        shootingChannel = animationControl.createChannel();
//        shootingChannel.addBone(animationControl.getSkeleton().getBone("uparm.right"));
//       shootingChannel.addBone(animationControl.getSkeleton().getBone("arm.right"));
//        shootingChannel.addBone(animationControl.getSkeleton().getBone("hand.right"));
    }

    @Override
    public void simpleUpdate(float tpf) {
        Vector3f camDir = cam.getDirection().clone().multLocal(0.1f);
        Vector3f camLeft = cam.getLeft().clone().multLocal(0.1f);
        camDir.y = 0;
        camLeft.y = 0;
        walkDirection.set(0, 0, 0);
        if (left) {
            walkDirection.addLocal(camLeft);
        }
        if (right) {
            walkDirection.addLocal(camLeft.negate());
        }
        if (up) {
            walkDirection.addLocal(camDir);
        }
        if (down) {
            walkDirection.addLocal(camDir.negate());
        }
        if (!character.onGround()) {
            airTime = airTime + tpf;
        } else {
            airTime = 0;
        }
        if (walkDirection.length() == 0) {
            if (!"idle".equals(animationChannel.getAnimationName())) {
                animationChannel.setAnim("idle", 1f);
            }
        } else {
            character.setViewDirection(walkDirection);
            if (airTime > .3f) {
                if (!"idle".equals(animationChannel.getAnimationName())) {
                    animationChannel.setAnim("idle");
                }
            } else if (!"Walk".equals(animationChannel.getAnimationName())) {
                animationChannel.setAnim("Walk", 0.7f);
            }
        }
        character.setWalkDirection(walkDirection);
    }

    public void onAction(String binding, boolean value, float tpf) {
        if (binding.equals("CharLeft")) {
            if (value) {
                left = true;
            } else {
                left = false;
            }
        } else if (binding.equals("CharRight")) {
            if (value) {
                right = true;
            } else {
                right = false;
            }
        } else if (binding.equals("CharUp")) {
            if (value) {
                up = true;
            } else {
                up = false;
            }
        } else if (binding.equals("CharDown")) {
            if (value) {
                down = true;
            } else {
                down = false;
            }
        } else if (binding.equals("CharSpace")) {
            character.jump();
//        } else if (binding.equals("CharShoot") && !value) {
//            bulletControl();
        }
    }




    public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
        if (channel == shootingChannel) {
            channel.setAnim("idle");
        }
    }

    public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
    }
}

It works if I don’t use animation. but looks like this:

I modify TestWalkingCharacter like this:



/**
 * A walking animated character followed by a 3rd person camera on a terrain with LOD.
 * @author normenhansen
 */
public class CharacterWalk extends SimpleApplication implements ActionListener {

    private BulletAppState bulletAppState;
    //character
    CharacterControl character;
    Node model;
    //temp vectors
    Vector3f walkDirection = new Vector3f();
    //terrain
    TerrainQuad terrain;
    RigidBodyControl terrainPhysicsNode;
    //Materials
    Material matRock;
    Material matBullet;
    //animation
    AnimChannel animationChannel;
    AnimChannel shootingChannel;
    AnimControl animationControl;
    float airTime = 0;
    //camera
    boolean left = false, right = false, up = false, down = false;
    ChaseCamera chaseCam;


    public static void main(String[] args) {
        CharacterWalk app = new CharacterWalk();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        bulletAppState = new BulletAppState();
        bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
        stateManager.attach(bulletAppState);
        bulletAppState.setDebugEnabled(true);    
        setupKeys();

        createLight();
        createSky();
        createTerrain();

        createCharacter();
        setupChaseCamera();
    //    setupAnimationController();
    //    setupFilter();
    }


    private PhysicsSpace getPhysicsSpace() {
        return bulletAppState.getPhysicsSpace();
    }

    private void setupKeys() {
        inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T));
        inputManager.addListener(this, "wireframe");
        inputManager.addMapping("CharLeft", new KeyTrigger(KeyInput.KEY_A));
        inputManager.addMapping("CharRight", new KeyTrigger(KeyInput.KEY_D));
        inputManager.addMapping("CharUp", new KeyTrigger(KeyInput.KEY_W));
        inputManager.addMapping("CharDown", new KeyTrigger(KeyInput.KEY_S));
        inputManager.addMapping("CharSpace", new KeyTrigger(KeyInput.KEY_SPACE));
        inputManager.addMapping("CharShoot", new KeyTrigger(KeyInput.KEY_X));
        inputManager.addListener(this, "CharLeft");
        inputManager.addListener(this, "CharRight");
        inputManager.addListener(this, "CharUp");
        inputManager.addListener(this, "CharDown");
        inputManager.addListener(this, "CharSpace");
        inputManager.addListener(this, "CharShoot");
    }

    private void createLight() {
        Vector3f direction = new Vector3f(-0.1f, -0.7f, -1).normalizeLocal();
        DirectionalLight dl = new DirectionalLight();
        dl.setDirection(direction);
        dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
        rootNode.addLight(dl);
    }

    private void createSky() {
		Texture west = assetManager.loadTexture("Textures/Sky/sky2/slice_1_0.jpg");
		Texture east = assetManager.loadTexture("Textures/Sky/sky2/slice_1_2.jpg");
		Texture north = assetManager.loadTexture("Textures/Sky/sky2/slice_1_1.jpg");
		Texture south = assetManager.loadTexture("Textures/Sky/sky2/slice_1_3.jpg");
		Texture up = assetManager.loadTexture("Textures/Sky/sky2/top_bottom.jpg");
		Texture down = assetManager.loadTexture("Textures/Sky/sky2/top_bottom.jpg");

    Spatial sky = SkyFactory.createSky(assetManager, west, east, north, south, up, down);
	rootNode.attachChild(sky);
    }

    private void createTerrain() {
        matRock = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
        matRock.setBoolean("useTriPlanarMapping", false);
        matRock.setBoolean("WardIso", true);
        matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));
        Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/island512.png");
        Texture grass = assetManager.loadTexture("Textures/Terrain/splat/snow.jpg");
        grass.setWrap(WrapMode.Repeat);
        matRock.setTexture("DiffuseMap", grass);
        matRock.setFloat("DiffuseMap_0_scale", 64);
        Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
        dirt.setWrap(WrapMode.Repeat);
        matRock.setTexture("DiffuseMap_1", dirt);
        matRock.setFloat("DiffuseMap_1_scale", 16);
        Texture rock = assetManager.loadTexture("Textures/Terrain/splat/sand.jpg");
        rock.setWrap(WrapMode.Repeat);
        matRock.setTexture("DiffuseMap_2", rock);
        matRock.setFloat("DiffuseMap_2_scale", 128);
        Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/normal.jpg");
        normalMap0.setWrap(WrapMode.Repeat);
        Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/normal.png");
        normalMap1.setWrap(WrapMode.Repeat);
        Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/normal.png");
        normalMap2.setWrap(WrapMode.Repeat);
        matRock.setTexture("NormalMap", normalMap0);
        matRock.setTexture("NormalMap_1", normalMap2);
        matRock.setTexture("NormalMap_2", normalMap2);

        AbstractHeightMap heightmap = null;
        try {
            heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f);
            heightmap.load();

        } catch (Exception e) {
            e.printStackTrace();
        }

        terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());
        List<Camera> cameras = new ArrayList<Camera>();
        cameras.add(getCamera());
        TerrainLodControl control = new TerrainLodControl(terrain, cameras);
        terrain.addControl(control);
        terrain.setMaterial(matRock);
        terrain.setLocalScale(new Vector3f(2, 2, 2));

        terrainPhysicsNode = new RigidBodyControl(CollisionShapeFactory.createMeshShape(terrain), 0);
        terrain.addControl(terrainPhysicsNode);
        rootNode.attachChild(terrain);
        getPhysicsSpace().add(terrainPhysicsNode);
    }

    private void createCharacter() {
        CapsuleCollisionShape capsule = new CapsuleCollisionShape(1f, 4f);
        character = new CharacterControl(capsule, 0.01f);
        model = (Node) assetManager.loadModel("Models/erika/erika.j3o");
        model.setLocalScale(3.5f);
        model.addControl(character);
        character.setPhysicsLocation(new Vector3f(-140, 40, -10));
        rootNode.attachChild(model);
        getPhysicsSpace().add(character);
    }

    private void setupChaseCamera() {
        flyCam.setEnabled(false);
        chaseCam = new ChaseCamera(cam, model, inputManager);
    }
/**
    private void setupAnimationController() {
        animationControl = model.getControl(AnimControl.class);
        animationControl.addListener(this);
        animationChannel = animationControl.createChannel();
//        shootingChannel = animationControl.createChannel();
//        shootingChannel.addBone(animationControl.getSkeleton().getBone("uparm.right"));
//       shootingChannel.addBone(animationControl.getSkeleton().getBone("arm.right"));
//        shootingChannel.addBone(animationControl.getSkeleton().getBone("hand.right"));
    }
*/
    @Override
    public void simpleUpdate(float tpf) {
        Vector3f camDir = cam.getDirection().clone().multLocal(0.1f);
        Vector3f camLeft = cam.getLeft().clone().multLocal(0.1f);
        camDir.y = 0;
        camLeft.y = 0;
        walkDirection.set(0, 0, 0);
        if (left) {
            walkDirection.addLocal(camLeft);
        }
        if (right) {
            walkDirection.addLocal(camLeft.negate());
        }
        if (up) {
            walkDirection.addLocal(camDir);
        }
        if (down) {
            walkDirection.addLocal(camDir.negate());
        }
        if (!character.onGround()) {
            airTime = airTime + tpf;
        } else {
            airTime = 0;
        }
        if (walkDirection.length() == 0) {
//            if (!"idle".equals(animationChannel.getAnimationName())) {
//                animationChannel.setAnim("idle", 1f);
//            }
        } else {
            character.setViewDirection(walkDirection);
            if (airTime > .3f) {
//                if (!"idle".equals(animationChannel.getAnimationName())) {
//                    animationChannel.setAnim("idle");
//                }
//            } else if (!"Walk".equals(animationChannel.getAnimationName())) {
//                animationChannel.setAnim("Walk", 0.7f);
            }
        }
        character.setWalkDirection(walkDirection);
    }

    public void onAction(String binding, boolean value, float tpf) {
        if (binding.equals("CharLeft")) {
            if (value) {
                left = true;
            } else {
                left = false;
            }
        } else if (binding.equals("CharRight")) {
            if (value) {
                right = true;
            } else {
                right = false;
            }
        } else if (binding.equals("CharUp")) {
            if (value) {
                up = true;
            } else {
                up = false;
            }
        } else if (binding.equals("CharDown")) {
            if (value) {
                down = true;
            } else {
                down = false;
            }
        } else if (binding.equals("CharSpace")) {
            character.jump();
//        } else if (binding.equals("CharShoot") && !value) {
//            bulletControl();
        }
    }



/**
    public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
        if (channel == shootingChannel) {
            channel.setAnim("idle");
        }
    }
*/
    public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
    }
}

Please, anybody can tell me what’s wrong? Is it my model or is it my code?

1 Like

Not a very descriptive error but you assume the AnimControl is under the main node when you write this:

animationControl = model.getControl(AnimControl.class);

Since you are not using orge export, you may want to make sure that’s where it is.

Examples,
https://jmonkeyengine.github.io/wiki/jme3/advanced/debugging.html#wireframe-for-animations
https://jmonkeyengine.github.io/wiki/jme3/advanced/traverse_scenegraph.html#code-sample

1 Like

Understood the concept. But because i’m noob i need sometime to understand the code. Thanks. Going to go deep to it.

Edit: I didn’t use Ogre because i still fail exporting ogre. Somehow it no export animation. But that’s another topic.

1 Like

Usually this is because Ogre defaults to selected only on export. This means you have to select both the model and the armature in object mode before exporting.

1 Like

I think it’s better option to convert models with animation to j3o models from blender.

1 Like

Don’t you need 3.2 for that?

2 Likes

I think you can convert it to j3o in jMB and use it in jME 3.1

1 Like

If you’re still getting the NullPointerException, please provide a stack trace for analysis.

1 Like

@javasabr I’m going to try that. But because my internet is getting slow, I need sometime.

1 Like

@sgold
stack trace? like this?..

SEVERE: Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.NullPointerException
	at mygame.CharWalk.setupAnimationController(CharWalk.java:240)
	at mygame.CharWalk.simpleInitApp(CharWalk.java:127)
	at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:220)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:130)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:211)
	at java.lang.Thread.run(Thread.java:745)

It’s when I use xbuf converted to j3o model (mixamo animated).

@javasabr I tried to convert my gltf model to j3o with jMB, but it just keeps loading. Is it my computer?

If I need to use 3.2 , I have it. Is it possible to test my gltf model with code above on 3.2? How to do that? I mean what do I need? I use bootmonkey. Add dependencies?

1 Like

@mitm I tried the tutorial again. I don’t know if I missed something. I found that animation exported to each mesh. The animation is unplayable when view on SDK. I alreday tried to join all all meshes to one mesh but the animation still unplayable.

1 Like

Yes. Now show us which is line 240 of CharWalk.java

1 Like

here

        animationControl.addListener(this);
1 Like

As mitm said, you’ve assumed in setupAnimationController() that the AnimControl is added to the main node (the Node referenced by the ‘model’ field), and it isn’t there. Animation controls can be added to any Spatial in the model. One way to search through all the spatials in the model would be to use a SceneGraphVisitor object (as mitm suggested). If you search all the spatials and still don’t find an AnimControl, then the issue is with the model or the asset pipeline.

1 Like

okay. i try to understand the code again.

1 Like

Heres an example of how to use an adapter.

Note that you change spatial to model, rename the channels and addListener from new AnimationEventListener() to this. Then add it to your setupAnimationController() method.

Don’t forget to include this part after the adapter just in case you don’t have an AnimControl.

        if (animControl == null) {
            LOG.log(Level.SEVERE, "No AnimControl {0}", spatial);
            throw new RuntimeException();
        }

add this to your class variables.

private static final Logger LOG = Logger.getLogger(CharWalk.class.getName());

See this for more info on logging,
https://jmonkeyengine.github.io/wiki/jme3/advanced/logging.html

This will at minimum get you past the AnimControl as being the problem

1 Like

have you seen any errors in log?

1 Like

I don’t know how to see errors in log. I close the window because the load never end.

1 Like

I try to add something like this:

    private void setUpAnimationAdapter() {
    model.depthFirstTraversal(new SceneGraphVisitorAdapter() {
        @Override
        public void visit(Node node) {
            if (node.getControl(AnimControl.class) != null) {
                animationControl = node.getControl(AnimControl.class);
                animationControl.addListener(this);
    
            }
        }
    });
    
            if (animationControl == null) {
            LOG.log(Level.SEVERE, "No AnimControl {0}", model);
            throw new RuntimeException();
        }
    
        } 

this line

                animationControl.addListener(this);

is a error. something like… incompatible types: cannot be converted to AnimEventListener

1 Like

Well, does “this” implement AnimEventListener? We can’t see that part.

1 Like