Texture missing in model, loading wrong texture path

Hello guys, im really an total newbie here.



Im trying load a OBJ model, i copy the modelLoad function of the Wiki jMe 2.0 code snipet.





My Eclipse project have this structure:



/myproject

    /src

          (default package)

            Game.java

          /res

            cajon.obj

            cajon.mtl

            Wood_Cherry_Original.jpg

            Wood_Plywood_Knots.jpg

        /lib

        /jMe

        …

        …



This load the model without load the textures, the shell drop a exception saying that cant find the texture file  Wood_Cherry_Original.jpg and Wood_Plywood_Knots.jpg in /myproject, (First, why search in root project dir?) i have the MTL file into /myproject/src/res and the textures also are in this dir.



I try put the textures in root /myproject and load ALL FINE! but this is rare,



Second, why create the jbin file in /myproject/res/cajon.jbin ? (yes! this create other res folder at root level)





Thank you very match,

this engine appear be too powerful, i comeback from python to java and is my first 3D engine.





My MTL file is this:



# Blender3D MTL File:
# Material Count: 4
newmtl Color_E07
Ns 96.078431
Ka 0.000000 0.000000 0.000000
Kd 0.640000 0.640000 0.125490
Ks 0.165000 0.165000 0.165000
Ni 1.000000
d 1.000000
illum 2


newmtl Wood_Plywood_Knots_Wood_Plywood_Knots.jp
Ns 96.078431
Ka 0.000000 0.000000 0.000000
Kd 0.119216 0.084706 0.047059
Ks 0.165000 0.165000 0.165000
Ni 1.000000
d 1.000000
illum 2
map_Kd Wood_Plywood_Knots.jpg


newmtl FrontColor
Ns 96.078431
Ka 0.000000 0.000000 0.000000
Kd 0.800000 0.800000 0.800000
Ks 0.165000 0.165000 0.165000
Ni 1.000000
d 1.000000
illum 2


newmtl Wood_Cherry_Original_Wood_Cherry_Original.
Ns 96.078431
Ka 0.000000 0.000000 0.000000
Kd 0.749804 0.699608 0.498823
Ks 0.165000 0.165000 0.165000
Ni 1.000000
d 1.000000
illum 2
map_Kd Wood_Cherry_Original.jpg






This is my Game.java:


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.util.export.Savable;
import com.jme.util.export.binary.BinaryExporter;
import com.jme.util.export.binary.BinaryImporter;
import com.jmex.audio.AudioSystem;
import com.jmex.audio.AudioTrack;
import com.jmex.model.converters.AseToJme;
import com.jmex.model.converters.FormatConverter;
import com.jmex.model.converters.MaxToJme;
import com.jmex.model.converters.Md2ToJme;
import com.jmex.model.converters.Md3ToJme;
import com.jmex.model.converters.MilkToJme;
import com.jmex.model.converters.ObjToJme;
import com.jmex.model.util.ModelLoader;



public class Game extends SimpleGame {
   
   private AudioTrack trebleLeftSnd;
   private AudioTrack trebleRightSnd;
   private AudioTrack bassLeftSnd;
   private AudioTrack bassRightSnd;
   private Node cajonNode;
   
   public static void main(String[] args) {
      Game app = new Game();
      app.setConfigShowMode(ConfigShowMode.AlwaysShow);
      app.start();
   }

   private Node loadModel (String modelFile){
      Node loadedModel = null;
      FormatConverter formatConverter = null;      
      ByteArrayOutputStream BO = new ByteArrayOutputStream();
      String modelFormat = modelFile.substring(modelFile.lastIndexOf(".") + 1, modelFile.length());
      String modelBinary = modelFile.substring(0, modelFile.lastIndexOf(".") + 1) + "jbin";
      URL   modelURL = ModelLoader.class.getClassLoader().getResource(modelBinary);
 
      //verify the presence of the jbin model
      if (modelURL == null){
         modelURL = ModelLoader.class.getClassLoader().getResource(modelFile);
         //evaluate the format
         if (modelFormat.equals("3ds")){
            formatConverter = new MaxToJme();
         } else if (modelFormat.equals("md2")){
            formatConverter = new Md2ToJme();
         } else if (modelFormat.equals("md3")){
            formatConverter = new Md3ToJme();
         } else if (modelFormat.equals("ms3d")){
            formatConverter = new MilkToJme();
         } else if (modelFormat.equals("ase")){
            formatConverter = new AseToJme();
         } else if (modelFormat.equals("obj")){
            formatConverter = new ObjToJme();
         }
         formatConverter.setProperty("mtllib", modelURL);
 
         try {
            formatConverter.convert(modelURL.openStream(), BO);
            loadedModel = (Node) BinaryImporter.getInstance().load(new ByteArrayInputStream(BO.toByteArray()));
            //save the jbin format
            BinaryExporter.getInstance().save((Savable)loadedModel, new File(modelBinary));
         }
         catch (IOException e) {            
            e.printStackTrace();
            return null;
         }
      }
      
      else {
         try {
            //load the jbin format
            loadedModel = (Node) BinaryImporter.getInstance().load(modelURL.openStream());
         }
         catch (IOException e) {
            return null;
         }
      }
 
      return loadedModel;
   }
   
   protected void simpleInitGame() {
      // Setup graphics
      this.cajonNode = this.loadModel("res/cajon.obj");
      //this.cajonNode.setLocalTranslation(new Vector3f(0,0,0));
      this.cajonNode.setModelBound(new BoundingBox());
      this.cajonNode.updateModelBound();
      this.rootNode.attachChild(this.cajonNode);
      
      // Setup sounds
      AudioSystem audio = AudioSystem.getSystem();
      this.trebleLeftSnd = audio.createAudioTrack(this.getClass().getResource("res/trebleLeftSnd.wav"), false);
      this.bassLeftSnd = audio.createAudioTrack(this.getClass().getResource("res/bassLeftSnd.wav"), false);
      
      // Setup inputs
      KeyBindingManager.getKeyBindingManager().set("trebleLeft", KeyInput.KEY_X);
      KeyBindingManager.getKeyBindingManager().set("bassLeft", KeyInput.KEY_W);
      KeyBindingManager.getKeyBindingManager().set("trebleRight", KeyInput.KEY_M);
      KeyBindingManager.getKeyBindingManager().set("bassRight", KeyInput.KEY_Y);
      
   }
   
   protected void simpleUpdate() {
      if (KeyBindingManager.getKeyBindingManager().isValidCommand("trebleLeft", false)) {
         this.trebleLeftHit();
      }
      if (KeyBindingManager.getKeyBindingManager().isValidCommand("bassLeft", false)) {
         this.bassLeftHit();
      }
   }

   private void bassLeftHit() {
      this.trebleLeftSnd.play();
   }

   private void trebleLeftHit() {
      this.bassLeftSnd.play();
   }

}

you need to tell the ResourceLocator where to look for Resources:



I think this should work in your case.

Don't forget the trailing / slash.



ResourceLocatorTool.addResourceLocator(
ResourceLocatorTool.TYPE_TEXTURE,
new SimpleResourceLocator(YourClass.class.getClassLoader().getResource("res/")));
ResourceLocatorTool.addResourceLocator(
ResourceLocatorTool.TYPE_MODEL,
new SimpleResourceLocator(YourClass.class.getClassLoader().getResource("res/")));

// to load the model
URL url = ResourceLocatorTool.locateResource(ResourceLocatorTool.TYPE_MODEL, "yourmodel.obj");


Core-Dump said:

you need to tell the ResourceLocator where to look for Resources:

I think this should work in your case.
Don't forget the trailing / slash.


ResourceLocatorTool.addResourceLocator(
ResourceLocatorTool.TYPE_TEXTURE,
new SimpleResourceLocator(YourClass.class.getClassLoader().getResource("res/")));
ResourceLocatorTool.addResourceLocator(
ResourceLocatorTool.TYPE_MODEL,
new SimpleResourceLocator(YourClass.class.getClassLoader().getResource("res/")));

// to load the model
URL url = ResourceLocatorTool.locateResource(ResourceLocatorTool.TYPE_MODEL, "yourmodel.obj");






But without edit the wiki modelLoader method?

What path i need load?

umm, the path where your models/textures are…

basixs said:

umm, the path where your model textures are...


i use res/cajon.obj without success, Missing textures, really im too confused, i want load textures and objects using the unified loadModel of wiki snipet.
i use res/cajon.obj without success

Thats not directory path, thats a path to a file :P (try just "res/")

Also, make sure your models actually have the texture applied to them; open them up in a modeling tool (such as blender) or viewer to check...

i want load textures and objects using the unified loadModel of wiki snipet.

There are LOTS of wiki articles with model loading, perhaps if you gave a link of what you are talking about...

But, im too confused, first…



res dir, where i must have the res with models and textures?



i have this on myproject/src/res/*



my objects mtl have the texture path, relative, as this. (last line)


newmtl Wood_Plywood_Knots1
Ka 0.000000 0.000000 0.000000
Kd 0.117647 0.086275 0.027451
Ks 0.330000 0.330000 0.330000
map_Kd Wood_Plywood_Knots1.jpg




and eclipse return a exception that cant find Wood... texture in myproject/Wood_Plywood_Knots1.jpg

Of course, i dont have the textures in project root dir. i have the textures next to the mtl and obj, in myproject/src/res,

Im loading it with this model unified modelLoader of wiki:  http://www.jmonkeyengine.com/wiki/doku.php?id=unified_model_loading&s[]=modelloader

as method of my class that i paste in my first post.

I cant try, or dont know how try your resourcelocator fix, because need edit this loader, because i see that the loader use other method, then WITHOUT edit this, how is possible fix it.

PD: Yes, i try the model in other viewer, and can see fine the textures, and also run fine the game when put the textures in project root dir.

Try this:

the only thing to fix now is saving the .jbin file.

right now it saves it to: yourproject/model.jbin instead to the "res" directory.


public class Game extends SimpleGame {
   
    private AudioTrack trebleLeftSnd;
    private AudioTrack trebleRightSnd;
    private AudioTrack bassLeftSnd;
    private AudioTrack bassRightSnd;
    private Spatial cajonNode;
   
    public static void main(String[] args) {
        Game app = new Game();
        app.setConfigShowMode(ConfigShowMode.AlwaysShow);
        app.start();
    }

    private Spatial loadModel (String modelFile){
        Spatial loadedModel = null;
        FormatConverter formatConverter = null;    
        ByteArrayOutputStream BO = new ByteArrayOutputStream();
        String modelFormat = modelFile.substring(modelFile.lastIndexOf(".") + 1, modelFile.length());
        String modelBinary = modelFile.substring(0, modelFile.lastIndexOf(".") + 1) + "jbin";
        // use resourcelocator to get the model url
        URL modelURL = ResourceLocatorTool.locateResource(ResourceLocatorTool.TYPE_MODEL, modelBinary);
 
        //verify the presence of the jbin model
        if (modelURL == null){
            modelURL = ResourceLocatorTool.locateResource(ResourceLocatorTool.TYPE_MODEL, modelFile);
            //evaluate the format
            if (modelFormat.equals("3ds")){
                formatConverter = new MaxToJme();
            } else if (modelFormat.equals("md2")){
                formatConverter = new Md2ToJme();
            } else if (modelFormat.equals("md3")){
                formatConverter = new Md3ToJme();
            } else if (modelFormat.equals("ms3d")){
                formatConverter = new MilkToJme();
            } else if (modelFormat.equals("ase")){
                formatConverter = new AseToJme();
            } else if (modelFormat.equals("obj")){
                formatConverter = new ObjToJme();
            }
            formatConverter.setProperty("mtllib", modelURL);
 
            try {
                formatConverter.convert(modelURL.openStream(), BO);
                loadedModel = (Spatial) BinaryImporter.getInstance().load(new ByteArrayInputStream(BO.toByteArray()));
                //save the jbin format
                // TODO: save to correct path
                BinaryExporter.getInstance().save((Savable)loadedModel, new File(modelBinary));
            }
            catch (IOException e) {            
                e.printStackTrace();
                return null;
            }
        }
       
        else {
            try {
                //load the jbin format
                loadedModel = (Node) BinaryImporter.getInstance().load(modelURL.openStream());
            }
            catch (IOException e) {
                return null;
            }
        }
 
        return loadedModel;
    }
   
    protected void simpleInitGame() {
        // set up resource paths
        try {
            ResourceLocatorTool.addResourceLocator(
                ResourceLocatorTool.TYPE_TEXTURE,
                new SimpleResourceLocator(Game.class.getClassLoader().getResource("res/")));
            ResourceLocatorTool.addResourceLocator(
                ResourceLocatorTool.TYPE_MODEL,
                new SimpleResourceLocator(Game.class.getClassLoader().getResource("res/")));
            ResourceLocatorTool.addResourceLocator(
                ResourceLocatorTool.TYPE_AUDIO,
                new SimpleResourceLocator(Game.class.getClassLoader().getResource("res/")));
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
       
        // Setup graphics
//        this.cajonNode = this.loadModel("res/cajon.obj");
        this.cajonNode = this.loadModel("cajon.obj");
        //this.cajonNode.setLocalTranslation(new Vector3f(0,0,0));
        this.cajonNode.setModelBound(new BoundingBox());
        this.cajonNode.updateModelBound();
        this.rootNode.attachChild(this.cajonNode);
       
        // Setup sounds
        AudioSystem audio = AudioSystem.getSystem();
//        this.trebleLeftSnd = audio.createAudioTrack(this.getClass().getResource("res/trebleLeftSnd.wav"), false);
//        this.bassLeftSnd = audio.createAudioTrack(this.getClass().getResource("res/bassLeftSnd.wav"), false);
        this.trebleLeftSnd = audio.createAudioTrack(ResourceLocatorTool.locateResource(ResourceLocatorTool.TYPE_AUDIO, "trebleLeftSnd.wav"), false);
        this.bassLeftSnd = audio.createAudioTrack(ResourceLocatorTool.locateResource(ResourceLocatorTool.TYPE_AUDIO, "bassLeftSnd.wav"), false);
       
        // Setup inputs
        KeyBindingManager.getKeyBindingManager().set("trebleLeft", KeyInput.KEY_X);
        KeyBindingManager.getKeyBindingManager().set("bassLeft", KeyInput.KEY_W);
        KeyBindingManager.getKeyBindingManager().set("trebleRight", KeyInput.KEY_M);
        KeyBindingManager.getKeyBindingManager().set("bassRight", KeyInput.KEY_Y);
    }
   
    protected void simpleUpdate() {
        if (KeyBindingManager.getKeyBindingManager().isValidCommand("trebleLeft", false)) {
            this.trebleLeftHit();
        }
        if (KeyBindingManager.getKeyBindingManager().isValidCommand("bassLeft", false)) {
            this.bassLeftHit();
        }
    }

    private void bassLeftHit() {
        this.trebleLeftSnd.play();
    }

    private void trebleLeftHit() {
        this.bassLeftSnd.play();
    }

}