As mentioned earlier, one advantage of the OBJ file is that it can link to a material laboratory file, which defines the lighting effects and the texture of the object. So in the OBJ file you may see that it has a line starting with MTL followed by a file name. Hence when mapping the material onto the object, the Android app needs to open and read the MTL file. Before I start explaining in details formats of the MTL file, I'll explain how to request for permission to open another file in your app. MTL by default does not allow an app to open a file automatically unless the permission is granted by the user. In order to obtain the permission for an app to open the MTL file automatically, I need to first add a line of code in the AndroidManifest XML file. Hence I add the XML cope with tag users permission will permits a Android permission read external storage. Then in the main activity, I first define a constant. My permission request read external storage, then in the onCreate function, I'll call the function chat permission read external storage. The function which have permission read external storage, basically called a context compat checks. Self permission to check if an app has permission to read external storage. If not, it will call the showed dialog function to show a dialogue to ask the users permission to read the external storage. The showedDialog function uses the alertDialog to show a dialogue to ask the users permission to read an external storage. When the user chooses an option, the onRequestPermissionResult will then be called and the permission granted is set or a permission denied message is shown. When you run the program, you see that the app will now request the user to allow the app to assess the photos, media, and files on the devices. When you click "Allow," the app will then be able to open and read the MTL file automatically. In order for our apps to read the MTL file automatically, we need to add a few functions in our program to ask the users permissions to read the file. The first is the constant call my permissions requests read external storage. So I set it to equal to 123. In the onCreate functions of the MainActivity at aligned to call the function, check permission with external storage. Then at the functions checkPermission with external storage, basically, it called the function, checkSelfPermissions of the contexts, comeback to check whether permission is granted. If not, it will call the showDialogue to ask the user's permissions to read the external storage. Otherwise, we request permission to allow the app to open the file automatically. The other function called showDialogue, basically show a dialogue box for asking the user's permissions to read the external storage. Then at over our functions onRequestPermissionResult, and check with the requestCode, whether does it go to my permission request with external storage and check if the permission is granted, if not, it will show an error message. Then in the AndroidManifest.xml file, we need to add a new line with a text user's permissions with parameters android permission with external storage. So when you run the program after you select the OBJ file, you will see that a dialogue box will shown to seek permissions to get the access to the photo, media, and files. In the lesson on lighting and illumination, we learnt how lighting effects such as diffuse light and specular highlights can be generated using OpenGL. The ambient light color, the diffuse light color, and the specular light color can be defined for each material with labels Ka, Kd, and Ks. In addition, the specular exponents can also be defined with label Ns. For each lighting effect, a texture material can be mapped. For instance in this example, the diffuse texture map is defined with texture filename, texture_filename.png. The text D defines the opacity of the material, where one means fully opaque and zero means transparent. Furthermore, the illumination model can be set for each material, where 2 means specular on. There are many more parameters are defined for materials in MTL file. There are many focus on the lighting colors, opacity, and texture mapping. To introduce the material into the object, we define new Java class called ObjMaterial which stores the parameters of each material including the name, ambient light color, diffuse light color, specular light color, etc. To use the programming, I create a few functions in the ObjMaterial. The function setLightParam, basically, set the RGB color for one of the lighting effects such as ambient. The loadTextureImage function loads an image file from the device and return a Bitmap for texture mapping. The LoadAllTextures function loads the texture for the diffuse color mapping, and it cause the loadTextureImage function to load the specified image file. A carrier function called loadMTLFile in the OBJ object class to load the MTL file specified in the OBJ file. It first simply finds the path name from the URI, and then open and read the content of the file line by line. Afterwards, I call the ReadMTLFile to parse the MTL file content. The ReadMTLFile function is defined to read the material information from the MTF file. It returns a list of ObjMaterial. The function processes read text line by line. It aligns empty and the materials previously read from the file like create new ObjMaterial, and store all the material parameters such as ambient and diffuse light color, and then add the newly created ObjMaterial to the array list. If the line is not empty, I first trimmed a string and then split the string into a string a array. The line starts with the hashtag as a comment, and I'll simply ignore it. If it starts with a text map_Kd, it means that it is a color texture file for diffuse light. I store the texture filename to the variable diffuse color texture file. If it starts with Ns, it'll represent the specular exponents. Illum is the illumination model. D is the opacity or the alpha channel of the color. Ks, Kd, or Ka representing the lighting colors. After I finish processing all the lines, I then create a new ObjMaterial with the extracted material parameters, and add that onto the array list material. The function then returns the array list of materials. As different faces of an object can be off different materials, to simplify the join process, I defined the array lists to define the materials for each vertex. So when each vertex is read from the OBJ file, I add a new elements in the material array list. For instance, I added the ambient light color with the initial wherever one, one, and one. When parsing the facet information of the OBJ file, I then set the material parameters for this specific vertices with the current selected material. The variable current object material is to current selected material. I set the ambient light, diverse light, specular light, specular exponents, and alpha parameters of this specified vertex to the respective value of the current object material. This section of code where the program detects the MTL, the text, I added the code to call the function loadMTLFile to load the material file automatically. The text usemtl in the OBJ file, defines which material is selected for the subsequent facets. So I call the function FindMaterial to find the OBJ material object with this, specify the material name, and assign that to the current object material as a current selected material. After parsing the strings of the OBJ file, I then convert the array lists into float arrays for the light colors. If the texture is divided, a quarter load texture from file function to load to texture image and assign the handle to diffuse texture data handle. The FindMaterial function, basically, searches for the material from the list of OBJ materials with the specify the name, and return to identify the material. To show the different materials used to form the object, I need to modify the Vertex Shader. So instead of using uniform variables to set the Ambient diffuse and Specular light color. Now, use attribute variables to define the light colors and instead of materials shiners, I use a specular exponents to set the shininess of the specular highlight. In addition, like the final set of varying variables for parsing the attribute ready with the Fragment Shader. In the main function of the vertex shader, many past the attribute variables values to the fragment shaders using the varying variables. In addition, I use the specular exponents to calculate the specular highlight you vet. In the fragment shader, a uniform variable US Texture to let the application program to set whether or not use texture mapping. If the US Texture is set to one, I said the fragment color to equal to the color of the corresponding pixel of the texture image. I then set the diffuse color and specular color to equal to the respective like waiting, multiplying with the varying variable of a diffuse and specular light color. If texture is used, I just set the GL frag color, to a texture color. Otherwise, I set the GLfrag color to use the Ambient specular and diffuse color. For the new attribute and uniform variables to find it for the materials, you might have to create the corresponding buffers and handles to point to the attributes and uniform variables in the shaders. I've also created a set of font arrays to store the values of the material parameters. The constructor of the LBJ object, I don't need to create the buffers from the font arrays to pass the data to the attribute variables in a shader. I also create a texture buffer to point to the texture coordinates. Then I point the handles of the attribute and uniform variable to the corresponding variables in a shader programs, and enable the attribute handlers. In the jaw function, I added a few lines of code to call the Geo vertex attribute pointer, to pass the lighting effect parameters to the shaders through the attribute variables. If the texture is used I added a few lines of code to act to activate bind and select a texture to map that texture onto the 3D object. To handle the material, I first add the new Costco OBJ material, and then add the number of variables to define the material. Basically, the lighting effect like a specular, diffuse, ambient light, the nim and also the texture use for this material. Then in the constructor, I initialize all the variables with the default value. The other function called Setlight Parameters, basically allow other functions to set the color intensity of the light. Then another function called load texture image basically, takes a file name and then load the bitmap file for texture mapping. Then another function called LoadAllTexture. Basically, allows all the texture fast defining for the material. Then in the OBJ object file, I had a new function called, Read MTO File, which takes a string and also the object file path as parameters. Then I add the new ArrayList core materials basically, is a list of all the object materials list in the file, and also defined number of variables for storing the current specular, diffuse or ambient light parameters. So like passing the OBJ file, I passed the MTO file string line by line. First, I remove all the carriage return, and then check whether there's any character on the line. If the line is empty, I would check whether the current name is defined. If it's not, then I will store all the parameters read from the file, then stored into a new OBJ material called Mat. Then I add the Mat, the OBJ material mat to the material list. If the current string [inaudible] or texts is not empty, then I will first remove all the trimming space and then split that into a string array. If the first string in the string array is equal to " hash ", which means the comments will ignore that. If its equal to new material, or new MTO, which means it defined the name of the material. If it's equal to Map kd, which means is a diffuse color texture file. So we store the file name for the texture and if is equal ns, which means is a specular exponents, if it's equal to M which means the elimination. If it's to D, which means the opacity of the material, and we sent it to the variable alpha. It will start with the string KS, KD or KA, which means it defined the specular, diffuse, or ambient color of the material. After passing all the lines, we check whether materials is defined by checking whether the name is now or not. If not, then we store all parameters rhetoric file into a new OBJ material call Met, and then add that to the material list. Add a new function called low MTL file. Basically, it takes a file name and file path, and then read the file directly from the file system of the Android. You would check if the file exist or not. If it's exist, then you'll read the file line by line, and then call the real MTL file function to pass the MTL file. Then add a new function called find material. Basically, it search through material list to find the name the material and return the OBJ material objects. Then another function called LoadTextureFromFile. Basically, it takes to be mapped and then loaded into a texture. In the vertex Shader, will first comment out those uniform variables defining the lighting effect on the object. Then we add the attribute variables to define the ambient diffuse, specular and all these lighting effects. Then in the main function of the vague vertex shader, we pass the attribute variables to the fragment shader using the varying variables. For the specular highlight, instead of using the uMaterialShininess, we use the attribute exponents revenue file to set the vSpecularLightWeighting. In the fragment shader, we first add the varying variables and also, the variables for mapping the texture onto the object. In the main function, we first check whether the texture is read from the object file, if so, we will set the fragmentColor to equal to the textureColor. Then we calculate the diffuseColor and specularColor. If the texture is defined, we set that glFragColor equal to the fragmentColor, if not, we set the glFragColor equal to the fragmentColor plus the vAmbientLight, specularColor, and diffuseColor. As now, we're using the attribute variables to define the color of our lighting effects, so we don't need those handler to ponder the newly formed variables, and also those photo array, for defining the color of the lighting effects. But we need a number of flow buffer, for passing the value of the light color to the attribute variables. We also need a number of handles, to ponder those attribute variables, then add the number of photo array, to store the values for those lighting effects, and also define the variables for setting the texture mapping of the object. Then in the past OBJ file sharing functions, I add a number array lists variables for storing the OBJ materials, and also the different color lighting effects. In this session of the code, where the functions read the vertex of the object, I add a few lines of code, to set the default value default color for each of the lighting effect, and add those to the respective list. This is to ensure that each vertex of the object has a color, the ambientColor, or difuseColor, defined it for that vertex. In the section of the code, where we list the facet of the object, if the texture is defined for the facet, I will set the variable uhastexture equal to true. Then if the current origin material is not able to know, then I will first find the vertex number, and then set the respective lighting color to the current object materials color. If the OBJ file lines starts with the name empty, or live which means the material file, I'll quote a low MTL file function to read and pass the MTL file, and we turn that and set it to the OBJ materials, which means all the materials read from the file. If the lines start with the name, Use material, which identify the name of the material to be used, then I call the file material functions to find and specify the material, and set it to the current object material. At the end of the functions, we need to add a few lines of code, to convert the folders to the folder array. Then I'll go for the list of materials, if the diffuse_texture is defined, I'll load the diffuse texture file, and then send it to the diffuseTextureHandle, and also convert the full list coordinates to texture buffer. Then in the constructor of the OBJ objects, so we can comment out all those buffer used to define the uniform color for the lighting effects. Then create a buffer to store the values of the different lighting effects, to pass it on to the attribute variables of the shaders. If texture is defined, we create a buffer for storing a texture coordinates, then we add the handles to the attribute variables in the shaders, then we set the handle as texture handle to point to the uniform level uhastexture to check if the texture is defined, and also at the handle for the texture mapping. Then in the onshore functions, we add the function glVertexAttribPointer to pass the variable's values of the lighting effects onto the shaders. If the texture has defined it, then we call those functions to map the texture onto the object. So let's run the program, and this time I want to try to look at the minicooper file. So when I open the minicooper OBJ file, it will automatically load the MTL, the material file for that object. When the objects load, you see that the object now has color. So the Mini Cooper now has the color red on the body, and then the different color on different section of the car. Let's try to open the Heart.obj file. When the file is opened, it will load the material and also load the texture. So as you can see, the texture of the heart is loaded onto the object. But the texture mapping doesn't seem right. Apparently, there's a bug in the program. When we try to read the coordinate for the texture mapping, the variable vertex number was not defined, so we need to move those lines of code after the vertex number is defined. Okay, let's try it again. Let's load the Heart.obj file. Let's zoom into object. As you can see, now the texture mapping seems to be correct now. Let's try a different obj file. This time, I opened the file Cow.obj. It also load the texture file for this object. So let's rotate the object around. You can see the texture mapping seems to be correct, and it shows a 3D cow model on our screen.