In order to get started porting my engine to JME, understanding this example seems like a very good start. It’s also a quick, hands on way to understand M3G and the blender exporter. So I’ll replace the Pogoroo by one of the sample files associated with the blender exporter. This will break the app and I’ll learn how it works by fixing it.
Please refer to my last article for links to this example — won’t be much use if we’re not looking at the code together.
I really liked the Pogoroo example. Apparently this was originally provided by Superscape, and somehow bundle in Sun’s edition of the JME before landing in the Samsung SDK.
I also like the blender M3G exporter. So I did this…
myWorld = (World)Loader.load(“/com/superscape/m3g/wtksamples/pogoroo/content/bebe.m3g”);
//myWorld = (World)Loader.load(“/com/superscape/m3g/wtksamples/pogoroo/content/pogoroo.m3g”);
…after trying this:
myWorld = (World)Loader.load(“c:/bebe.m3g”); // replace by sample model exported from blender.
Since an absolute path doesn’t work, we can tell that there’s a configuration bit somewhere setting the path for resources.
Now, you’d figure that we can’t replace the original model by another one, and you’re almost right. Except instead of a black screen we get a very cute 3D rendering of a Penguin (Pingoo?) and an engaging exception.
So I think we’re set. We have a working JME project manager, a working simulator and a working assets exporter. Time to understand some of this stuff. Now, this is what triggers an exception:
tRoo = (Group)myWorld.find(POGOROO_MOVE_GROUP_TRANSFORM_ID);
tCams = (Group)myWorld.find(CAMERA_GROUP_TRANSFORM_ID);
acRoo = (Group)myWorld.find(POGOROO_TRANSFORM_ID);
animRoo = (AnimationController)myWorld.find(ROO_BOUNCE_ID);
I haven’t looked at JSR184 in the past 5 years or more, and I never actually used JSR184. The beauty of it is that it doesn’t require an explanation(?).
Here’s what I’m finding:
- I moved the camera in the original blender file and exported again. The camera updates in the MIDlet, so this camera is actually in use.
- None of the above calls (tRoo = etc…) does actually trigger an exception, so they’ll just be returning null (I don’t have a debugger setup and line numbers seem wrong, so I’m tracing)
Surely this would trigger a NullPointerException at this point.
AnimationTrack track=null; // changed this way because there is already code to provide defaults instead.
//AnimationTrack track = acRoo.getAnimationTrack(0); // exception!
Once modified as above, we don’t have an exception anymore. We can use the phone simulator’s controls to try to move the Pingoo and it obviously doesn’t budge. More worrying, we don’t get an exception either.
I want to reassign tRoo, tCams, cRoo, animRoo. If we can do that, we’ll know that we know for sure how the exporter generates IDs. But before that I’m really curious to find out why trying to operate the controls doesn’t throw an exception.
So I started tracing this stuff again, and I found that exceptions raised within RefreshTask‘s run() method (Oh my… they use a timer for that!?) aren’t displayed. We can catch them though.
So what do we need?
This is what gets extracted first:
private AnimationController animRoo; // 5, 18
private Group tRoo;
private Group tCams;
private Group acRoo;
In my last article I mentionned that the blender M3G exporter allows the user to specify a user ID for scene nodes – scene nodes are retrieved using an integer – a (hopefully) unique identifier. The Pogoroo example demonstrates the same idea.
I missed several interesting facts about the exporter and the provided example last time:
- The exporter assigns ID 0 to anything that doesn’t have a user defined ID (so much for unique IDs?)
- In the provided example 2 nodes have ID 1. One is the armature controlling the Pingoo, the other is an animation controller.
The exporter displays export related data (includings IDs) in the blender console. Rudimentary, but it helps.
The first item I managed to rebind was animRoo. I used the second animation in the blender file, and this works easily because it has ID 2 by default, and that is a unique ID.
Bound a transform group for the camera (tCams)
In the blender scene browser (I’ll post a screenshot), any object seems to be living under a transform group. However, although tCams expects a transform group, the exporter doesn’t create one for the camera. Instead the transform and the camera seem collapsed to one node.
So I added an ‘Empty’ in blender and parented it from the camera (so the camera is a child of the empty). I named this Empty#25 (25 is an arbitrary int I came up with and voila I managed to bind my camera group.
tRoo and acRoo
I have these two left. Now I have nodes for both the armature and the Pingoo, but they’re not groups. Since I already got into this trap, I thought OK, why should we have two transforms for the Pingoo. Not diving deeper into the code, I’m just guessing there’s an inner transform for the rotation, and an outer transform for the translation. So I made two empties, further complicating the transform hierarchy, but maybe necessary to get this to work. I ‘named’ them 200, 201 and updated the static ints in the java file.
I wouldn’t say this feels like it works as I expected. However…
At the next run, several interesting things happen:
- I can see the little Pingoo moving it’s beak. So our animation is working out, big time!
- Left/Right keys appear to rotate the Pingoo
- Top/Down appear to move the Pingoo
I write ‘appear to’ because these behaviors seem somehow incorrect. I put the camera back in place (facing the pingoo) and moved the transforms (aka tRoo, acRoo) to coincide with the Pingoo’s vertical axis.
My cute project manager seems to be getting moody. Also, when I check my process my manager, I find 4 (yes, four!) instances of java running simultaneously. Admittingly they don’t seem very busy, but that’s just a cherry on top of weird taskbar widgets that I didn’t have before installing the JME SDKs (three of these).
Guess I’ll try a ‘cold start’.
I checked things up after restarting the IDE. The Pingoo is moving along the wrong axis (got bold enough to actually add some terrain so I could get a fair idea). It’s rotating too, but somehow I’m not convinced the camera is following as it should. This seems to be down to axis orientations (and assumptions the ‘game logic’ makes about it).
There’s a lot of good stuff in here. JSR184 clearly supports bone animation, textures and lighting (looks horrible in the simulator) out of the box, never mind a well formed scene-graph. Plus, the exporter gets it right too, although I really need to do something about these IDs.
My engine maybe implements 10% of all this stuff, not to say anything about my exporter. So porting the engine ‘facade’ and reimplementing my game logic on top of that may be much easier than I anticipated. Proof also, than 10% of a game engine can run a pretty nice game. OK… I do have quite a bit of stuff in there that’s clearly not scoped under “3D rendering” :)
The frame rate is defeating in the simulator, but it doesn’t say much about how it would look on a phone.