When you want to visualize 3D content on Android phones you have several solutions and frameworks. While using Actionscript with Away3D (with GPU activated in AIR) might be the quickest solution to display low polygon models, what should you do when you want to integrate a more complex 3D view in an existing Android Java app? In this case you will probably think that you must use the complex Open GL libs of Android. But there is a more convenient solution: using the min3D framework to rapidly render OBJ, MD2 and 3DS models.
Here is a short tutorial on how to use and render a 3D object ( in this case a human face) using min3D for Android.
Part 1: Download the Min3D framework
The min3D framework is based on OpenGL ES and you can use it to develop 3D apps for Android. The major feature of min3D is the fact that you don’t need to be an OpenGL specialist. Believe me if you have used other 3D libs like Away3D or Papervision before, you won’t be lost and I was pretty surprised to see how easy it was to use min3D.
http://code.google.com/p/min3d/
Once you have downloaded min3d from the SVN, you will need to create a new Android Project, import the min3d library.
Part 2: Get a nice 3D model
As we want to visualize a nice 3D object, I highly recommend you to have a short glance at www.3dvia.com where you can find resources for OBJ and DAE and other formats.
Navigate to www.3dvia.com and download following 3D model of a face: http://www.3dvia.com/models/66964B5C6E405264/face
Unzip the file. You will have following files:
Now select the .jpg files and paste them into the /res/drawable directory . You will see following message in the console section of Eclipse.
The problem is that Android doesn’t accept capital letters in the file names, so the easiest solution is to write the file name lowercase.
Create a directory named /raw under res and place the face.mtl and face.obj. You will notice this message:
Don’t worry 😉 You will only need to rename face.mtl in face_mtl and face.obj into face_obj. Min3D will automatically “know” what kind of file needs to be loaded, so the .obj will be loaded correctly.
Now put also your textures into res/drawable
The final step is to modify the material file. The material file is stored under face_mtl. This file contains a reference to the textures that should be applied to the 3D object. Let’s have a look in it:
newmtl Texture0 Ns 20 d 1 illum 2 Kd 0.7 0.7 0.7 Ks 0 0 0 Ka 0 0 0 map_Kd face_eyeL_hi.jpg <- Modify this line! With face_eyel_hi.jpg
If you would now start the application you wouldn’t see the textured 3D face because the map_Kd parameter has the wrong path to the texture (remember that we’ve changed the name to lowercase?). Ok so you only need to rename the map_Kd lines in order to match the filenames under /res/drawable.
We’ve almost finished. We now have to load the face_obj into min3D. To do this, take note of this line:
IParser myParser = Parser.createParser(Parser.Type.OBJ, getResources(), "com.Test3D:raw/face_obj",true);
com.Test3D is the name of your package and obviously raw/face_obj is the name of your OBJ file. Add in your Manifest file following lines (to register your activity)
<activity android:name="Obj3DView" android:label="@string/app_name"></activity>
Part 3: Modifying and tuning the OBJ file
The problem with imported OBJ file is that sometimes the values included might not completely fit with what you would expect. In my case I’ve faced problems with the luminosity and the loading of textures. In order to solve this, I’ve manually edited the face_mtl file:
newmtl Texture0 Ns 20 d 1 illum 2 map_Kd face_eyel_hi.jpg Kd 0.7 0.7 0.7 Ks 0 0 0 Ka 0 0 0
[Updated] Important note:
Please remove the tabulation at the beginning of each line in the face_mtl, otherwise the texture won’t load.
And I did this for the other textures.
Now you need to go to face_obj, and change the mtllib entry to face_mtl (instead of face.mtl)
The code
Here is the code to load the OBJ with min3D. You only need to extend from RenderActivity and to instantiate this Activity in your onCreate() function.
package com.min3dtest; import min3d.core.Object3dContainer; import min3d.core.RendererActivity; import min3d.parser.IParser; import min3d.parser.Parser; import min3d.vos.Light; public class Obj3DView extends RendererActivity { private Object3dContainer faceObject3D; /** Called when the activity is first created. */ @Override public void initScene() { scene.lights().add(new Light()); scene.lights().add(new Light()); Light myLight = new Light(); myLight.position.setZ(150); scene.lights().add(myLight); IParser myParser = Parser.createParser(Parser.Type.OBJ, getResources(), "com.min3dtest:raw/face_obj",true); myParser.parse(); faceObject3D = myParser.getParsedObject(); faceObject3D.position().x = faceObject3D.position().y = faceObject3D.position().z = 0; faceObject3D.scale().x = faceObject3D.scale().y = faceObject3D.scale().z = 0.009f; // Depending on the model you will need to change the scale faceObject3D.scale().x = faceObject3D.scale().y = faceObject3D.scale().z = 0.009f; scene.addChild(faceObject3D); } @Override public void updateScene() { faceObject3D.rotation().x += 0.5; faceObject3D.rotation().z += 1; }
And of course you need to launch this activity:
public class Min3dTest extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.startActivity( new Intent(this,Obj3DView.class)); } }
Part 5: The result
Now launch your application and voilà: you will have now a beautiful 3D model turning around.
Final note
Loading an OBJ file with Min3D is pretty easy (just 2 lines of code). The problem I’ve faced were all linked to the OBJ file format, missing textures (or badly referenced) and of course the scale of the loaded object that differs with each 3D model you will download. So it means you will need to check several times if everything is ok and even need to move the camera to see your 3D model. Of course if you are building your own 3Dmodel you won’t need to take care of this details, but it’s necessary to know, that almost 80% of the “I don’t see my model!” problems will come from either missing textures, faulty scaled or a faulty camera placement.
You will notice if you are debugging with Eclipse and adb that the 3D object won’t display directly and will be really very sluggish (under 10fps ). This is because the Android phone is in debug mode. To really see the result, unplug the USB cable from your mobile phone and tada… you will directly see the 3D object running at over 60ps! I’ve experienced this phenomenon on Froyo 2.2 with an HTC Desire, Froyo 2.2.2 on a Dell Streak and on Gingerbread 2.3 on a Samsung Nexus S L So I assume this is a general “bug due to the debug mode.
[Update]: I’ve extend the tutorial by selecting frequent issues and problems visitors have face while using min3D in a new post: http://www.mat-d.com/site/using-min3d-for-android-frequently-asked-questions-common-texture-issues-blender-import/