I am currently in the process of implementing a simple model viewer. I am having some trouble with coding a .obj loader(taking a input model and passing it to my jogl code to draw to my canvas). I have found an existing loader in one of the jogl demo's but i am unsure on how to incorporate it into my own program. I was just wondering if any of you gurus had any tips on writing a .obj loader (or getting the loader from the shadow(i think) demo) and then applying a texture if needed?
Thanks in advance |
Administrator
|
U may have a look at my port of the .obj loader from JGL-Mark for JOGL2: WavefrontObjectLoader_DisplayList.java
The class has a convenience method loadWavefrontObjectAsDisplayList(GL2 inGL,String inFileName) wich returns a display list id to be used out-of-the-box in ur code. Guess this class is as easy as it gets ... |
Administrator
|
> ... and then applying a texture if needed?
Ah and btw: For a complete demo of using the .obj loader class in conjunction with a uv-unwrapped, textured polygon exported from Blender u may have a look here GL2_UVUnwrap.java |
Thank you for the helpful reply Demoscene Passivist! However, the first link does not work :(
Also, how easy would it be to change the code to work with pre-JOGL2 as i started this program a few months before JOGL2 was released..... |
Administrator
|
Ups, sorry here is the correct link: WavefrontObjectLoader_DisplayList.java
>Also, how easy would it be to change the code to work with pre-JOGL2 as i started >this program a few months before JOGL2 was released..... It should be very easy to do so as u mainly have to change the imports and remove the GLProfile stuff. The original source from JGL-Mark was JOGL1, but unfortunately the site https://jglmark.dev.java.net/ is offline since Oracle more or less killed java.net. Anyway u are lucky that in my ongoing mission to backup the whole internet I also came by to stop at jglmark . The original version is missing the display list feature, and also can't load compressed models but I guess u can easily backport that functionality from my extended version. So here we go with the original JOGL1 version from jglmark.dev.java.net: package OpenGL.JOGL.loaders.obj; import com.sun.opengl.util.BufferUtil; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.util.ArrayList; import javax.media.opengl.GL; /* * OBJModel.java * Created on June 3, 2006, 11:44 AM */ /** * @author Chris "Crash0veride007" Brown * crash0veride007@gmail.com * https://jglmark.dev.java.net/ */ public class OBJModel { private String OBJModelPath; // The path to the Model File private ArrayList vData = new ArrayList(); // List of Vertex Coordinates private ArrayList vtData = new ArrayList(); // List of Texture Coordinates private ArrayList vnData = new ArrayList(); // List of Normal Coordinates private ArrayList fv = new ArrayList(); // Face Vertex Indices private ArrayList ft = new ArrayList(); // Face Texture Indices private ArrayList fn = new ArrayList(); // Face Normal Indices private FloatBuffer modeldata; // Buffer which will contain vertice data private int FaceFormat; // Format of the Faces Triangles or Quads private int FaceMultiplier; // Number of possible coordinates per face private int PolyCount = 0; // The Models Polygon Count private boolean init = true; public OBJModel(String Modelpath) { OBJModelPath = Modelpath; LoadOBJModel(OBJModelPath); SetFaceRenderType(); } private void LoadOBJModel(String ModelPath) { try { // Open a file handle and read the models data BufferedReader br = new BufferedReader(new FileReader(ModelPath)); String line = null; while((line = br.readLine()) != null) { if (line.startsWith("#")) { // Read Any Descriptor Data in the File //System.out.println("Descriptor: "+line); //Uncomment to print out file descriptor data } else if (line.equals("")) { //Ignore whitespace data } else if (line.startsWith("v ")) { // Read in Vertex Data vData.add(ProcessData(line)); } else if (line.startsWith("vt ")) { // Read Texture Coordinates vtData.add(ProcessData(line)); } else if (line.startsWith("vn ")) { // Read Normal Coordinates vnData.add(ProcessData(line)); } else if (line.startsWith("f ")) { // Read Face Data ProcessfData(line); } } br.close(); } catch(IOException e) { System.out.println("Failed to find or read OBJ: " + ModelPath); System.err.println(e); } } private float[] ProcessData(String read) { final String s[] = read.split("\\s+"); return (ProcessFloatData(s)); //returns an array of processed float data } private float[] ProcessFloatData(String sdata[]) { float data[] = new float[sdata.length-1]; for (int loop=0; loop < data.length; loop++) { data[loop] = Float.parseFloat(sdata[loop+1]); } return data; // return an array of floats } private void ProcessfData(String fread) { PolyCount++; String s[] = fread.split("\\s+"); if (fread.contains("//")) { // Pattern is present if obj has only v and vn in face data for (int loop=1; loop < s.length; loop++) { s[loop] = s[loop].replaceAll("//","/0/"); //insert a zero for missing vt data } } ProcessfIntData(s); // Pass in face data } private void ProcessfIntData(String sdata[]) { int vdata[] = new int[sdata.length-1]; int vtdata[] = new int[sdata.length-1]; int vndata[] = new int[sdata.length-1]; for (int loop = 1; loop < sdata.length; loop++) { String s = sdata[loop]; String[] temp = s.split("/"); vdata[loop-1] = Integer.valueOf(temp[0]); //always add vertex indices if (temp.length > 1) { // we have v and vt data vtdata[loop-1] = Integer.valueOf(temp[1]); // add in vt indices } else { vtdata[loop-1] = 0; // if no vt data is present fill in zeros } if (temp.length > 2) { // we have v, vt, and vn data vndata[loop-1] = Integer.valueOf(temp[2]); // add in vn indices } else { vndata[loop-1] = 0; //if no vn data is present fill in zeros } } fv.add(vdata); ft.add(vtdata); fn.add(vndata); } private void SetFaceRenderType() { final int temp [] = (int[]) fv.get(0); if ( temp.length == 3) { FaceFormat = GL.GL_TRIANGLES; // The faces come in sets of 3 so we have triangular faces FaceMultiplier = 3; } else if (temp.length == 4) { FaceFormat = GL.GL_QUADS; // The faces come in sets of 4 so we have quadrilateral faces FaceMultiplier = 4; } else { FaceFormat = GL.GL_POLYGON; // Fall back to render as free form polygons } } private void ConstructInterleavedArray(GL gl) { final int tv[] = (int[]) fv.get(0); final int tt[] = (int[]) ft.get(0); final int tn[] = (int[]) fn.get(0); // If a value of zero is found that it tells us we don't have that type of data if ((tv[0] != 0) && (tt[0] != 0) && (tn[0] != 0)) { ConstructTNV(); //We have Vertex, 2D Texture, and Normal Data gl.glInterleavedArrays(GL.GL_T2F_N3F_V3F, 0, modeldata); } else if ((tv[0] != 0) && (tt[0] != 0) && (tn[0] == 0)) { ConstructTV(); //We have just vertex and 2D texture Data gl.glInterleavedArrays(GL.GL_T2F_V3F, 0, modeldata); } else if ((tv[0] != 0) && (tt[0] == 0) && (tn[0] != 0)) { ConstructNV(); //We have just vertex and normal Data gl.glInterleavedArrays(GL.GL_N3F_V3F, 0, modeldata); } else if ((tv[0] != 0) && (tt[0] == 0) && (tn[0] == 0)) { ConstructV(); gl.glInterleavedArrays(GL.GL_V3F, 0, modeldata); } } private void ConstructTNV() { int[] v, t, n; float tcoords[] = new float[2]; //Only T2F is supported in InterLeavedArrays!! float coords[] = new float[3]; int fbSize= PolyCount*(FaceMultiplier*8); // 3v Per Poly, 2vt Per Poly, 3vn Per Poly modeldata = BufferUtil.newFloatBuffer(fbSize); modeldata.position(0); for (int oloop=0; oloop < fv.size(); oloop++) { v = (int[])(fv.get(oloop)); t = (int[])(ft.get(oloop)); n = (int[])(fn.get(oloop)); for (int iloop=0; iloop < v.length; iloop++) { // Fill in the texture coordinate data for (int tloop=0; tloop < tcoords.length; tloop++) //Only T2F is supported in InterLeavedArrays!! tcoords[tloop] = ((float[])vtData.get(t[iloop] - 1))[tloop]; modeldata.put(tcoords); // Fill in the normal coordinate data for (int vnloop=0; vnloop < coords.length; vnloop++) coords[vnloop] = ((float[])vnData.get(n[iloop] - 1))[vnloop]; modeldata.put(coords); // Fill in the vertex coordinate data for (int vloop=0; vloop < coords.length; vloop++) coords[vloop] = ((float[])vData.get(v[iloop] - 1))[vloop]; modeldata.put(coords); } } modeldata.position(0); } private void ConstructTV() { int[] v, t; float tcoords[] = new float[2]; //Only T2F is supported in InterLeavedArrays!! float coords[] = new float[3]; int fbSize= PolyCount*(FaceMultiplier*5); // 3v Per Poly, 2vt Per Poly modeldata = BufferUtil.newFloatBuffer(fbSize); modeldata.position(0); for (int oloop=0; oloop < fv.size(); oloop++) { v = (int[])(fv.get(oloop)); t = (int[])(ft.get(oloop)); for (int iloop=0; iloop < v.length; iloop++) { // Fill in the texture coordinate data for (int tloop=0; tloop < tcoords.length; tloop++) //Only T2F is supported in InterLeavedArrays!! tcoords[tloop] = ((float[])vtData.get(t[iloop] - 1))[tloop]; modeldata.put(tcoords); // Fill in the vertex coordinate data for (int vloop=0; vloop < coords.length; vloop++) coords[vloop] = ((float[])vData.get(v[iloop] - 1))[vloop]; modeldata.put(coords); } } modeldata.position(0); } private void ConstructNV() { int[] v, n; float coords[] = new float[3]; int fbSize= PolyCount*(FaceMultiplier*6); // 3v Per Poly, 3vn Per Poly modeldata = BufferUtil.newFloatBuffer(fbSize); modeldata.position(0); for (int oloop=0; oloop < fv.size(); oloop++) { v = (int[])(fv.get(oloop)); n = (int[])(fn.get(oloop)); for (int iloop=0; iloop < v.length; iloop++) { // Fill in the normal coordinate data for (int vnloop=0; vnloop < coords.length; vnloop++) coords[vnloop] = ((float[])vnData.get(n[iloop] - 1))[vnloop]; modeldata.put(coords); // Fill in the vertex coordinate data for (int vloop=0; vloop < coords.length; vloop++) coords[vloop] = ((float[])vData.get(v[iloop] - 1))[vloop]; modeldata.put(coords); } } modeldata.position(0); } private void ConstructV() { int[] v; float coords[] = new float[3]; int fbSize= PolyCount*(FaceMultiplier*3); // 3v Per Poly modeldata = BufferUtil.newFloatBuffer(fbSize); modeldata.position(0); for (int oloop=0; oloop < fv.size(); oloop++) { v = (int[])(fv.get(oloop)); for (int iloop=0; iloop < v.length; iloop++) { // Fill in the vertex coordinate data for (int vloop=0; vloop < coords.length; vloop++) coords[vloop] = ((float[])vData.get(v[iloop] - 1))[vloop]; modeldata.put(coords); } } modeldata.position(0); } public void DrawModel(GL gl) { if (init) { ConstructInterleavedArray(gl); cleanup(); init = false; } gl.glEnable(GL.GL_CULL_FACE); gl.glCullFace(GL.GL_BACK); gl.glPolygonMode(GL.GL_FRONT,GL.GL_LINE); gl.glDrawArrays(FaceFormat, 0, PolyCount*FaceMultiplier); gl.glDisable(GL.GL_CULL_FACE); } public String Polycount() { String pc = Integer.toString(PolyCount); return pc; } private void cleanup() { vData.clear(); vtData.clear(); vnData.clear(); fv.clear(); ft.clear(); fn.clear(); modeldata.clear(); System.gc(); } } |
Hi there,
I saw your latest on the WavefrontObjectLoader_Displaylist.java I am wondering where i could get the library for "framework.base"? And how can I use the loadWavefrontObjectAsDisplayList method? Any quick sample help? Thanks |
Administrator
|
>I am wondering where i could get the library for "framework.base"?
The "framework.base" package is part of my JOGL2 development framework. U can download it from my github repository. Feel free to use/modify it >And how can I use the loadWavefrontObjectAsDisplayList method? For a simple example take a look at GL2_UVUnwrap.java. The usage comes down to only two lines: init+loading: int mDisplayListID = WavefrontObjectLoader_DisplayList.loadWavefrontObjectAsDisplayList(inGL,"/binaries/geometry/TextureBaking_Normals.wobj.zip"); and usage (every frame): inGL.glCallList(mDisplayListID); The repository/framework also contains a lot of other examples on what u can do with JOGL2. For a quick overview take a look at my youtube channel. |
I am trying to load the obj...
It did load but there's a problem... after loaded the obj file, it gives me this: POLYGON COUNT FOR MODEL=252 VERTEX COUNT FOR MODEL=236 TEXTURE COORDINATE COUNT FOR MODEL=292 NORMAL COUNT FOR MODEL=275 Exception in thread "AWT-EventQueue-0" java.nio.BufferOverflowException at java.nio.DirectFloatBufferU.put(Unknown Source) at java.nio.FloatBuffer.put(Unknown Source) at prac4.WavefrontObjectLoader_DisplayList.ConstructTNV(WavefrontObjectLoader_DisplayList.java:203) at prac4.WavefrontObjectLoader_DisplayList.ConstructInterleavedArray(WavefrontObjectLoader_DisplayList.java:173) at prac4.WavefrontObjectLoader_DisplayList.drawModel(WavefrontObjectLoader_DisplayList.java:285) at prac4.WavefrontObjectLoader_DisplayList.loadWavefrontObjectAsDisplayList(WavefrontObjectLoader_DisplayList.java:306) at prac4.Test.init(Test.java:120) at jogamp.opengl.GLDrawableHelper.init(GLDrawableHelper.java:155) at jogamp.opengl.GLDrawableHelper.init(GLDrawableHelper.java:175) at javax.media.opengl.awt.GLCanvas$InitAction.run(GLCanvas.java:856) at jogamp.opengl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:356) at javax.media.opengl.awt.GLCanvas.maybeDoSingleThreadedWorkaround(GLCanvas.java:769) at javax.media.opengl.awt.GLCanvas.display(GLCanvas.java:388) at javax.media.opengl.awt.GLCanvas.paint(GLCanvas.java:487) at sun.awt.RepaintArea.paintComponent(Unknown Source) at sun.awt.RepaintArea.paint(Unknown Source) at sun.awt.windows.WComponentPeer.handleEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.EventQueue.dispatchEventImpl(Unknown Source) at java.awt.EventQueue.access$000(Unknown Source) at java.awt.EventQueue$1.run(Unknown Source) at java.awt.EventQueue$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source) at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue$2.run(Unknown Source) at java.awt.EventQueue$2.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source) |
One more question, if i don't wish to use
framework.base framework.util how can i modify the GL2_UnWrap.java to make it work for the texture? :( |
Administrator
|
In reply to this post by diskhub
>It did load but there's a problem...
>after loaded the obj file, >it gives me this: Vertex and normal count have to be multiple of 3 or 4. So usually u have to triangulate the model while exporting. I normally use Blender for Wavefront export, wich has an option to triangulate the model. |
Administrator
|
In reply to this post by diskhub
>One more question, if i don't wish to use framework.base framework.util
>how can i modify the GL2_UnWrap.java to make it work for the texture? :( If u don't wanna use my framework, then simply wrap the init, mainloop and cleanup of GL2_UnWrap into the corresponding methods of a GLEventListener and inline the utility methods for texture loading. They are not that much code, son inlining them would be ok I guess. |
In reply to this post by Demoscene Passivist
hello,
i had pull your code ,and found that the code has err in : framework.base.BaseGlobalEnvironment.java 's line 50 : private float mParameterKey_FLOAT_LÖ; 第50行有乱码! 谢谢!
你们好!
很高兴跟大家一起学习JOGL |
Free forum by Nabble | Edit this page |