|
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 |
