Announcing Rajawali: An OpenGL ES 2.0 Based 3D Framework For Android

Rajawali is a 3D framework for Android built on top of the OpenGL ES 2.0 API. Its main purpose is to make things easy and to take away the hard work that’s involved in OpenGL programming.

Rajawali can be used to create live wallpapers and stand alone apps.

Here are some of Rajawali’s features:

  • import .obj, .md2, .3ds and .fbx files
  • point and directional lights
  • fog
  • materials: simple, diffuse, phong, gouraud, toon, bump map, environment cube map, sphere map, masked, particle
  • skybox
  • frustum culling
  • object serialisation and compression for optimisation
  • easily create custom shaders
  • 2D (screen quad) renderer
  • (color) object picking
  • very easy to create live wallpapers
  • animation classes and interpolators
  • bezier splines, catmull-rom splines
  • particles
  • post processing effects (sepia, swirl, or create your own shader-based one)
  • vertex animated models
  • quaternion based rotations
  • cube, sphere, particle, plane and line primitives


If you want to contribute to this project, you’re more than welcome of course!

The name “Rajawali” comes from the Indonesian language. It means “eagle”. It is also the name of a kampung on the island of Banda Neira. Banda Neira is part of the Banda Islands group. Another island from this group is called Pulau Hatta, which used to be called Rozengain. See the connection??

All the files can be found on Github:

You can download the free examples app from Google Play

Documentation and tutorials can be found here http://masdennis.github.com/rajawali/

OpenSceneGraph Level of Detail Management

I managed to get my head around the basics of OpenSceneGraph by reviewing the book OpenSceneGraph 3.0 Beginner’s Guide. I picked up a few things that were very interesting.

OSG has a very convenient way of using an optimisation technique called Level of Detail management. Simply said: when an object is far away from the camera a copy of the original object is used with a reduced number of faces. Because the object is far away you don’t need a mesh that is as detailed as the original one. Check the Wikipedia article for a visual explanation.

The mesh simplifier class does all the hard work and is based on the visitor design pattern. The Node is the host that accepts the visitor. The host and the visitor communicate with each other via their public interfaces. This allows us to separate the algorithmic complexity from the data structure. Other visitor classes that can be accepted by a Node are IntersectionVisitor (testing intersections within the scene), CollectOccludersVisitor (cluster culling to cull back facing drawables), ComputeBoundsVisitor, RemoveEmptyNodesVisitor and a lot more.

There are some C++ specifics in this bit of code that might seem a little crazy if you’re used to ActionScript. In native C++ there is no garbage collection, you have to do all that yourself. In OSG there is something called a smart pointer that can help you with this.
Also there is a dynamic_cast. More info on the different types of casting in C++ can be found here.

Here’s the bit of code that does all the magic:


#include <osg/LOD>
#include <osgDB/ReadFile>
#include <osgUtil/Simplifier>
#include <osgViewer/Viewer>

using namespace osg;
using namespace osgDB;
using namespace osgUtil;
using namespace osgViewer;

int main(int argc, char** argv)
{
// load the .osg model
ref_ptr<Node> cowLevel3 = readNodeFile( "cow.osg" );
// clone the model
ref_ptr<Node> cowLevel2 = dynamic_cast<Node*>( cowLevel3->clone( CopyOp::DEEP_COPY_ALL ) );
// make another copy
ref_ptr<Node> cowLevel1 = dynamic_cast<Node*>( cowLevel3->clone( CopyOp::DEEP_COPY_ALL ) );

// create an instance of the mesh simplifier
Simplifier simplifier;
// reduce the number of vertices and faces
simplifier.setSampleRatio( 0.5 );
cowLevel2->accept( simplifier );

// reduce the number of vertices and faces even more

simplifier.setSampleRatio( 0.1 );
// this node should accept the simplifier node visitor
cowLevel3->accept( simplifier );

// create a new level of detail node
ref_ptr<LOD> lodNode = new LOD();
// add the meshes
lodNode->addChild( cowLevel1.get(), 200.0f, FLT_MAX );
lodNode->addChild( cowLevel2.get(), 50.0f, 200.0f );
lodNode->addChild( cowLevel3.get(), 0.0f, 50.0f );

Viewer viewer;
viewer.setSceneData( lodNode.get() );
return viewer.run();
}

Min3D for Android: Fog

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.

Here’s something I just added to Min3D: fog.
Just a few lines of code are needed:


scene.fogColor(new Color4(0, 0, 0, 255) );
scene.fogNear(10);
scene.fogFar(40);
scene.fogEnabled(true);

You can download the .apk containing all the examples here.

Here’s a full example:


package com.rozengain.min3d;

import min3d.Shared;
import min3d.Utils;
import min3d.core.RendererActivity;
import min3d.objectPrimitives.Box;
import min3d.objectPrimitives.Rectangle;
import min3d.vos.Color4;
import min3d.vos.Light;
import min3d.vos.LightType;
import android.graphics.Bitmap;

public class TestActivity extends RendererActivity {
	private Box[] boxes;

	@Override
	public void initScene() {
		Light light = new Light();
		light.type(LightType.DIRECTIONAL);
    	scene.lights().add(light);
    	scene.camera().position.x = 0;
    	scene.camera().position.y = 0;
    	scene.camera().position.z = 10;

		Bitmap b = Utils.makeBitmapFromResourceId(R.drawable.barong);
		Shared.textureManager().addTextureId(b, "barong", false);
		b.recycle();

		b = Utils.makeBitmapFromResourceId(R.drawable.wood);
		Shared.textureManager().addTextureId(b, "wood", false);
		b.recycle();

		boxes = new Box[5];

		for(int i=0; i<5; i++)
		{
			Box box = new Box(1, 1, 1);
			box.position().x = (float) (-4 + ( Math.random() * 8));
			box.position().y = (float) (-4 + ( Math.random() * 8));
			box.position().z = (i + 1) * -8;
			box.textures().addById("barong");
			box.vertexColorsEnabled(false);
			boxes[i] = box;
	   		scene.addChild(box);
		}

   		Color4 planeColor = new Color4(255, 255, 255, 255);
		Rectangle east = new Rectangle(40, 12, 2, 2, planeColor);
		Rectangle west = new Rectangle(40, 12, 2, 2, planeColor);
		Rectangle up = new Rectangle(40, 12, 2, 2, planeColor);
		Rectangle down = new Rectangle(40, 12, 2, 2, planeColor);

		east.position().x = -6;
		east.rotation().y = -90;
		east.position().z = -20;
		east.lightingEnabled(false);
		east.textures().addById("wood");

		west.position().x = 6;
		west.rotation().y = 90;
		west.position().z = -20;
		west.lightingEnabled(false);
		west.textures().addById("wood");

		up.rotation().x = -90;
		up.rotation().z = 90;
		up.position().y = 6;
		up.position().z = -20;
		up.lightingEnabled(false);
		up.textures().addById("wood");

		down.rotation().x = 90;
		down.rotation().z = 90;
		down.position().y = -6;
		down.position().z = -20;
		down.lightingEnabled(false);
		down.textures().addById("wood");

   		scene.addChild(east);
   		scene.addChild(west);
   		scene.addChild(up);
   		scene.addChild(down);

   		scene.fogColor(new Color4(0, 0, 0, 255) );
   		scene.fogNear(10);
   		scene.fogFar(40);
   		scene.fogEnabled(true);
	}

	@Override
	public void updateScene()
	{
		for(int i=0; i<5; i++)
		{
			Box box = boxes[i];
			box.position().z += .25;
			box.rotation().x++;
			box.rotation().y++;
			if( box.position().z > scene.camera().position.z)
				box.position().z = -40;
		}
	}
}

Min3D for Android: Loading Multiple MD2 files

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.

This was a request from a Min3D user. It’s a short tutorial about how to load multiple animated MD2 files with Min3D. If you don’t know what MD2 files are, then read this.

The .md2 file has to placed in the “res/raw” folder of your Android project. The texture should be in the res/drawable folder. The parser picks up the textures automatically.

The most important bit of code is this:


IParser parser = Parser.createParser(Parser.Type.MD2,
	getResources(), "com.rozengain.min3d:raw/revenant", true);
parser.parse();
AnimationObject3D revenant = parser.getParsedAnimationObject();
scene.addChild(revenant);

First specify the type (Parser.Type.MD2) and the path to the resource (the package name, “raw”, and the resource id (the file name without the extension).
Adding a second MD2 model is done in the exact same way. Here’s the full code:


package com.rozengain.min3d;

import min3d.animation.AnimationObject3d;
import min3d.core.RendererActivity;
import min3d.parser.IParser;
import min3d.parser.Parser;
import min3d.vos.Light;
import min3d.vos.Number3d;

public class MultiMD2Activity extends RendererActivity {
	private AnimationObject3d revenant;
	private AnimationObject3d fatso;

	@Override
	public void initScene() {
		IParser parser = Parser.createParser(Parser.Type.MD2,
				getResources(), "com.rozengain.min3d:raw/revenant", true);
		parser.parse();

		revenant = parser.getParsedAnimationObject();
		revenant.position().x = -1;
		revenant.scale().x = revenant.scale().y = revenant.scale().z = .03f;
		revenant.rotation().z = -90;
		revenant.rotation().x = -90;
		scene.addChild(revenant);

		parser = Parser.createParser(Parser.Type.MD2,
				getResources(), "com.rozengain.min3d:raw/fatso", true);
		parser.parse();

		fatso = parser.getParsedAnimationObject();
		fatso.scale().x = fatso.scale().y = fatso.scale().z = .03f;
		fatso.position().x = 1;
		fatso.rotation().z = -90;
		fatso.rotation().x = -90;
		scene.addChild(fatso);

		Light light = new Light();
    	scene.lights().add(light);

    	scene.camera().position.y = 1;
    	scene.camera().target = new Number3d(0, 1, 0);

    	revenant.setFps(20);
    	revenant.play();
    	fatso.setFps(30);
    	fatso.play();
	}
}

Download the Eclipse project here.

Blender to Objective-C exporter

I’ve been trying to get my head around Objective-C the last two weeks. It’s a language you have to get used to. But, as they say, it grows on you. I’ve also explored OpenGL for the iPhone which is quite awesome. It’s delightful to work on something non-browser based once in a while!

While looking for Objective-C OpenGL resources I found some useful resources that’ll help me developing 3D applications for the iPhone. Jeff LaMarche has created a Python script for my favourite 3D content creation suite, Blender. This script exports Blender objects to Objective-C header files. He’s frequently updating it with new functionality. You can download the plugin here.
On the same blog you can find some good OpenGL tutorials for the iPhone.

Another good tutorial series can be found here.