Adobe STL file is a well-adopted standard 3D file formats. You may notice that the STL file does not contain any color or texture information. It's fine for monochrome 3D printing, but may not be ideal for representing objects for virtual reality. Another fairly common 3D object file format is called the OBJ file. It was developed by Wavefront Technologies. It's based on a text file format and similar to the STL ASCII format, where it stores the object vertices and the facet normal vectors. One advantage of the OBJ file format is that, it can link to a Material Template Library, MTL file, which stores the color, lighting, and texture mapping of the object. This example OBJ file, as you can see that each line starts with a character or a word. That indicates the information contained in the line of text. For instance, if a line starts with the word mtllib, it means that the following word is the file name of the associated MTL or the material file. If a line starts with a hash, it means that it's just a comment. If it starts with the character o, it indicates the name of the object. V represents the vertex and it follows with three floating point numbers separated with space, representing the x, y, and z coordinate of the vertex. Vn represent a normal vector, and f represents the facet or triangle. Similar to the indexes, we used to draw 3D objects, the facet or triangle information in the OBJ file contains indexes or vertexes representing each facet or surface of the 3D object. The facet could be of three different format. It can contain only the vertex, the vertex and normal vector, or vertex normal vector, facet texture coordinates. Each facets could have more than three vertices. For each sample, it could have four vertices representing our quadrilateral object. Please note that, the index of the vertex's normal vector or texture coordinates start with one. Let's look at a cube as example. In the object file for the cube, it starts with the vertex v. Eight vertices are required to define a cube. I set the cube to be of size of 2 by 2 by 2, and position at the origin. The cube has six faces, and the normal vectors of the six faces are shown in the red in the drawing and each normal vector is stored in the OBJ file starting with the label vn. As explained in the previous lesson, each face can be drawn with two triangles or facets and e need a total of 12 facets. As I don't want any texture for the cube, I only choose the facet format with only the vertices and normal vectors. For instance, the first facet identifies the triangle on the top face of the cube with the vertices three, four, and eight, and the normal vector with index three. Let's look into the functions of parsing an OBJ file. I first, define the vertex is normal vectors, indexes, texture and coords as ArrayList. A two-dimensional ArrayList is defining core faces for storing all the indices of the facets, and the ArrayList faces indexes is defined to show the indexes of each facet. As mentioned before, a facet could have more than three vertices. For example, a facet could have four vertices representing a quadrilateral. To draw a quadrilateral in OpenGL, we need to represent it as two triangles. Hence an integer array called order, is defined which contains the order of vertices to form the polygon defined in the facet. For instance, for a facet with three vertices, the order of the vertices could be one, two, and three and for facets with four vertices, the order of the vertices could be one, two, three, and one, three, four, representing the two triangles for joining their quadrilateral. Made the STL file, I pass the object file line by line. I first check if the line is empty or not, and whether it is a comment line. If so, I just skip the line. For others, I first replace all the sediments in the line with multiple spaces with only one space and trim the line so that the line will have no preceding or telling spaces and each word or number is separated with only one space. Then I split the line into a string array. The first string in the string array is free. The line contains the coordinates of the vertex, and I store the coordinates in the list vertices. I also use those coordinates to find the mean, max and min values for determining the central location and dimension of the object. Your line start with vt. The line contains the texture coordinates, and I store the coordinates into the texture list. The line start with the words vn. The line contains the unit normal vector, and I store that into a normalvectors list. Your line start with f. The line represent the facet. I first identify the format, what type of a facet first to see if it contains vertex normal, vertex texture, and normalvectors, or just vertices. Then I find the number of order of vertices required for representing the facet or surface. For instance, if the facet has three vertices, the number of order will be equal to three and if the facet has four vertices, the number of order will be equal to six. Hence, we need six vertices to draw two triangles for a four vertex quadrilateral. Then for each vertex in the order, I first split the corresponding sub string based on the type of the facet format. If it is of type one with texture, I store the texture coordinate in the coords ArrayList. Afterwards, I find the vertex number and add that to the indexes ArrayList and also the face indices list. Please note that the vertex numbers start with one. So the vertex number has to minus one for the OpenGL to point of the vertex in the array which start with zero. After passing all the vertex indices, then I store the face indices into the faces list. This will be used to find the normal vectors of the facets if the normal vectors are not defined in the object file. For the line starts with the mtllib contains the name of the material file, the line starts with usemtl in the case the material to be used and the line starts with o indicates the label of the object. As object file may not provide normal vectors of the facets of the object, we will have to calculate and set normal vectors of the facets in order to draw the object with proper lighting and shading effects. If no normal vectors find, I first initialize normal vectors array of serial then I calculate the normal of each facets one-by-one. As explained before, we can use free vertices to calculate a unit normal vector. That's each facet could have more than three vertices. I choose to use the average normal vectors as normal vector of the facets that the average normal vectors are stored in the normal vectors list. Like the STL file, I calculate the centroid and the dimension of the object and then translate and scale the vertices to position the object at the origin with size within this space 2 by 2 by 2 for this plate. The resulting vertices, normal vectors and indices are stored in the floating point arrays. I define that function FloatList2floatarray and IntegerList2intarray to convert the float ArrayList and integer ArrayList through floating point array and integer array respectively. Once those buffers to define it, the same shade of programs and routines for joining 3D objects using OpenGL can be used to draw the OBJ object in Android. The function FindNormalofTriangleFromIndices simply gets the indices from the array list and call the function FindNormalofTriangle to calculate normal vectors of the triangle. The FindNormalofTriangle is the same as the one we used to define it for parsing the STL file. The function FloatList2floatarray and IntegerList2intarray basically convert the list array into floating point array an integer array respectively. To read an OBJ file, I first create a new class called OBJ Object and then copy the vertex shader at source code from the STLObject and also the fragment shader source code and paste it onto the OBJObject. Also, copy all the buffers handles to the attribute or uniform variables and arrays float or integer arrays from the STLObject file to this OBJObject file and also copy the child functions, set the location functions from the STLObject. I also copied all the code for the constructor of the STLObject and then paste those onto the constructor of the OBJObject. I also copy those functions for calculating the normal vectors of surface from the STL object and also those float list or integer list to float array or integer array functions for the OBJObject. Then I add a new function called FindNormalofTriangleFromIndexes. Basically, calculate the normal vector of a triangle by providing the indexes to the vertex array. Then I add a new function called ParseOBJFilestring which takes a string and the Uri file path as its parameters. First, I create a number of array list floating point variables for storing the vertexes, normal vectors, indices, textures, coordinates, faces or faces indices, and also a number of variables for finding the centroid and the range of the size of the object. Then I create an integer array storing the orders of the vertexes for each faces. This is for creating the faces from the vertexes read from the file. By parsing the STL file, we parse the OBJ file line by line, checking whether it's a comments or no and also removing the white spaces. If a line start with the character v which means it contains all the vertices. So we read the x, y, and z vertexes from the string and then store that in the vertex list array. You'll also find the mean and max of the vertexes to calculate the centroid later. If it start with the character vt which means the texture coordinates, we store those in the texture lists array and we start with vn which means the normal vectors, so get the normal vectors from the string and store that in normal vectors list. So if the line start with the character F, which means it's a facet. So we first check what format is using, whether it's a vertex with normal, vertex with texture and normal vectors, or vertex with texture, or just a vertex only. I assign those two types with one and two. Then I calculate the number of orders, which means the number of vertexes to represent the facets. So for each order or the vertex of the facets based on the type of the facets, I read the vertex number or the texture coordinates indexes and store the vertex number into the index list, and also the facets index list. Then I stored all the indexes rough for the facets into the list array called faces. For those lines start with the mtllib or usemtl or o representing the material form, material name, or the object name. We will handle that later. So if there's no normal vectors defined in the Obj file, we have to calculate the normal vectors for each of the facets of the object. So we use the same approach and functions to calculate the normal vectors for each of the facets of the object. Then we do the same as what we have done with the STL file objects, we calculate the means or centroid, and also the range or the size of the object. Using those to translate the object to the origin and also scale that such that it will be within the two-by-two-by-two size. In the MyRenderer object, we need to add a function called parseObj with parameter file string and filepath. Then we store the OBJ file string and Obj file path into local verbose and define that into the object. The surface changed function, which had whether the Obj_file_string is defined, if so, then we create object called objobj. The onDrawframe functions, we first copy those lines. Those also for joining the STL file object and then paste it in the functions, and then we face the STL object with the objobj object. In the MainActivity class, we get a new function called getObjFile, which is very similar to the getSTLFile except that we call the function parseObj, which is in the GLView, instead of parseSTL. Then in my view object, ahead of the function called parseObj basically called the parseObj functions in the MyRenderer. Then go back to the MainActivity class on activity result functions. Within that, we need to add a few lines of code to handle the request for reading the OBJ file. So any request code in a function for lower class code freely fall low class code. Add a few lines basically similar to the STL file, instead of reading the STL string, we check where the founding contains the OBJ name. If so, we call the getObjFile functions to read the OBJ file. Then add a few lines of code to show alert dialog box. So indicating that the user trying to open the unknown file type, which is not STL or OBJ file. When you run the program, you can select OBJ file. In this case, I see that was cube OBJ file, then I can use to virtual sensor to rotate the object around. So to select another file, I run the program again. Now, this time, I want to show the heart OBJ file. When opened, you will see the 3D shape of the heart is shown. I can zoom in and also rotate the object using the virtual sensors. Let's try another OBJ file. This time, I open a Mini Cooper OBJ file. So basically, it's a 3D model of a Mini Cooper. I can rotate the object around using the virtual sensors. When you zoom in, actually, you should be able to see that detail inside a Mini Cooper.