Using MakeHuman models

Hey does anyone have experience with using makehuman to create your in game characters, it’s completely free no licensing issues etc and can create very high quality human models. You can also download motion capture data from other sources (sound licensing again) to animate these humans through various actions. Which is all fine and good.

However I’m having trouble getting the model into jmonkey, I’m trying to export as an OgreXML and then import it in and I’m getting all sorts of problems. Firstly I tried loading it via the .scene but that didn’t work then using the .mesh.xml for the whole object. I tried converting the .mesh.xml into a .j3o binary but the sdk gives me a list of exceptions starting with an Array Index Out of Bounds at com.jme3.scene.plugins.ogre.MaterialLoader.readTextureUnit(MaterialLoader.java:197)

I’m wondering if this is because of how makehuman lays out its file structure (I make the people in makehuman export as an OBJ then import into blender and the skeleton etc is already done for me).

Here’s my load model code for importing the ogre xml:

[Edit:] just realised both my code and the sdk have a problem with line 197 in the material loader… I’m going to dig into the source right now

[java] Spatial heman=assetManager.loadModel(“Models/heman2/Clothes_testMesh.mesh.xml”);[/java]

[java]Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readPassStatement
WARNING: Unsupported pass directive: alpha_to_coverage
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readPassStatement
WARNING: Unsupported pass directive: colour_write
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readPassStatement
WARNING: Unsupported pass directive: depth_check
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readPassStatement
WARNING: Unsupported pass directive: depth_func
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readPassStatement
WARNING: Unsupported pass directive: depth_write
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readPassStatement
WARNING: Unsupported pass directive: illumination_stage
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readPassStatement
WARNING: Unsupported pass directive: light_clip_planes
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readPassStatement
WARNING: Unsupported pass directive: light_scissor
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readPassStatement
WARNING: Unsupported pass directive: normalise_normals
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readPassStatement
WARNING: Unsupported pass directive: polygon_mode
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readPassStatement
WARNING: Unsupported pass directive: scene_blend_op
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readPassStatement
WARNING: Unsupported pass directive: shading
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readPassStatement
WARNING: Unsupported pass directive: transparent_sorting
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readTextureUnitStatement
WARNING: Unsupported texture_unit directive: scale
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readTextureUnitStatement
WARNING: Unsupported texture_unit directive: colour_op
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readTextureUnitStatement
WARNING: Unsupported texture_unit directive: scale
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readTextureUnitStatement
WARNING: Unsupported texture_unit directive: colour_op
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readTextureUnitStatement
WARNING: Unsupported texture_unit directive: scale
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readTextureUnitStatement
WARNING: Unsupported texture_unit directive: colour_op
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readTextureUnitStatement
WARNING: Unsupported texture_unit directive: scale
Apr 20, 2013 9:24:17 AM com.jme3.scene.plugins.ogre.MaterialLoader readTextureUnitStatement
WARNING: Unsupported texture_unit directive: colour_op_ex
Apr 20, 2013 9:24:17 AM com.jme3.app.Application handleError
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.ArrayIndexOutOfBoundsException: 4
at com.jme3.scene.plugins.ogre.MaterialLoader.readTextureUnit(MaterialLoader.java:197)
at com.jme3.scene.plugins.ogre.MaterialLoader.readPassStatement(MaterialLoader.java:247)
at com.jme3.scene.plugins.ogre.MaterialLoader.readPass(MaterialLoader.java:283)
at com.jme3.scene.plugins.ogre.MaterialLoader.readTechnique(MaterialLoader.java:299)
at com.jme3.scene.plugins.ogre.MaterialLoader.readMaterialStatement(MaterialLoader.java:305)
at com.jme3.scene.plugins.ogre.MaterialLoader.readMaterial(MaterialLoader.java:316)
at com.jme3.scene.plugins.ogre.MaterialLoader.load(MaterialLoader.java:452)
at com.jme3.scene.plugins.ogre.MaterialLoader.load(MaterialLoader.java:465)
at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:283)
at com.jme3.scene.plugins.ogre.MeshLoader.load(MeshLoader.java:867)
at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:283)
at com.jme3.asset.DesktopAssetManager.loadModel(DesktopAssetManager.java:369)
at com.jme3.asset.DesktopAssetManager.loadModel(DesktopAssetManager.java:373)[/java]

I imported makehuman models into jme3 no problem at all.

Incidentally in the makehuman options you can select the mesh and the rig to export, you should look at those since otherwise you end up with a character with a LOT of polygons and bones.

I used the makehuman blender exporter/importer went from makehuman->blender. I then animated the rigged model in blender (FK rigging only) and used the blender importer in the SDK (blend->convert to j3o) to import.

Worked perfectly first time.

hmm I tried different settings and I finally got it to import, only problem was the model was oddly translucent. Guess I’m going to have to fiddle with makehuman export settings/blender until I get it right.

Hello,

I have made a character in MakeHuman application, exported it in .mhx format, and then imported it in blender.

I have then animated the character and imported in jmonkeyengine.

The problem is that:

  • The animation is appliaed to each part seperately (e.g. to the body, to the hair, to the shirt… etc)

  • In jmonkeyengine if i call for an animation using the body node, only the body plays the animation and the hair and clothes etc remains static.

  • Also the clothes and hair etc are some white coloured things and not the real clothes and hair that i picked in makehuman.

Can you help please? if you can give some tips?

Thanks a lot,
Ayesha

Make a simple control that loops through all sub-AnimControls and sets the animation on all of them. Did you experiment with the humanoid presets in MakeHuman? Theres some that are meant for 3D image creation and some for live 3D rendering, as in jME. I think some of them have simpler models and animation systems which might be more suitable for jME.

2 Likes

Heres some of my code that does this:
[java]/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */
    package com.jme3.powermonkey.controls;

import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.SkeletonControl;
import com.jme3.asset.AssetManager;
import com.jme3.powermonkey.Entity;
import com.jme3.powermonkey.components.MovementComponent;
import com.jme3.powermonkey.components.PositionComponent;
import com.jme3.powermonkey.components.InSceneComponent;
import com.jme3.powermonkey.components.VisualRepComponent;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.SceneGraphVisitorAdapter;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import jme3tools.optimize.TextureAtlas;

/**
*

  • @author normenhansen
    */
    public final class EntityControl extends AbstractControl {

    private static final Logger logger = Logger.getLogger(EntityControl.class.getName());
    private static final Map<String, Spatial> models = new ConcurrentHashMap<String, Spatial>();
    private Entity entity;
    private AssetManager manager;
    private String currentModelName;
    private Spatial currentModel;
    private long lastLocationUpdate;
    private float updateTime;
    private List animControls;
    private List animChannels;

    public EntityControl(Entity entity, AssetManager manager) {
    this.entity = entity;
    this.manager = manager;
    }

    @Override
    public void setSpatial(Spatial spatial) {
    super.setSpatial(spatial);
    }

    @Override
    protected void controlUpdate(float tpf) {
    if (entity == null) {
    return;
    }
    if (!updateVisualRep()) {
    return;
    }
    if (!updateLocation(tpf)) {
    return;
    }
    if (!updateAnimation()) {
    return;
    }
    }

    private boolean updateVisualRep() {
    VisualRepComponent visRep = entity.getComponent(VisualRepComponent.class);
    if (visRep != null) {
    if (currentModelName != null && currentModelName.equals(visRep.getAssetName())) {
    return true;
    } else {
    if (currentModel != null) {
    setAnimControls(null);
    currentModel.removeFromParent();
    }
    currentModelName = visRep.getAssetName();
    // Spatial model = models.get(currentModelName);
    // if (model == null) {
    //
    // setAnimControls(model);
    // model = manager.loadModel(currentModelName);
    // try {
    // Spatial newmodel = TextureAtlas.makeAtlasBatch(model, manager, 1024);
    // if (newmodel != null) {
    // model = newmodel;
    // }
    // } catch (Exception e) {
    // System.out.println("error batching model " + currentModelName + ": " + e);
    // }
    // } else {
    // model = model.clone(false);
    // }
    // models.put(currentModelName, model);
    // currentModel = model;
    currentModel = manager.loadModel(currentModelName);
    setAnimControls(currentModel);
    ((Node) spatial).attachChild(currentModel);
    }
    } else {
    //dispose ourselves if the entity has no VisualRepComponent anymore…
    setAnimControls(null);
    spatial.removeFromParent();
    entity.clearComponent(InSceneComponent.class);
    return false;
    }
    return true;
    }

    private boolean updateLocation(float tpf) {
    PositionComponent position = entity.getComponent(PositionComponent.class);
    MovementComponent movement = entity.getComponent(MovementComponent.class);
    if (movement != null && position != null) {
    spatial.setLocalTranslation(position.getLocation());
    spatial.setLocalRotation(position.getRotation());

         if (position.getLastUpdate() == lastLocationUpdate) {
             //TODO: interpolate
         }
     } else if (position != null) {
         spatial.setLocalTranslation(position.getLocation());
         spatial.setLocalRotation(position.getRotation());
     }
     return true;
    

    }

    private boolean updateAnimation() {
    MovementComponent movement = entity.getComponent(MovementComponent.class);
    if (movement != null && movement.getMovement().length() > 0) {
    setAnimation(“walk”);
    } else {
    setAnimation(“idle”);
    }
    return true;
    }

    private void setAnimation(String name) {
    if (animChannels != null) {
    for (Iterator it = animChannels.iterator(); it.hasNext():wink: {
    AnimChannel animChannel = it.next();
    if (animChannel.getAnimationName() == null || !animChannel.getAnimationName().equals(name)) {
    animChannel.setAnim(name);
    logger.log(Level.INFO, “Setting anim {0}”, name);
    if (animChannel.getControl().getAnim(name) != null) {
    }
    }
    }
    }
    }

    private void setAnimControls(Spatial spatial) {
    if (spatial == null) {
    if (animControls != null) {
    for (Iterator it = animControls.iterator(); it.hasNext():wink: {
    AnimControl animControl = it.next();
    animControl.clearChannels();
    }
    }
    animControls = null;
    animChannels = null;
    return;
    }
    SceneGraphVisitorAdapter visitor = new SceneGraphVisitorAdapter() {

         @Override
         public void visit(Geometry geom) {
             super.visit(geom);
             checkForAnimControl(geom);
         }
    
         @Override
         public void visit(Node geom) {
             super.visit(geom);
             checkForAnimControl(geom);
         }
    
         private void checkForAnimControl(Spatial geom) {
             AnimControl control = geom.getControl(AnimControl.class);
             if (control == null) {
                 return;
             }
             if (animControls == null) {
                 animControls = new LinkedList<AnimControl>();
             }
             if (animChannels == null) {
                 animChannels = new LinkedList<AnimChannel>();
             }
    

// geom.removeControl(geom.getControl(SkeletonControl.class));
// geom.removeControl(control);
animControls.add(control);
animChannels.add(control.createChannel());
}
};
spatial.depthFirstTraversal(visitor);
}

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

public Control cloneForSpatial(Spatial spatial) {
    throw new UnsupportedOperationException("Not supported");
}

}
[/java]

2 Likes

Thanks so much norman, now the body, hair and clothes etc, move altogether :slight_smile:

Thanks for sharing your code as well.

@ayesha-kashif said: Thanks so much norman, now the body, hair and clothes etc, move altogether :)

Thanks for sharing your code as well.

Just hoping for that rundown when you got it working completely :stuck_out_tongue:

1 Like