Tuesday, December 5, 2017

Simple Wavefront .OBJ Model Loader in JOGL

Wavefront .OBJ files are the most simplest of models that can be loaded into OpenGL. I have loaded some simple files and it has worked well. Im still working on other files containing negative vertex indexes.

This is an image of an elephant and a college visualized in a model mentioned in this site=> http://netization.blogspot.in/2014/10/loading-obj-files-in-opengl.html

On request I have texture mapped a custom texture to the elephant body(Chess board pattern)





If you are interested in the .OBJ model file format it is a simple text based model. It does not use any compression in storing the vertices or their relations. Hence this file format is human readable to some extent and editable to a fair degree of control. I am reproducing some text describing the format from an E-Book by David J Eck(without permission of course).
Wavefront .OBJ file format:
For complex shapes that are not described by any simple mathematical formula, it’s not feasible to generate the shape using Java code. We need a way to import shape data into our programs from other sources. The data might be generated by physical measurement, for example, or by an interactive 3D modeling program such as Blender (http://www.blender.org). To make this possible, one program must write data in a format that can be read by another program. The two programs need to use the same graphics file format. One of the most common file formats for the exchange of polygonal mesh data is the Wavefront OBJ file format. Although the official file format can store other types of geometric data, such as Bezier curves, it is mostly used for polygons, and that’s the only use that we will consider here.
An OBJ file (with file extension “.obj”) can store the data for an indexed face set, plus normal vectors and texture coordinates for each vertex. The data is stored as plain, human-readable text, using a simple format. Lines that begin with “v”, “vn”, “vt”, or “f”, followed by a space, contain data for one vertex, one normal vector, one set of texture coordinates, or one face, respectively. For our purposes here, other lines can be ignored. A line that specifies a vertex has the form
v x y z
where x, y, and z are numeric constants giving the coordinates of the vertex. For example:
v 0.707 -0.707 1
Four numbers, specifying homogeneous coordinates, are also legal but, I believe, rarely used. All the “v” lines in the file are considered to be part of one big list of vertices, and the vertices are assigned indices based on their position in the list. The indices start at one not zero, so vertex 1 is the vertex specified by the first “v” line in the file, vertex 2 is specified by the second “v” line, and so on. Note that there can be other types of lines interspersed among the “v” lines—those extra lines are not counted when computing the index of a vertex.
Lines starting with “vn” or “vt” work very similarly. Each “vn” line specifies a normal vector, given by three numbers. Normal vectors are not required to be unit vectors. All the “vn” lines in the file are considered to be part of one list of normal vectors, and normal vectors are assigned indices based on their order in the list. A “vt” line defines texture coordinates with one, two, or three numbers. (Two numbers would be used for 2D image textures.) All the “vt” lines in the file create a list of texture coordinates, which can be referenced by their indices in the list.
Faces are more complicated. Each “f” line defines one face, that is, one polygon. The data on the “f” line must give the list of vertices for the face. The data can also assign a normal vector and texture coordinates to each vertex. Vertices, texture coordinates, and normals are referred to by giving their indices in the respective lists. (Remember that the numbering starts from one, not from zero; if you’ve stored the data in Java arrays, you have to subtract 1 from the numbers given in the “f” line to get the correct array indices. There reference numbers can be negative. A negative index in an “f” line means to count backwards from the position of the “f” line in the file. For example, a vertex index of −1 refers to the “v” line that was seen most recently in the file, before encountering the “f” line; a vertex index of −2 refers the “v” line that precedes that one, an so on. If you are reading the file sequentially and storing data in arrays as you go, then −1 simply refers to the last item that is currently in the array, −2 refers to the next-to-last item, and so on.)
In the simple case, where there are no normals or texture coordinates, an “f” line can simply list the vertex indices in order. For example, an OBJ file for the pyramid example from the previous subsection could look like this:
v 1 0 1
v 1 0 -1
v -1 0 -1
v -1 0 1
v 0 1 0
f 5 4 1
f 5 1 2
f 5 2 3
f 5 3 4
f 1 4 3 2
When texture coordinate or normal data is included, a single vertex index such as “5” is replaced by a data element in the format v/t /n, where v is a vertex index, t is a texture coordinates index, and n is a normal coordinate index. The texture coordinates index can be left out, but the two slash characters must still be there. For example, “5/3/7” specifies vertex number 5, with texture coordinates number 3, and normal vector number 7. And “2//1” specifies vertex 2 with normal vector 7. As an example, here is complete OBJ file representing a cube, with its normal vectors, exactly as exported from Blender. Note that it contains additional data lines, which we want to ignore:
# Blender3D v248 OBJ File:
# www.blender3d.org
mtllib stage.mtl
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vn -0.000000 -1.000000 0.000000
vn 0.000000 1.000000 -0.000000
vn 1.000000 0.000000 0.000000
vn -0.000000 -0.000000 1.000000
vn -1.000000 -0.000000 -0.000000
vn 0.000000 0.000000 -1.000000
usemtl Material
s off
f 1//1 2//1 3//1 4//1
f 5//2 8//2 7//2 6//2
f 1//3 5//3 6//3 2//3
f 2//4 6//4 7//4 3//4
f 3//5 7//5 8//5 4//5
f 5//6 1//6 4//6 8//6

Once you have read a geometric object from an OBJ file and stored the data in arrays, it is easy enough to use the arrays to draw the object with OpenGL.

6 comments:

  1. Hi friend, i use Your code i try add textures to my object but i its not working... please help me!!
    i try this code: for(int i=0;i<face_count;i++)
    {
    if(usesnormals==1)
    {

    gl.glEnable(GL2.GL_TEXTURE_2D); gl.glBindTexture(GL2.GL_TEXTURE_2D, texture);

    gl.glNormal3f(normals[faces[i][3]][0],normals[faces[i][3]][1],normals[faces[i][3]][2]);
    }gl.glTexCoord2f(textures[faces[i][1]][0],textures[faces[i][1]][1]);
    gl.glVertex3f(vertices[faces[i][0]][0],vertices[faces[i][0]][1],vertices[faces[i][0]][2]);
    if(usesnormals==1)
    {

    gl.glEnable(GL2.GL_TEXTURE_2D); gl.glBindTexture(GL2.GL_TEXTURE_2D, texture);

    gl.glNormal3f(normals[faces[i][4]][0],normals[faces[i][4]][1],normals[faces[i][4]][2]);
    }gl.glTexCoord2f(textures[faces[i][2]][0],textures[faces[i][2]][1]);
    gl.glVertex3f(vertices[faces[i][1]][0],vertices[faces[i][1]][1],vertices[faces[i][1]][2]);
    if(usesnormals==1)
    {

    gl.glEnable(GL2.GL_TEXTURE_2D); gl.glBindTexture(GL2.GL_TEXTURE_2D, texture);

    gl.glNormal3f(normals[faces[i][5]][0],normals[faces[i][5]][1],normals[faces[i][5]][2]);
    }gl.glTexCoord2f(textures[faces[i][3]][0],textures[faces[i][3]][1]);
    gl.glVertex3f(vertices[faces[i][2]][0],vertices[faces[i][2]][1],vertices[faces[i][2]][2]);
    }

    ReplyDelete
    Replies
    1. Hi I will try to get texture working on the model.. and get back to you. Great idea to texture map this elephant or any other object. But the texture applies only to a triangle.. if you need to map texture to the multiple triangle strips (mesh) I am not sure what needs to be done. Before concluding anything I will try and do what you tried.

      Delete
    2. I have another project that texture maps a custom made texture... https://drive.google.com/file/d/1-xYLshk8IbEWKxddl5TbE0siMrjCrkGA/view?usp=sharing

      Delete
    3. thank You for answer, but i need image texture, i have program look like You but:
      https://files.fm/u/2sgm7dnyh
      look here, first pic is from jogl and secon is from blender object i need this in jogl, This possible?
      Thank You very much for answer

      Delete
    4. You can load an image into the buffer that I have prepared manually.. I know to create a textured elephant requires mtl files along with obj. You cannot create a texture programmatically and expect it to be realistic. As of now I dont think i can do it.

      Delete
  2. ok i will try load image into buffor, i need only blind texture on full object not for every tiangle. thank You

    ReplyDelete