Archive for January, 2007|Monthly archive page

Creating a basic M3G file with Blender

When using the Mobile 3D Graphics API (JSR 184), it’s important to understand how to create 3D objects, as discussed in my last couple of posts. However, in a real application you will typically use files created by 3D modeling software.

Many commercial software suites allow you to export 3D scenes in M3G format (required by JSR 184), including a free one called Blender, which you can download here. Don’t let the fact that it’s free fool you — like a lot of free software, it’s a full-featured software package suitable for professional use. By default Blender doesn’t export files in M3G format — you have to install an additional plugin such as the one I found from Nelson Games here. The plugin is very easy to install, you just need to make sure that Python (version 2.4 or greater) is correctly installed, and then you place the additional script in the Blender python scripts folder.

As the Blender documentation freely admits, Blender is not terribly newbie-friendly(really it could stand a few basic tutorials…) but it’s quite powerful and configurable once you get the hang of it. Here are some basic steps to get started and create a simple M3G file:

screenshotblendercube.png

This is what you will see when you first open Blender. (Click on the image to see it full-size.)

A new file in Blender starts off with a cube near the origin. You can see what the cube looks like when rendered by selecting render. The camera used for this rendering is that little line drawing near the bottom right corner.

If you don’t feel like using the default cube, just get rid of it by just pressing the delete key. (Since the cube is initially selected by default, the delete key deletes it.) If you’d like to keep it instead, you can transform it. If you’re in object or edit mode (the first drop-down menu in the toolbar along the bottom in the above screenshot is the mode), you’ll see some little buttons with icons for different ways of transforming the objcet: a triangle for translation, a donut for rotation, and a square for scale. To add further objects, go to add > mesh as seen in the following screenshot:

screenshotaddmesh.png

At this point you have the idea of how to create a very basic file, and you can try fiddling with all of the various gizmos on your own to see what else you can do. 😀

Once you have your scene ready, you can export it in M3G format by selecting M3G under the file > export menu. This option will appear automatically if the plugin is correctly installed. If you’re using the same plugin I’ve recommended, you’ll have a choice between exporting as M3G or as Java code. The Java code option is what I like about this particular plugin (I don’t know if others offer it). But let’s start by exporting it as M3G since that’s what you’ll usually do in a real application, and talk about exporting it as Java code later in this example.

Rendering the M3G file in your Java application is even easier than creating it! (Although — as with creating the file — there’s no end to the possibilities once you get started and get the hang of it.) All you do is put your M3G file in the MIDlet’s Jar file, load it with the Loader class, find the World node, and render it using the Graphics3D class.

There are a bunch of tutorials that show these basic steps, but I’ll show them here for completeness since there are only a few essential lines. Let’s assume we called the file “cube.m3g”. Here’s the code for the initialization step:

Object3D[] allNodes = Loader.load(“/cube.m3g”);

// find the world node
for(int i = 0, j = 0; i < allNodes.length; i++) {
if(allNodes[i] instanceof World) {
myWorld = (World)allNodes[i];
}
}

Then in the paint method of the Canvas (or other rendering target), you start by binding the Graphics3D singleton to the target’s Graphics instance, then call render on the World you read from the file, then release the target. You can do more entertaining things by manipulating the scene graph that is accessible from the World node, but if all you want to do is display the image file you created, then you’re done.

/**
* Paint the graphics onto the screen.
*/
protected void paint(Graphics g) {
Graphics3D g3d = null;
try {
// Start by getting a handle to the Graphics3D
// object which does the work of projecting the
// 3-D scene onto the 2-D screen (rendering):
g3d = Graphics3D.getInstance();
// Bind the Graphics3D object to the Graphics
// instance of the current canvas:
g3d.bindTarget(g);

// Now render: (project from 3D scene to 2D screen)
g3d.render(myWorld);

} catch(Exception e) {
e.printStackTrace();
} finally {
// Done, the canvas graphics can be freed now:
g3d.releaseTarget();
}
}

In my earlier examples we had to define the camera, but when rendering a world node like this, the default camera is defined in the world’s data. This mode of rendering is called “retained mode” (the earlier examples were “immediate mode”). A typical way to think about these two modes is that immediate mode is what you would use when defining a simple object in the code whereas retained mode is what you use for rendering M3G files. That’s what it usually comes down to in practice, but that isn’t the real difference, especially since you can define a world node and complete scene graph in the code and render it in retained mode or you could extract the VertexBuffer and IndexBuffer from a Mesh you found in an M3G file and render it in immediate mode if you like.

The fact that you can create the same data in Java code as you can define in an M3G file becomes very apparent if you export your scene from Blender as Java code. In fact, that way you can look at the code and see how it’s done, tweaking it and seeing the effects of your modifications if you like. Even though the Java class generally takes more space in the jar (even after obfuscation), there are real-world applications for exporting the file as Java code since on many platforms Java code loads faster than resources from the Jar file.

The Java code produced by this plugin is quite easy to use. It creates a Java class with the name you choose when you export, and the class has a static “getRoot” method that returns the world node. The only things I had to change to get it to work were to add it to my package and change the use of “Canvas3D” to “Canvas”. (I’m not sure why Canvas3D is used here since Canvas is more widely supported and works just the same.)

If you’d like to have a look at the code it generates, I’m posting the exported code of a simple Blender-generated cube below the fold.

Continue reading

Advertisements