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?