Android Opengl .Obj File Loader

Android OpenGL .OBJ file loader

You asked this a while back but I have a good solution if you are still looking.

Instead of loading an obj file, you can easily convert it into arrays for the vertices, normals and texture coordinates. There's a tool which converts obj files to c header files. You can convert the output to work with java afterwards. It shouldn't be hard.

http://www.heikobehrens.net/2009/08/27/obj2opengl/

This solution is easy, the header files wont add much space in source code than the obj files and the data will be more compact when compiled, it's very fast since you have the data there ready to render straight away, it can convert texture coordinates and you don't need to worry about using it for your commercial products.

How to load and display .obj file in Android with OpenGL-ES 2

I ended up writing a new parser, it can be used like this to build FloatBuffers to use in your Renderer:

ObjLoader objLoader = new ObjLoader(context, "Mug.obj");

numFaces = objLoader.numFaces;

// Initialize the buffers.
positions = ByteBuffer.allocateDirect(objLoader.positions.length * mBytesPerFloat)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
positions.put(objLoader.positions).position(0);

normals = ByteBuffer.allocateDirect(objLoader.normals.length * mBytesPerFloat)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
normals.put(objLoader.normals).position(0);

textureCoordinates = ByteBuffer.allocateDirect(objLoader.textureCoordinates.length * mBytesPerFloat)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
textureCoordinates.put(objLoader.textureCoordinates).position(0);

and here's the parser:

public final class ObjLoader {

public final int numFaces;

public final float[] normals;
public final float[] textureCoordinates;
public final float[] positions;

public ObjLoader(Context context, String file) {

Vector<Float> vertices = new Vector<>();
Vector<Float> normals = new Vector<>();
Vector<Float> textures = new Vector<>();
Vector<String> faces = new Vector<>();

BufferedReader reader = null;
try {
InputStreamReader in = new InputStreamReader(context.getAssets().open(file));
reader = new BufferedReader(in);

// read file until EOF
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split(" ");
switch (parts[0]) {
case "v":
// vertices
vertices.add(Float.valueOf(parts[1]));
vertices.add(Float.valueOf(parts[2]));
vertices.add(Float.valueOf(parts[3]));
break;
case "vt":
// textures
textures.add(Float.valueOf(parts[1]));
textures.add(Float.valueOf(parts[2]));
break;
case "vn":
// normals
normals.add(Float.valueOf(parts[1]));
normals.add(Float.valueOf(parts[2]));
normals.add(Float.valueOf(parts[3]));
break;
case "f":
// faces: vertex/texture/normal
faces.add(parts[1]);
faces.add(parts[2]);
faces.add(parts[3]);
break;
}
}
} catch (IOException e) {
// cannot load or read file
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
//log the exception
}
}
}

numFaces = faces.size();
this.normals = new float[numFaces * 3];
textureCoordinates = new float[numFaces * 2];
positions = new float[numFaces * 3];
int positionIndex = 0;
int normalIndex = 0;
int textureIndex = 0;
for (String face : faces) {
String[] parts = face.split("/");

int index = 3 * (Short.valueOf(parts[0]) - 1);
positions[positionIndex++] = vertices.get(index++);
positions[positionIndex++] = vertices.get(index++);
positions[positionIndex++] = vertices.get(index);

index = 2 * (Short.valueOf(parts[1]) - 1);
textureCoordinates[normalIndex++] = textures.get(index++);
// NOTE: Bitmap gets y-inverted
textureCoordinates[normalIndex++] = 1 - textures.get(index);

index = 3 * (Short.valueOf(parts[2]) - 1);
this.normals[textureIndex++] = normals.get(index++);
this.normals[textureIndex++] = normals.get(index++);
this.normals[textureIndex++] = normals.get(index);
}
}
}

How can an .obj file be converted to Android openGL?

You essentially have 3 options:

  1. Adopt the use of a comprehensive framework that contains model loading capabilites like Min3D , Bonzai or Rajawali. (There is a metric ton of these frameworks) Personally, I prefer Min3D as it imposes the most minimal constraints on your application design and it is has been use tested more heavily than most of the alternatives. A good tutorial for loading models with Min3D can be found here.

  2. Use a standalone model loader written for Android in Java like this one. Licence is GPL if I am remembering correctly and interaction with it's API is fairly trivial.

  3. Write your own model loader! OBJ is just about the simplest file format in existence to parse and it would only take an hour or two to construct your own custom loader. This avenue will alleviate any licensing concerns you may have and, if you are new to 3D rendering, it may serve as a helpful exercise.

OBJ Loader, texture binding and texture buffers

So, in OpenGL a vertex is whatever combination of information describes a particular point on the model. You're using the old fixed pipeline so a vertex is one or more of a location, some texture coordinates, a normal and a colour.

In OBJ a vt is only a location. The thing that maps to the OpenGL concept of a vertex is each unique combination of — in your case — location + texture coordinate pairs given after an f.

You need a mapping whereby if the f says 56/92 then you can lookup the 56/92 and find out that you consider that to be, say, vertex 23 and have communicated suitable arrays to OpenGL such that the location value in slot 23 was the 56th thing the OBJ gave as a v and the 92nd thing it gave as a vt.

Putting it another way, OBJ files have an extra level of indirection that OpenGL does not.

It looks to me like you're not resolving that difference. A common approach would be to use a HashMap from v/vt pair to output index, building your output arrays on demand as you parse the f.



Related Topics



Leave a reply



Submit