I hadn’t actually planned a 3rd part to this series, but Dennis Ippel kindly spent some time looking at the code posted in the last post, to see where optimisations might be made to increase the sphere count.
Consequently, Dennis made some changes to the Rajawali framework to support batch rendering of objects, as well as suggesting some client-side changes that make use of object cloning to avoid the need for replicated vertex buffers, index buffers, textures, etc. – all properties/dependent objects that the code was previously creating per sphere.
The results were stunning: with really a modest change to the client code (and an update to the Rajawali library, of course), the geometry creation phase has been sped up significantly and the app can now load up to Level 10 packings on my Kindle Fire. Although the frame-rate is down around a single frame-per-second, should you actually try to do anything with the model. But hey. :-)
Here is the only function that needed updating:
private void createSphere(
float x, float y, float z, float radius,
int level, boolean isRoot
)
{
if (isRoot && mRootSphere != null)
return;
BaseObject3D sphere = null;
if (mRootSphere == null)
{
// Create our initial sphere
sphere = new Sphere(radius, 9, 9);
sphere.setScale(radius);
sphere.getMaterial().setUseColor(true);
sphere.setRenderChildrenAsBatch(true);
mRootSphere = sphere;
}
else
{
// Cloning re-uses vertex buffers, index buffers,
// textures, etc.
sphere = mRootSphere.clone();
sphere.setScale(radius);
}
sphere.setScale(sphere.getScale().multiply(100f));
sphere.setX(x);
sphere.setY(y);
sphere.setZ(z);
// Add our light
sphere.addLight(mLight);
// Set the material and color
sphere.setColor(level > 10 ? Color.WHITE : mColors[level], true);
// Make it our root sphere or add it as a child
if (isRoot)
{
mRootSphere = sphere;
addChild(mRootSphere);
}
else if (mRootSphere != null)
{
mRootSphere.addChild(sphere);
}
}
Here are some screenshots of these higher levels:
With a couple of close-ups of the detail on Level 10:
I still get some quirks where the spheres don’t all come in when loading a particular level (and that’s from Level 6 upwards), but I strongly suspect this is due to inherent limitations of the Kindle Fire (which is a fairly modest device, as far as Android tablets go).
Here’s the updated .apk file, and the complete project, as it currently stands. I was going to update the application to target a lower version of Android, but it seems Rajawali requires at least 2.2, in any case (and my current target is 2.3.3). If anyone really needs a version for 2.2, do let me know.
By the way – some of you may be wondering why the difference is fairly modest between Levels 9 and 10, in terms of the number of spheres created: this is because we set a lower radius threshold of 0.01, which – as we’re only generating the data for a radius of 1.0 and reusing that for other radii – means we will only return spheres as small as 1% of the provided radius, nothing smaller. We could very easily adjust this on the server, of course, which would clearly lead to more data being downloaded, particularly for these higher levels.
I’ve now started work on an iOS version of the app, or at least trying to identify an appropriate, open-source 3D engine that keeps me away from making calls to OpenGL ES directly. Hopefully I’ll have something to share sometime next week.