|
elias4444
|
 |
« on: January 26, 2005, 16:13:05 » |
|
I know you guys are probably tired of my constant questions, but is there a way to load an OBJ file, other than having to write my own loader/translator for the file format?
|
|
|
|
|
Logged
|
|
|
|
funsheep
Newbie

Posts: 11
|
 |
« Reply #1 on: January 26, 2005, 16:24:10 » |
|
you will probably have your own datastructure to represent 3d models, so you will have to write an specific obj loader. you should adapt one of the various loader tutorials on the web. some are collected here: http://www.j3d.org/utilities/loaders.html
|
|
|
|
|
Logged
|
|
|
|
|
|
|
elias4444
|
 |
« Reply #3 on: January 27, 2005, 13:59:21 » |
|
OK.... Here it is. This is crude... this is uncommented... this has got to be some of the craziest and ugliest coding I've ever done. BUT, I've wanted to find a way to say thank you to those on the board for all their help... SO, here's my simple object loader. It loads and assists in drawing .obj files. I can't guarantee anything, but it's worked for me on every obj file I've thrown at it so far. It supports coordinates, normals, and texture coordinates. Please be kind, as this has taken me all day to program (mostly trying to decipher the obj spec), and I'm too tired to go back through and clean-up/optimize it right now. Feel free to delete all the System.out.println commands.  **Updated: August 8, 2005 Notice that now you pass a BufferedReader object into the class. This way you can handle your own file loading and error routines on a per program basis. /* * Modified on August 8, 2005 */ package tools;
import java.io.BufferedReader; import java.io.IOException; import java.util.ArrayList;
import org.lwjgl.opengl.GL11;
/** * @author Jeremy Adams (elias4444) * * Use these lines if reading from a file * FileReader fr = new FileReader(ref); * BufferedReader br = new BufferedReader(fr);
* Use these lines if reading from within a jar * InputStreamReader fr = new InputStreamReader(new BufferedInputStream(getClass().getClassLoader().getResourceAsStream(ref))); * BufferedReader br = new BufferedReader(fr); */
public class Object3D { private ArrayList vertexsets = new ArrayList(); // Vertex Coordinates private ArrayList vertexsetsnorms = new ArrayList(); // Vertex Coordinates Normals private ArrayList vertexsetstexs = new ArrayList(); // Vertex Coordinates Textures private ArrayList faces = new ArrayList(); // Array of Faces (vertex sets) private ArrayList facestexs = new ArrayList(); // Array of of Faces textures private ArrayList facesnorms = new ArrayList(); // Array of Faces normals private int objectlist; private int numpolys = 0; //// Statisitcs for drawing //// public float toppoint = 0; // y+ public float bottompoint = 0; // y- public float leftpoint = 0; // x- public float rightpoint = 0; // x+ public float farpoint = 0; // z- public float nearpoint = 0; // z+ public Object3D(BufferedReader ref, boolean centerit) { loadobject(ref); if (centerit) { centerit(); } opengldrawtolist(); numpolys = faces.size(); cleanup(); } private void cleanup() { vertexsets.clear(); vertexsetsnorms.clear(); vertexsetstexs.clear(); faces.clear(); facestexs.clear(); facesnorms.clear(); } private void loadobject(BufferedReader br) { int linecounter = 0; try { String newline; boolean firstpass = true; while (((newline = br.readLine()) != null)) { linecounter++; newline = newline.trim(); if (newline.length() > 0) { if (newline.charAt(0) == 'v' && newline.charAt(1) == ' ') { float[] coords = new float[4]; String[] coordstext = new String[4]; coordstext = newline.split("\\s+"); for (int i = 1;i < coordstext.length;i++) { coords[i-1] = Float.valueOf(coordstext[i]).floatValue(); } //// check for farpoints //// if (firstpass) { rightpoint = coords[0]; leftpoint = coords[0]; toppoint = coords[1]; bottompoint = coords[1]; nearpoint = coords[2]; farpoint = coords[2]; firstpass = false; } if (coords[0] > rightpoint) { rightpoint = coords[0]; } if (coords[0] < leftpoint) { leftpoint = coords[0]; } if (coords[1] > toppoint) { toppoint = coords[1]; } if (coords[1] < bottompoint) { bottompoint = coords[1]; } if (coords[2] > nearpoint) { nearpoint = coords[2]; } if (coords[2] < farpoint) { farpoint = coords[2]; } ///////////////////////////// vertexsets.add(coords); } if (newline.charAt(0) == 'v' && newline.charAt(1) == 't') { float[] coords = new float[4]; String[] coordstext = new String[4]; coordstext = newline.split("\\s+"); for (int i = 1;i < coordstext.length;i++) { coords[i-1] = Float.valueOf(coordstext[i]).floatValue(); } vertexsetstexs.add(coords); } if (newline.charAt(0) == 'v' && newline.charAt(1) == 'n') { float[] coords = new float[4]; String[] coordstext = new String[4]; coordstext = newline.split("\\s+"); for (int i = 1;i < coordstext.length;i++) { coords[i-1] = Float.valueOf(coordstext[i]).floatValue(); } vertexsetsnorms.add(coords); } if (newline.charAt(0) == 'f' && newline.charAt(1) == ' ') { String[] coordstext = newline.split("\\s+"); int[] v = new int[coordstext.length - 1]; int[] vt = new int[coordstext.length - 1]; int[] vn = new int[coordstext.length - 1]; for (int i = 1;i < coordstext.length;i++) { String fixstring = coordstext[i].replaceAll("//","/0/"); String[] tempstring = fixstring.split("/"); v[i-1] = Integer.valueOf(tempstring[0]).intValue(); if (tempstring.length > 1) { vt[i-1] = Integer.valueOf(tempstring[1]).intValue(); } else { vt[i-1] = 0; } if (tempstring.length > 2) { vn[i-1] = Integer.valueOf(tempstring[2]).intValue(); } else { vn[i-1] = 0; } } faces.add(v); facestexs.add(vt); facesnorms.add(vn); } } } } catch (IOException e) { System.out.println("Failed to read file: " + br.toString()); //System.exit(0); } catch (NumberFormatException e) { System.out.println("Malformed OBJ (on line " + linecounter + "): " + br.toString() + "\r \r" + e.getMessage()); //System.exit(0); } } private void centerit() { float xshift = (rightpoint-leftpoint) /2f; float yshift = (toppoint - bottompoint) /2f; float zshift = (nearpoint - farpoint) /2f; for (int i=0; i < vertexsets.size(); i++) { float[] coords = new float[4]; coords[0] = ((float[])(vertexsets.get(i)))[0] - leftpoint - xshift; coords[1] = ((float[])(vertexsets.get(i)))[1] - bottompoint - yshift; coords[2] = ((float[])(vertexsets.get(i)))[2] - farpoint - zshift; vertexsets.set(i,coords); // = coords; } } public float getXWidth() { float returnval = 0; returnval = rightpoint - leftpoint; return returnval; } public float getYHeight() { float returnval = 0; returnval = toppoint - bottompoint; return returnval; } public float getZDepth() { float returnval = 0; returnval = nearpoint - farpoint; return returnval; } public int numpolygons() { return numpolys; } public void opengldrawtolist() { this.objectlist = GL11.glGenLists(1); GL11.glNewList(objectlist,GL11.GL_COMPILE); for (int i=0;i<faces.size();i++) { int[] tempfaces = (int[])(faces.get(i)); int[] tempfacesnorms = (int[])(facesnorms.get(i)); int[] tempfacestexs = (int[])(facestexs.get(i)); //// Quad Begin Header //// int polytype; if (tempfaces.length == 3) { polytype = GL11.GL_TRIANGLES; } else if (tempfaces.length == 4) { polytype = GL11.GL_QUADS; } else { polytype = GL11.GL_POLYGON; } GL11.glBegin(polytype); //////////////////////////// for (int w=0;w<tempfaces.length;w++) { if (tempfacesnorms[w] != 0) { float normtempx = ((float[])vertexsetsnorms.get(tempfacesnorms[w] - 1))[0]; float normtempy = ((float[])vertexsetsnorms.get(tempfacesnorms[w] - 1))[1]; float normtempz = ((float[])vertexsetsnorms.get(tempfacesnorms[w] - 1))[2]; GL11.glNormal3f(normtempx, normtempy, normtempz); } if (tempfacestexs[w] != 0) { float textempx = ((float[])vertexsetstexs.get(tempfacestexs[w] - 1))[0]; float textempy = ((float[])vertexsetstexs.get(tempfacestexs[w] - 1))[1]; float textempz = ((float[])vertexsetstexs.get(tempfacestexs[w] - 1))[2]; GL11.glTexCoord3f(textempx,1f-textempy,textempz); } float tempx = ((float[])vertexsets.get(tempfaces[w] - 1))[0]; float tempy = ((float[])vertexsets.get(tempfaces[w] - 1))[1]; float tempz = ((float[])vertexsets.get(tempfaces[w] - 1))[2]; GL11.glVertex3f(tempx,tempy,tempz); } //// Quad End Footer ///// GL11.glEnd(); /////////////////////////// } GL11.glEndList(); } public void opengldraw() { GL11.glCallList(objectlist); } }
|
|
|
|
|
Logged
|
|
|
|
funsheep
Newbie

Posts: 11
|
 |
« Reply #4 on: January 28, 2005, 00:30:01 » |
|
we are also using obj files. and it had turned out, that in java 1.4 the switch case blocks are for such things faster than the if then else if then else ... statements. and when you are going to read mtl files there are several commands, beginning with the same character, what do you do then? ok: use switch case blocks to determine the first character and than proove with if else statements which command it is  happy hacking
|
|
|
|
|
Logged
|
|
|
|
|
elias4444
|
 |
« Reply #5 on: January 28, 2005, 07:53:24 » |
|
I'm actually not too worried about the if-then statements. They're primarily used in the loading sequence, which I traditionally do before the game actually begins. The drawing sequence doesn't seem to be effected as much as the information is already in memory and is simply looped through.
|
|
|
|
|
Logged
|
|
|
|
|
|
|
elias4444
|
 |
« Reply #7 on: February 07, 2005, 21:06:17 » |
|
Right... make sure you grab the code again from the previous post (I've updated it a couple of times). I hadn't done anything with textures, so I didn't realize I was setting the texture coordinates out of order. It seems to work now with just about everything I've thrown at it (including custom objects exported from Maya). Keep in mind though, I'm only using faces (no curves or anything yet - I just don't know how to do those in openGL yet). BTW, that's a cool p51 model. 
|
|
|
|
|
Logged
|
|
|
|
|
elias4444
|
 |
« Reply #8 on: February 07, 2005, 21:33:38 » |
|
Here's a site with some fun free objects to test with: http://o.ffrench.free.fr/meshbank/Also for fun, I've made what I call a "texture tester" for the guy doing my 3D graphics for me. Feel free to use it (whenever my webserver is actually up): http://www.tommytwisters.com/texture/texture.jnlpTo use it, find the "tommytwisters" folder under your user directory (on windows - c:\documents and settings\userid\tommytwisters\), and drop in an object file named "object.obj" and a texture file named "texture.png" (you can use other image types, but it must be named "texture.png" - even if it's a gif or something) to see what it looks like. It'll tell you how many faces the object has and a simple FPS benchmark for it. Also, you can use the following keys for testing: L = turn dynamic lighting on and off S = turn spheremapping on and off R = lock the light to the camera position (and unlock) I = "zoom in" = scale your object larger O = "zoom out" = scale your object smaller T,F,G,H = move the object around. Arrow Keys = move the camera around. It uses my most up-to-date version of the object reader code above. I also experienced missing triangles, but it turned out to be an older version of my code and the way I had the texture mapping setup. It seems to be fixed now.
|
|
|
|
|
Logged
|
|
|
|
|
napier
|
 |
« Reply #9 on: February 08, 2005, 19:25:16 » |
|
Hmmm..... I grabbed the most recent code above but get the same result (several triangles are missing). The model has verts, normals and faces. It also has smoothing groups (I thing that's what 'g' and 's' are about). Maybe that's related. BTW, that's a cool p51 model. I'd love to take credit but can't. I found it on the web, I think it's part of the Java 3D demos. If it was my own I'd be more suspicious that I screwed up the model and that's what's causing render problems Anyhoo I can't debug for two days or so. If you do get to it let me know and I'll test. BTW Thanks for the loader!
|
|
|
|
|
Logged
|
|
|
|
|
elias4444
|
 |
« Reply #10 on: February 09, 2005, 10:26:17 » |
|
I'm noticing some missing triangles in the cockpit windshield for the model, although I'm not sure it's a bug in my code (although it could be that the object file is using something I haven't implemented yet). Are you having problems with any other models? I've been downloading some pretty complex models from the web and haven't found any with the same problem yet.
I'll have a friend load it into Maya and see what he gets.
|
|
|
|
|
Logged
|
|
|
|
|
elias4444
|
 |
« Reply #11 on: February 09, 2005, 11:27:16 » |
|
Mmmm... Yummy humble pie!!!
Yep, I left a line out of my code up there. It should work just fine for you now.
|
|
|
|
|
Logged
|
|
|
|
|
napier
|
 |
« Reply #12 on: February 09, 2005, 20:54:21 » |
|
Very cool. Now it works.
Thanks!
|
|
|
|
|
Logged
|
|
|
|
|
elias4444
|
 |
« Reply #13 on: March 11, 2005, 07:23:24 » |
|
Figured I better point out that I updated the code (posted above). It's about 30% faster now. I convert the arraylists to arrays in order to avoid casting everything on every draw. Also, the constructor now supports a boolean variable that specifies whether you want the object automatically centered around an origin or not. There's also some extra functions to get the different dimensions and number of polygons used.
Hope that helps!
|
|
|
|
|
Logged
|
|
|
|
|
elias4444
|
 |
« Reply #14 on: March 14, 2005, 11:30:25 » |
|
Well, the joy keeps coming with this one... I just implemented genlists... with a 35,000 face count, I went from 35fps to 120+ fps in my tester app. Enjoy the upgrade!
|
|
|
|
|
Logged
|
|
|
|
|