ASE, OBJ, 3DS Loader for ODEJava - anybody interested?

Hi

I made some loaders for ODEJava, that load Geoms from ASE, OBJ, 3DS files. I’m doing it this way:

file ----Xith3ed loader----> Xith3d Branchgroup ----Converter----> PlaceableGeom

If you’re interested in this I could post the code.

Arne

PS: I think this is obvious, but I think I should state it: This will only work for people who got Xith3d installed - Java3D and others won’t be able to use this

Well, I am using Java3D, but have occasionally used Xith3D for a couple of app’s… Anyway, yeah, I am keen to see what you have done. Post it if you can. I think a lot of people might benifit from it!

Cheers…

Ok here it is:


import org.odejava.*;
import com.xith3d.scenegraph.*;
import org.xith3d.loader3ds.Loader3DS;
import org.xith3d.loaders.obj.OBJLoader;
import com.xith3d.loaders.ase.AseFile;
import javax.vecmath.*;

public class XithToOde {
	
	private static int num = 0;
	private Vector3f tempPos;
	private Quat4f tempRot;
	
	private XithToOde() {
		tempPos = new Vector3f();
		tempRot = new Quat4f();
	}
	
	private static String newName() {
		num++;
		return("GeneratedName"+num);
	}
	//this is from the old xith to ode converter that was located in org.odejava.xith3d.* or something like that.
	public GeomTriMesh createTriMesh(TriangleArray ta, String name) {
		
		float[] vertices = new float[ta.getVertexCount() * 3];
		int[] index = new int[ta.getVertexCount()];
		Point3f pos = new Point3f();
		for (int i = 0; i < ta.getVertexCount(); i++) {
			ta.getVertex(i, pos);
			vertices[i * 3 + 0] = pos.x;
			vertices[i * 3 + 1] = pos.y;
			vertices[i * 3 + 2] = pos.z;
			index[i] = i;
		}
		
		return new GeomTriMesh(name, vertices, index);
  	}

	
	private void addToGeom(GeomTransform geom, Group group, Matrix4f transform) {
		Matrix4f newTrans;
		if(group instanceof TransformGroup) {
			TransformGroup tgroup = (TransformGroup) group;
			newTrans = new Matrix4f(transform);
			newTrans.mul(tgroup.getTransform().getMatrix4f());
		}
		else newTrans = transform;
		for(int i = 0; i < group.numChildren(); i++) {
			Node n = (Node) group.getChild(i);
			if(n instanceof Group) {
				addToGeom(geom,(Group) n,newTrans);
			}
			else if(n instanceof Shape3D) {
				Shape3D s = (Shape3D) n;
				Geometry g = s.getGeometry();
				GeomTriMesh gtm = null;
				if(g instanceof TriangleArray) {
					gtm = createTriMesh((TriangleArray) g, newName());
				}
				else {
					System.out.println("not able to parse "+g.getClass());
				}
				if(gtm != null) {
					newTrans.get(tempPos);
					newTrans.get(tempRot);
					gtm.setPosition(tempPos);
					gtm.setQuaternion(tempRot);
					geom.setEncapsulatedGeom(gtm);
				}
			}
		}
	}
	/**
	 * creates a Geom that represents the Xith-Group. 
	 * This function does NOT create Joints!!
	 * 
Note: Only com.xith3d.scenegraph.TriangleArray is supported as Geometry.
	 * @param g the Group to convert
	 * @return a PlaceableGeom that represents the Group
	 */
	public static PlaceableGeom convert(Group g) {
		XithToOde xto = new XithToOde();
		GeomTransform gt = new GeomTransform("main_"+newName());
		Matrix4f m = new Matrix4f();
		m.setIdentity();
		xto.addToGeom(gt,g,m);
		return(gt);
	}
	/**
	 * This function uses convert(Group) to directly load Models to Odejava.
	 * 
Supported file-formats:
	 * 
ASE
	 * 
OBJ
	 * 
3DS
	 * @param filename the file to be loaded
	 * @return a PlaceableGeom that represents the Model
	 */
	public static PlaceableGeom load(String filename) {
		try {
			if(filename.endsWith(".ase") || filename.endsWith(".ASE")) {
				//load ASE
				return(convert(AseFile.getModel(filename)));
			}
			else if(filename.endsWith(".obj") || filename.endsWith(".OBJ")) {
				//load OBJ
				return(convert(new OBJLoader().load(filename)));
			}
			else if(filename.endsWith(".3ds") || filename.endsWith(".3DS")) {
				//load 3DS
				return(convert(new Loader3DS().load(filename).getSceneGroup()));
			}
			else return null;
		} catch(java.io.IOException ex) {
			System.err.println("not able to load Model!! - loading aborted");
			return null;
		}
	}
}

arne,

Look good.

My only question is why copy the source of my static createTriMesh method when you can just reference it org.odejava.xith3d.Xith3DToOdejava.createTriMesh?

Cheers,

Will.

I don’t know anymore, but I think it was because I thought I might have to change it or so. But from this POV it now seems irrational. A reference would be better. Mmh maybe we could add this code to org.odejava.xith3d.Xith3DToOdejava ?

A totally different thing: my program can only convert BranchgroupS whose Shape3DS contain of TriangleArrayS.

um… ähm I’ve noticed a big error in my code. In odejava it is not possible to add different Geoms to one GeomTransform (ofcourse not, but all these guys comparing GeomTransform with TransformGroups irritated me :wink: ) So now I can’t simply return a PlaceableGeom, but a Vector of such Geoms, because such a BranchGroup can contain different TriangleArrays - so also different GeomTriMesh.

Here is the new code (I’ve changed it also to use org.odejava.xith3d.Xith3DToOdejava - I didn’t before [yes I know now why], because I was to lazy to download the whole “[odejava] / odejava-xith3d / src” from cvs):


import org.odejava.*;
import org.odejava.xith3d.Xith3DToOdejava;
import com.xith3d.scenegraph.*;
import org.xith3d.loader3ds.Loader3DS;
import org.xith3d.loaders.obj.OBJLoader;
import com.xith3d.loaders.ase.AseFile;
import javax.vecmath.*;
import java.util.*;

public class XithToOde {
	
	private static int num = 0;
	private Vector3f tempPos;
	private Quat4f tempRot;
	
	private XithToOde() {
		tempPos = new Vector3f();
		tempRot = new Quat4f();
	}
	
	private static String newName() {
		num++;
		return("GeneratedName"+num);
	}
	
	private void addToGeom(Vector<PlaceableGeom> gVec, Group group, Matrix4f transform) {
		Matrix4f newTrans;
		if(group instanceof TransformGroup) {
			TransformGroup tgroup = (TransformGroup) group;
			newTrans = new Matrix4f(transform);
			newTrans.mul(tgroup.getTransform().getMatrix4f());
		}
		else newTrans = transform;
		for(int i = 0; i < group.numChildren(); i++) {
			Node n = (Node) group.getChild(i);
			if(n instanceof Group) {
				addToGeom(gVec,(Group) n,newTrans);
			}
			else if(n instanceof Shape3D) {
				Shape3D s = (Shape3D) n;
				Geometry g = s.getGeometry();
				GeomTriMesh gtm = null;
				if(g instanceof TriangleArray) {
					gtm = Xith3DToOdejava.createTriMesh((TriangleArray) g, newName());
				}
				else {
					System.out.println("not able to parse "+g.getClass());
				}
				if(gtm != null) {
					newTrans.get(tempPos);
					newTrans.get(tempRot);
					gtm.setPosition(tempPos);
					gtm.setQuaternion(tempRot);
					gVec.add(gtm);
				}
			}
		}
	}
	/**
	 * creates a Geom that represents the Xith-Group. 
	 * This function does NOT create Joints!!
	 * 
Note: Only com.xith3d.scenegraph.TriangleArray is supported as Geometry.
	 * @param g the Group to convert
	 * @return a PlaceableGeom that represents the Group
	 */
	public static Vector<PlaceableGeom> convert(Group g) {
		XithToOde xto = new XithToOde();
		Vector<PlaceableGeom> gVec = new Vector<PlaceableGeom>();
		Matrix4f m = new Matrix4f();
		m.setIdentity();
		xto.addToGeom(gVec,g,m);
		return(gVec);
	}
	/**
	 * This function uses convert(Group) to directly load Models to Odejava.
	 * 
Supported file-formats:
	 * 
ASE
	 * 
OBJ
	 * 
3DS
	 * @param filename the file to be loaded
	 * @return a PlaceableGeom that represents the Model
	 */
	public static Vector<PlaceableGeom> load(String filename) {
		try {
			if(filename.endsWith(".ase") || filename.endsWith(".ASE")) {
				//load ASE
				return(convert(AseFile.getModel(filename)));
			}
			else if(filename.endsWith(".obj") || filename.endsWith(".OBJ")) {
				//load OBJ
				return(convert(new OBJLoader().load(filename)));
			}
			else if(filename.endsWith(".3ds") || filename.endsWith(".3DS")) {
				//load 3DS
				return(convert(new Loader3DS().load(filename).getSceneGroup()));
			}
			else return null;
		} catch(java.io.IOException ex) {
			System.err.println("not able to load Model!! - loading aborted");
			return null;
		}
	}
}

Have fun with it !! :smiley: :smiley:

  1. there is an issue with your loader. when loading a 3DS file…

Shape3D s = (Shape3D) n;
Geometry g = s.getGeometry(); …returns an IndexedTriangleArray, while you ask for TriangleArray.
this causes a class cast exception.

I just had to change Will’s code to:

public GeomTriMesh createTriMesh(IndexedTriangleArray ita, String name){
        return new GeomTriMesh(name, ita.getCoordRefFloat(), ita.getIndex());
}

I didn’t get to test it with an .obj file, because OBJLoader seems to have it’s own issues with Maya
exported files.

  1. can I collide 2 TriMeshES in Odejava? Ode documentation suggest’s it works, but
    I couldn’t get it to work. how would you implement the position cache that is mentioned
    in Ode documentation for two moving colliding TriMeshES in Odejava ?

mmh - yes it only works for normal TriangleArrays, if you want it to work also for IndexedTriangleArrays, simply add another if-block, where you transform the Xith representation to the ODEJava rep. I just was lucky, because I was able to use the predifined function in Xith3DToOdejava

I don’t know, but I had only issues with textures and stuff using the OBJLoader, but, because only the geom data is needed, it might work. (I actually I have no experience with exporting .OBJ from Maya, so it could be a problem)

Arne

you were too fast with your answer…I had to modify my previous post a little. but thanks for the info.

TriMesh collisions in ODEJava has always been tricky. We will try to do better for JOODE… or maybe implements complex shapes with another method…

For a WTF moment of the week, I present you this: source

There are two files: SimpleExample.java and MeshBody.java .
If you have Xith3D and Odejava installed, you shouldn’t have problems
compiling and running it. I also included the kiostudios loader for your convenience.

It’s a TriMesh Cube colliding with a GeomBox. Now what’s the big deal? Take a closer
look at MeshBody.java and its constructor and try to move that line:


public MeshBody(World world) {
        // TRY MOVING THIS LINE BENEATH THE TRY BLOCK. WTF!?!
        body = new Body("myBody" + ++count, world);
        
        Hashtable ht = null;
        try{
            if (new java.io.File(".\\obj").exists())
                ht = ((TDSModel)(
                    new Loader3DS().load(".\\obj\\cube.3DS"))).getNamedObjects();
            else System.exit(1);
        } catch(IOException e){}
        Enumeration en = ht.keys();
        
        //LIKE HERE FOR EXAMPLE ***************************
        //body = new Body("myBody" + ++count, world);

        while(en.hasMoreElements()){
            String key = (String)en.nextElement();
            System.out.println("Loading shape: " + key);
            if (!(ht.get(key) instanceof TransformGroup)) continue;
            tg = (TransformGroup)ht.get(key);
            tg.removeFromParentGroup();
            Shape3D s3d = (Shape3D)tg.getChild(0);
            s3d.setAppearance(initApp());
            IndexedTriangleArray ita = (IndexedTriangleArray)s3d.getGeometry();
            body.addGeom(new GeomTriMesh(
                "myBounds" + count, ita.getCoordRefFloat(), ita.getIndex()));
            body.adjustMass(1f);
            break;
        }
    }

First it works, then it doesn’t and the Cube falls through the Box. Am I going crazy?

Not sure what’s happening but I have also found that the order of statements matters a lot with ODE.

Will.

(We should really avoid that in JOODE. Maybe because it’s OO we won’t have this problem at all…)

Good idea arne. canyou modify them so they return raw geometry instead of xith nodes ?

It should be included in one of the libs of the gamma project. Really.

Heah ??? I don’t that. I don’t return Xith-nodes. I use Xith-nodes for input.

Actually it belongs to ODEJava.
+If you haven’t deleted it (which I believe you did) then it would be in the gamma project already. (Like my terrainloader)
But - didn’t you say you don’t want to use ODEJava?

I think that “Loaders” and “Converters between raw geometry and ODEJava geometry” should be separated. So the loaders don’t belongs to ODEJava (IMHO).
I haven’t deleted anything, I just changed of server :slight_smile: We could add generic loaders one of these days.
And you’re right, I still don’t want to use ODEJava. JOODE why not.

OK didnt know, but I mean so they returned general stuff ? like indexed geometry in a float array and a int array. Or similar with stripified geometry.
The big job with loaders are to parse the files, I think it would be a shame to limit all that work to a single 3d library…
They OBJ loader from sun is insane… it just returns a java 3d scene object, theres no way you can get the geometry (unless you download their code and modify it…like I did he he )

I think arne uses the Xith loaders and just convert the nodes to an ODEJava geometry.