Blender obj import and the infamous white material

  I'm having a bear of a time with import.  I am a noob to JME and an almost noob to Blender.  I have been going through the JME tuts and trying to learn this beast known as JME.  He seems like quite the warrior if not a tad difficult to get one's head around.



  I created an impressive cube in Blender.  Really, it is!  And I have the cube a material of a red color.  No UV…I just set it to "red".



I then exported out as an obj from Blender.  I get an .obj and a .mtl after export. Cool!  When I load it up in my app (extended off of SimpleGame) I get the cube but it's looking all white on me.  I want it to be red as I set it in Blender. A red cube looks so much tougher!



  I searched around the forums and I noticed lighting seems to be an issue for whiteness at times.  But I assumed (please correct me if I am in error) that SimpleGame kind of takes care of that in a .uhhhh… simple way?



I assume I am doing something extremely stupid.  So I'd appreciate someone pointing out just how stupid I am (with a solution, of course). :slight_smile:



Thank you in advance to any kind soul that can scoot me along in my learning.



Here are my files.



cube.obj



# Blender3D v244 OBJ File: cube.blend
# www.blender3d.org
mtllib cube.mtl
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vn -0.000000 -0.000000 1.000000
vn 1.000000 0.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000001 -0.000000 -1.000000
vn -1.000000 0.000000 -0.000000
vn -1.000000 -0.000000 -0.000001
vn -0.000000 -1.000000 0.000000
vn 0.000000 1.000000 -0.000000
g Cube_Cube_RED
usemtl RED
s 1
f 4//1 1//1 8//1
f 1//1 5//1 8//1
f 3//2 4//2 8//2
f 3//2 8//2 7//2
f 2//3 3//3 6//3
f 3//4 7//4 6//4
f 1//5 2//5 5//5
f 2//6 6//6 5//6
f 5//7 6//7 7//7
f 5//7 7//7 8//7
f 1//8 4//8 3//8
f 1//8 3//8 2//8



cube.mtl:


# Blender3D MTL File: cube.blend
# Material Count: 1
newmtl RED
Ns 96.078431
Ka 0.000000 0.000000 0.000000
Kd 0.640000 0.000000 0.000000
Ks 0.500000 0.500000 0.500000
Ni 1.000000
d 1.000000
illum 2



LoadCube.java


import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.bounding.BoundingSphere;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Node;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Sphere;
import com.jme.scene.TriMesh;
import com.jme.scene.state.LightState;
import com.jme.scene.state.MaterialState;
import com.jme.light.LightNode;

import com.jme.system.DisplaySystem;

import com.jme.light.PointLight;
import com.jme.util.export.binary.BinaryImporter;
import com.jmex.model.converters.ObjToJme;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import java.net.URL;

public class LoadCube extends SimpleGame
{
   public static void main(String[] args)
   {
      LoadCube app = new LoadCube();
      app.setDialogBehaviour(SimpleGame.ALWAYS_SHOW_PROPS_DIALOG);
      app.start();
   }
 
   protected void simpleInitGame()
   {

      ObjToJme converter = new ObjToJme();
      try
      {
         URL objFile = LoadCube.class.getClassLoader().getResource(
               "cube.obj");
         
         converter.setProperty("mtllib", objFile);
            converter.setProperty("texdir",objFile);
                    
         ByteArrayOutputStream BO = new ByteArrayOutputStream();
         
         System.out.println("Starting to convert .obj to .jme");
         
         converter.convert(objFile.openStream(), BO);
         
            //load as a TriMesh if single object
          TriMesh model = (TriMesh) BinaryImporter.getInstance().load(
               new ByteArrayInputStream(BO.toByteArray()));
         
            //load as a node if multiple objects
            // Node model = (Node)BinaryImporter.getInstance().load(
            //                new ByteArrayInputStream(BO.toByteArray()));

         
           model.setLocalScale(5f);
         model.setModelBound(new BoundingSphere());
         
         model.updateModelBound();         
            
         rootNode.attachChild(model);


      }
      catch (IOException e)
      {
         e.printStackTrace();
      }
                  
       rootNode.setLightCombineMode(LightState.OFF);
      
 }
 
}


I had issues loading obj files exported from Blender in jME. I assume you need to set the “mtllib” variable on the importer since it only takes an InputStream to the model and can’t possibly access the MTL file without knowing in which directory the model is. Another solution is not to use the OBJ at all but to use mesh.xml (Ogre3D engine model format) and use the Radakan mesh.xml importer, which has support for multiple meshes, materials, textures and alpha operations.

Okay I tried this (replacing TriMesh with Node):



  Node model = (Node)BinaryImporter.getInstance().load(
                            new ByteArrayInputStream(BO.toByteArray()));



And I got:


May 3, 2008 4:49:38 PM class LoadCube start()
SEVERE: Exception in game loop
java.lang.ClassCastException: com.jme.scene.TriMesh cannot be cast to com.jme.scene.Node
   at LoadCube.simpleInitGame(LoadCube.java:58)
   at com.jme.app.BaseSimpleGame.initGame(Unknown Source)
   at com.jme.app.BaseGame.start(Unknown Source)
   at LoadCube.main(LoadCube.java:32)



I searched around the forum and some suggested one should use Spatial instead of Node.  So I did:


             Spatial model = (Spatial)BinaryImporter.getInstance().load(
                            new ByteArrayInputStream(BO.toByteArray()));



And I get the red cube I expected. YAY!!!! I accept that as a victory but I don't understand it.  Does anyone have any ideas?

The OBJ importer imports single meshes as TriMesh and multiple meshes as Node. Since both these classes are subclasses of Spatial, that should always be used when loading imported OBJ scenes unless you know exactly what your scene looks like.

hevee said:

The OBJ importer imports single meshes as TriMesh and multiple meshes as Node. Since both these classes are subclasses of Spatial, that should always be used when loading imported OBJ scenes unless you know exactly what your scene looks like.


I can accept that as a given. But why did Maggie Simpson work? She's loaded with a "Node"

http://www.jmonkeyengine.com/wiki/doku.php?id=starter:hello_modelloading

Maggie consists of multiple meshes with different materials. Your cube is probably only one simple mesh, with one material, and can thus be imported as a TriMesh.



Sorry for not being more specific earlier, the reason a complex model is imported as a Node in the OBJ importer is that a jME TriMesh cannot have multiple materials. So every part of the OBJ model with a different material on it needs to be imported as a separate TriMesh, and then they are all wrapped in a single Node to provide a single Spatial to be returned by the load() method.

A single mesh with a single material however can be loaded as a TriMesh, so the slight overhead of wrapping a Node around the TriMesh is avoided here.

hevee said:

Maggie consists of multiple meshes with different materials. Your cube is probably only one simple mesh, with one material, and can thus be imported as a TriMesh.



That's the thing that confused me. Maggie looks so much more complicated than my simple itty bitty Cube. So I assumed  - no problem.  But Trimesh and Node were inadequate.  Spatial was the only way I got a material along with the geometry.


Sorry for not being more specific earlier, the reason a complex model is imported as a Node in the OBJ importer is that a jME TriMesh cannot have multiple materials. So every part of the OBJ model with a different material on it needs to be imported as a separate TriMesh, and then they are all wrapped in a single Node to provide a single Spatial to be returned by the load() method.
A single mesh with a single material however can be loaded as a TriMesh, so the slight overhead of wrapping a Node around the TriMesh is avoided here.


Not meaning to belabor the point but why didn't my simple lil' cube come in fine as a TriMesh (material and all)?

It doesn't make any difference whether you cast it to a Node or a TriMesh or a Spatial, it's still the same object and jME treats it exactly the same. Probably the reason why it loaded the material is because the TestObjLoading class correctly sets up the material path for the importer while your class doesn't.

Momoko_Fan said:

It doesn't make any difference whether you cast it to a Node or a TriMesh or a Spatial, it's still the same object and jME treats it exactly the same.


That's what I would have assumed too.


Probably the reason why it loaded the material is because the TestObjLoading class correctly sets up the material path for the importer while your class doesn't.


I have no idea what that means.  I just followed the Maggie example being a noob.

Momoko_Fan said:

Probably the reason why it loaded the material is because the TestObjLoading class correctly sets up the material path for the importer while your class doesn't.


Could you please share how my class *should* handle the material path?  As I wrote earlier I just followed the Maggie example.  So if I missed something I'd sure like to know what it is so that I can make sure to do it from this point on.

One thing you can do is use the ResourceLocatorTool to setup a path to your model and texture related files, so that jME will look for those files there. An example of how to do this can be fount in the  ModelLoader test

duenez said:

One thing you can do is use the ResourceLocatorTool to setup a path to your model and texture related files, so that jME will look for those files there. An example of how to do this can be fount in the  ModelLoader test


Thanks!

I went to:  http://www.jmonkeyengine.com/doc/

And I couldn't find com.jme.util.resource.ResourceLocatorTool.

I also am not sure what you mean by ModelLoader test? I went into my src/jmetest but I didn't see anything like that. Could you dumb it down a bit for me :)  Where would this be located?

My apologies if these seem like trivial questions.

My fault, ModelLoader is not a test, it is a utility  :roll:



com.jmex.model.util.ModelLoader



As for the ResourceLocator… this thread should help… http://www.jmonkeyengine.com/jmeforum/index.php?topic=5707.0