Loading 3D models with the min3D framework for Android

NOTE: This OpenGL ES 1.1 framework isn’t maintained anymore. Check out the OpenGL ES 2.0 Rajawali framework which also supports live wallpapers.

Min3D is a new 3D framework based on OpenGL ES for Android. It’s still in its early stages, but new stuff is getting added rapidly. If you have an Android phone you can download the demo .apk file and install it on your phone.

I started contributing to the framework by writing a parser for .obj files. Almost all 3D programs export to this format, so it was an obvious choice. The first version of this parser has just been committed to Google Code and I still need to add support for a couple of things:

  • multiple objects in one file
  • groups of objects
  • bump map, specular texture map, etc

Here’s an example of how to use the new Obj parser. These are the export option from Blender:

Blender to Obj  exporter options

Blender to Obj exporter options

When you export materials, you can also select “copy images” .

The Obj file should be exported to [your android project]/res/raw. Both the .obj and .mtl files have the same filename and should be renamed so there are no conflicts in the resource manager. It is best to remove the dot between the file name and the extension and replace it with an underscore. Like so:

  • camaro.obj renamed to camaro_obj
  • camaro.mtl renamed to camaro_mtl

Don’t worry about changing the file names in the file itself. The parser will take care of this. Just be sure that there are no paths prefixed to the file name.

The images should be placed in [your android project]/res/drawable. You don’t need to worry about file extensions here. Here’s what the structure looks like for the demo project:

Example project structure

Example project structure

Now all that’s left is adding a few lines of code. It’s as simple as creation a new Activity that is based on min3D’s RenderActivity. The parser code should be added to the initScene() method:


package min3d.sampleProject1;

import min3d.core.Object3dContainer;
import min3d.core.RendererActivity;
import min3d.parser.IParser;
import min3d.parser.Parser;

/**
 * How to load a model from a .obj file
 *
 * @author dennis.ippel
 *
 */
public class ExampleLoadObjFile extends RendererActivity {
	private Object3dContainer objModel;

	@Override
	public void initScene() {
		IParser parser = Parser.createParser(Parser.Type.OBJ,
				getResources(), "min3d.sampleProject1:raw/camaro_obj");
		parser.parse();

		objModel = parser.getParsedObject();
		objModel.scale().x = objModel.scale().y = objModel.scale().z = .7f;
		scene.addChild(objModel);
	}

	@Override
	public void updateScene() {
		objModel.rotation().x++;
		objModel.rotation().z++;
	}
}

The Parser.createParser() method takes two arguments:

  • the parser type (only obj for now)
  • the location of the obj file resource (in “package:type/entry” format)

The rest should be self-explanatory.

This is what the result looks like for the example project:

Example min3D Obj parser output

Example min3D Obj parser output

  • Delicious
  • Facebook
  • Digg
  • Reddit
  • StumbleUpon
  • Twitter

88 thoughts on “Loading 3D models with the min3D framework for Android

  1. adradr says:

    Hello ! I want to make an application in which I will load an object. In my application I have an user interface with different buttons. I want to connect one of my buttons to open ExampleLoadObjFile class. Here is what I did:

    Button 3D =(Button)findViewById(R.id.3DView);
    Vizualizare3D.setOnClickListener(this);

    after this I have:

    public void onClick(View v){
    switch (v.getId()) {
    case R.id.3DView:
    Intent i=new Intent(this, ExampleLoadObjFile.class);
    startActivity(i);
    break;

    In my manifest file I declared ExampleLoadObjFile as an activity, and the model of my object is in raw folder. My problem is that when I press the button the application stops unexpectedly. If I use ExampleLoadObjFile as main activity when I start the application everything goes fine. Also I want to know if this method is good to open ExampleLoadObjFile because this extends for RenderActivity.

    Thank you!

  2. ravenfeld says:

    hello, I would like to know the procedure to export a file. obj and which is compatible to min3D.
    I have already completed the tutorial
    but nothing works. I have no texture.

    sorry to english

  3. Chris says:

    @ravenfeld: In recent versions 2.5x+ Blender does not show this export dialogue for OBJ any more.

    Did you get the two files (.obj and .mtl)?
    Did you copy .obj, .mtl and .jpg file to the correct project folders?
    Did you rename the files .obj with _obj and .mtl with _mtl?

  4. Chris says:

    EDIT: The export options for OBJ are now located in the Blender file selector window to the left. Did not find them on first look.. ;-)

    There you can have normals exported, too.

  5. Asha says:

    Nice code!! I could display a 3D image using the above code. I am wondering if there is a way to display larger files like 30 MB obj file?

  6. Shreyas says:

    Thanks for the tutorial Dennis. Now that I have the obj model loaded I was trying to rotate the model using the touch listener. I am implementing the OnTouchListener interface on the RenderActivity, is this the right way to go about it?

    Thanks Shreyas

  7. sami says:

    hi, thanks for the tutorial , everything else works fine but when the model is loaded it looks like the scene is missing some lights
    the object is really dark and cant see it properly because of i think lightning. can u tell me how to enable the lights?
    Thanx

  8. dazzy says:

    i am doing the same thing on nyartoolkit in min3d.core package in rendereractivity but its not displaying my object can anyone help?
    thanks

  9. Eric Echeverri says:

    Could you give an example on how to draw a font on the screen. Does Min3ds has an utility to create and load fonts

    Thanks

  10. Ecke says:

    I can load my own model without UV-setting, but how to load it with UV???
    Just putting the UV in a drawable folder doesnt work…
    Or do i need Special Setting for this in Blender??

  11. Alex says:

    Dennis, I also have the same problem on real device (android 2.2)

    I can’t texture The Obj files(a car and a moving car) on devece HT-03A.
    And “texture wrapping” is also not.
    But it textured on my emulator at my computer.

    Is it some solution?

  12. Truong says:

    Hi Denis,
    How Can I set background image with 3D Object? I made searching but still not find the answer. The background is still black.

  13. Truong says:

    Hi Denis,

    Thanks for response,

    Yes, That is exactly What I am looking for. Do you have any suggestion?

  14. Truong says:

    Hi Denis,

    Is there any way to change 3D Object color (file .obj, 3ds, md2) using min3d?

    Thanks,

  15. m0skit0 says:

    Hi Dennis, excellent work on this open 3D engine. I was looking to make one myself when I stumbled on yours :)

    I’m having a problem using Mini3D since I followed your example and ended up with a blank screen and no errors whatsoever. I’m using the obj files that are included on the sample, but the sample project was made by me.

    I packed Min3D as a JAR to include in the example project. I don’t think this is the issue…

    Here’s the LogCat:

    05-06 12:16:18.462: I/Min3D(457): ManagedLightList.reset()
    05-06 12:16:18.753: D/libEGL(457): egl.cfg not found, using default config
    05-06 12:16:18.753: D/libEGL(457): loaded /system/lib/egl/libGLES_android.so
    05-06 12:16:18.773: I/Min3D(457): Renderer.onSurfaceCreated()
    05-06 12:16:18.783: V/Min3D(457): RenderCaps – openGLVersion: 1.1
    05-06 12:16:18.783: V/Min3D(457): RenderCaps – maxTextureUnits: 2
    05-06 12:16:18.783: V/Min3D(457): RenderCaps – maxTextureSize: 4096
    05-06 12:16:18.783: V/Min3D(457): RenderCaps – maxLights: 8
    05-06 12:16:18.793: I/Min3D(457): Scene.init()
    05-06 12:16:18.803: I/Min3D(457): ManagedLightList.reset()
    05-06 12:16:18.813: I/global(457): Default buffer size used in BufferedReader constructor. It would be better to be explicit if an 8k-char buffer is required.
    05-06 12:16:18.813: D/Min3D(457): Start parsing object org.ak47.android.min3d.example:raw/camaro_obj
    05-06 12:16:18.813: D/Min3D(457): Start time 1336306578817
    05-06 12:16:18.833: I/global(457): Default buffer size used in BufferedReader constructor. It would be better to be explicit if an 8k-char buffer is required.
    05-06 12:16:18.843: D/Min3D(457): Adding texture org.ak47.android.min3d.example:drawable/camaro
    05-06 12:16:19.113: D/dalvikvm(457): GC_FOR_MALLOC freed 10495 objects / 432152 bytes in 66ms
    05-06 12:16:19.472: D/dalvikvm(457): GC_FOR_MALLOC freed 15165 objects / 535184 bytes in 61ms
    05-06 12:16:19.583: D/dalvikvm(457): GC_FOR_MALLOC freed 3171 objects / 111088 bytes in 50ms
    05-06 12:16:19.583: I/dalvikvm-heap(457): Grow heap (frag case) to 3.200MB for 2740-byte allocation
    05-06 12:16:19.663: D/dalvikvm(457): GC_FOR_MALLOC freed 1 objects / 1840 bytes in 73ms
    05-06 12:16:19.993: D/dalvikvm(457): GC_FOR_MALLOC freed 12902 objects / 455024 bytes in 56ms
    05-06 12:16:20.103: D/Min3D(457): End time 1295
    05-06 12:16:20.113: D/Min3D(457): Start object creation
    05-06 12:16:20.183: D/dalvikvm(457): GC_EXTERNAL_ALLOC freed 5129 objects / 210952 bytes in 63ms
    05-06 12:16:20.253: D/dalvikvm(457): GC_FOR_MALLOC freed 5 objects / 224 bytes in 49ms
    05-06 12:16:20.263: I/dalvikvm-heap(457): Grow heap (frag case) to 5.279MB for 1048592-byte allocation
    05-06 12:16:20.333: D/dalvikvm(457): GC_FOR_MALLOC freed 41 objects / 1592 bytes in 67ms
    05-06 12:16:20.502: D/Min3D(457): Creating object
    05-06 12:16:20.833: D/Min3D(457): Object creation finished
    05-06 12:16:20.833: I/Min3D(457): Renderer.onSurfaceChanged()
    05-06 12:16:20.843: I/ARMAssembler(457): generated scanline__00000197:03545444_00009501_00000000 [171 ipp] (267 ins) at [0x2bc3a0:0x2bc7cc] in 2480396 ns

    Again, thanks for this and thanks for making it open source :)

  16. Arbeginer says:

    Hi all,
    Thanks for this great tutorial I finally managed to insert and .obj file into my Augmented Reality application on Android.
    Maybe some of you can help me with the next step. I would like to show in the screen the frame rate at the same time that the application is running. Do you know how to display text with min3d, if it’s possible?
    Thanks in advance

  17. Arun Goyal says:

    Hi dennis

    can u please tell how can we change colour of car means texture at run time
    anykind of help will be appreciated.

    thanx

  18. Andrew says:

    I saw someone had asked about using min3D with touch event, I just want to make sure that the answer you reply, did you mean I can not use min3D to rotate the model by hand? if so, what tools should I use ?! please help me! thanks!!

  19. Bhauso says:

    i am tries to rotate object by touch events but its not working well…please tell what changes me required…….my code is…….

    package ezeelearning.tablet.min3d.sampleProject1;
    import android.opengl.GLSurfaceView;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.Gravity;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup.LayoutParams;
    import android.widget.Button;
    import android.widget.LinearLayout;
    import ezeelearning.tablet.R;
    import ezeelearning.tablet.min3d.core.Object3dContainer;
    import ezeelearning.tablet.min3d.core.RendererActivity;
    import ezeelearning.tablet.min3d.parser.IParser;
    import ezeelearning.tablet.min3d.parser.Parser;
    import ezeelearning.tablet.min3d.vos.Light;
    public class ExampleLoadObjFlower extends RendererActivity{
    private Object3dContainer objModel;
    Button b;
    protected GLSurfaceView _glSurfaceView;
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    _glSurfaceView = new GLSurfaceView(this);
    }

    public boolean onTouchEvent(MotionEvent event) {

    int action = event.getAction() & MotionEvent.ACTION_MASK;
    switch(action) {
    case MotionEvent.ACTION_DOWN : {

    objModel.rotation().x=objModel.rotation().x+10;
    Log.d(“CV”,”ACTION_DOWN”);

    break;
    }
    case MotionEvent.ACTION_UP : {

    objModel.rotation().x=objModel.rotation().x-10;
    Log.d(“CV”,”ACTION_DOWN”);

    break;
    }

    }

    return true;
    }
    public void initScene() {

    scene.lights().add(new Light());
    IParser parser = Parser.createParser(Parser.Type.MAX_3DS, getResources(),
    “ezeelearning.tablet:drawable/monster_high”, true);

    parser.parse();
    objModel = parser.getParsedObject();
    objModel.scale().x = objModel.scale().y = objModel.scale().z = .7f;
    scene.addChild(objModel);

    }

    public void updateScene() {
    //objModel.rotation().x++;
    //objModel.rotation().z++;
    }

    }

  20. Manikandan says:

    I am developing a server application to provide .obj and .mtl files. With the current obj parser, is it possible to load .obj file from network path instead of local resources?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>