Intro to J2ME. Prog.
240-571, Semester 2, 2006-2007
M3G. Part 1
Objectives:
– to introduce M3G;
– to start talking about "M3G Chapter 2. An
Animated Model"
leave the floor, penguin, and animation
details until next time
240-571 J2ME: M3G/1 1
1. Features
M3G: the Mobile 3D Graphics API
– developed as JSR-184
– present in WTK 2.2 and later
– a combination of high-level and low-level
features
retained and immediate modes
– combined with J2ME via the Canvas or
GameCanvas classes
240-571 J2ME: M3G/1 2
No callbacks
No separate rendering thread
– so you must code your own animation loop
using a timer or a thread
Requires CLDC 1.1. for floats
– make sure to select it in the WTK
240-571 J2ME: M3G/1 3
Two Modes
Retained Mode (high-level API)
– build a 3D scene by building a scene graph
– the scene graph is rendered automatically
– similar to Java 3D, but a much smaller API
and a few extras
Immediate Mode (low-level API)
– based on OpenGL ES
– no scene graph data structure
240-571 J2ME: M3G/1 4
Scene Graph Example
a World object
World is the top node
Group Camera Light Light
Mesh Group
Mesh Sprite
240-571 J2ME: M3G/1 5
Mesh: a 3D model
– subclasses: morphing mesh, skinned mesh
Sprite:a 2D image
A Group is a useful way of grouping objects
so they can be transformed with a single
operation.
Typical transformations:
– scaling, rotation, translation
– animation based on key frames
240-571 J2ME: M3G/1 6
Mesh Details
Appearance
Mesh
VertexBuffer Material
composed composed
of IndexBuffer 1 or more
of PolygonMode
Appearance 1 or more
CompositingMode
VertexBuffer
positions
VertexArray Fog
composed normals
of VertexArray 0 or 1 Texture2D Image2D
colours
1 or more
VertexArray 0 or 1
tex. coords.
VertexArray 0 or more
240-571 J2ME: M3G/1 7
2. WTK 2.2 Examples
Life3D
– the Game of Life in 3D
PogoRoo
– a kangaroo bouncing on a pogo stick
retainedmode
– animates a skateboarder model
a M3D file
240-571 J2ME: M3G/1 8
Hello World
public class Test extends MIDlet
{
private MyCanvas c = new MyCanvas();
protected void startApp()
{ Display.getDisplay(this).setCurrent(c); }
protected void pauseApp() {}
protected void destroyApp() {}
}
240-571 J2ME: M3G/1 9
public class MyCanvas extends Canvas
{
private Graphics3D iG3D; // for rendering
private World scene; // for the scene graph
public MyCanvas()
{ iG3D = Graphics3D.create();
scene = (World) Loader.load(”/w.m3d”)[0];
}
protected void paint(Graphics g)
{ iG3D.bindTarget(g);
iG3D.render( scene );
iG3D.releaseTarget(); // flush
}
}
240-571 J2ME: M3G/1 10
Animated World
public class Test extends MIDlet
{
MyCanvas c = new MyCanvas();
MyTimer updater = new MyTimer();
. . .
private class MyTimer extends TimerTask {
public MyTimer()
{ new Timer().schedule(this,0,40); } // 40ms
public void run()
{ c.repaint(); }
}
}
240-571 J2ME: M3G/1 11
public class MyCanvas extends Canvas
{
int time = 0;
. . .
protected void paint(Graphics g)
{
iG3D.bindTarget(g);
scene.animate(time += 40); // 25 fps
iG3D.render( scene );
iG3D.releaseTarget();
}
}
240-571 J2ME: M3G/1 12
3. M3G Chapter 2. An Animated Model
Make a penguin walk in circles
http://fivedots.coe.psu.ac.th/~ad/jg/m3g2/
240-571 J2ME: M3G/1 13
3.1. Features
Uses retained mode.
The scene includes a single directional light,
a textured floor, a light blue background
– or an image background
Mixes M3G rendering and MIDP's
drawString()
Penguin model is an animated Mesh
– it translates and rotates
240-571 J2ME: M3G/1 14
AnimM3G Class Diagrams
TimerTask
MIDlet
Canvas
CommandListener
240-571 J2ME: M3G/1 15
Scene Graph
scene World scene graph
children
Background Light Camera
Mesh Group animated
floorMesh transRotGroup
built by the Mesh model
Floor class
built by the AnimModel class
240-571 J2ME: M3G/1 16
3.2. AnimCanvas Constructor
private World scene; // global variable
public AnimCanvas(...)
{
// ... other code
scene = new World();
buildScene();
// ... other code
}
240-571 J2ME: M3G/1 17
private void buildScene()
// add nodes to the scene graph
{
addCamera();
addLight();
addBackground();
animModel = new AnimModel();
scene.addChild(
animModel.getModelGroup() );
// add the model
addFloor();
} // end of buildScene()
240-571 J2ME: M3G/1 18
3.3. Adding the Camera
private void addCamera()
{
Camera cam = new Camera();
float aspectRatio =
((float) getWidth()) / ((float) getHeight());
cam.setPerspective(70.0f, aspectRatio, 0.1f, 50.0f);
cam.setTranslation(0.0f, 0.5f, 2.0f); // up and back
// cam.setOrientation(-10.0f, 1.0f, 0, 0);
// angle downwards slightly
scene.addChild(cam);
scene.setActiveCamera(cam);
}
240-571 J2ME: M3G/1 19
AnimM3G Viewed from Above
cam.setTranslation(0.0f, 5.0f, 0.0f);
cam.setOrientation(-90.0f, 1.0f, 0, 0);
240-571 J2ME: M3G/1 20
3.4. Adding a Light
private void addLight()
{
Light light = new Light();
// default white, directional light
light.setIntensity(1.25f);
// make it a bit brighter
light.setOrientation(-45.0f, 1.0f, 0, 0);
// down and into scene
scene.addChild(light);
}
240-571 J2ME: M3G/1 21
3.5. Adding a Background
private void addBackground()
{
Background backGnd = new Background();
backGnd.setColor(0x00bffe);
// a light blue background
scene.setBackground(backGnd);
}
240-571 J2ME: M3G/1 22
Clouds in the BackGround
240-571 J2ME: M3G/1 23
A Background Image
private void addBackground()
{
Background backGnd = new Background();
Image2D backIm = loadImage("/clouds.gif");
// cloudy blue sky
if (backIm != null) {
backGnd.setImage(backIm);
backGnd.setImageMode(Background.REPEAT,
Background.REPEAT);
}
else
backGnd.setColor(0x00bffe);
// a light blue background
scene.setBackground(backGnd);
}
240-571 J2ME: M3G/1 24
private Image2D loadImage(String fn)
{
Image2D im = null;
try {
im = (Image2D) Loader.load(fn)[0];
}
catch (Exception e)
{ System.out.println(
"Cannot make image from " + fn); }
return im;
} // end of loadImage()
240-571 J2ME: M3G/1 25
3.6. Adding the Floor
private void addFloor()
{
Image2D floorIm = loadImage("/bigGrid.gif");
// large, so slow to load
Floor f = new Floor( floorIm, 8); //8 by 8 sz
// Image2D floorIm = loadImage("/grass.gif");
// or try "/floor.png"
// Floor f = new Floor( floorIm, 6);// 6 by 6
scene.addChild( f.getFloorMesh() );
}
240-571 J2ME: M3G/1 26
The Floor Grid Image
240-571 J2ME: M3G/1 27
3.7. Adding the Penguin
// global for translating and rotating the model
private Group transRotGroup;
public AnimModel()
{
// other code ...
Mesh model = makeModel();
// reposition the model's start position and size
model.setTranslation(0.25f, 0.25f, 0.25f);
// so at center
model.scale(0.5f, 0.5f, 0.5f);
// translation/rotation group for the model
transRotGroup = new Group();
transRotGroup.addChild(model);
// other code ...
}
240-571 J2ME: M3G/1 28
Changing the Penguin's Position
Mesh model = makeModel();
// reposition the model's start position and size
model.setTranslation(0.25f, 0.25f, 0.25f); // so at center
model.scale(0.5f, 0.5f, 0.5f);
240-571 J2ME: M3G/1 29
3.8. Updating the Application
paint()
{ // render the 3D scene
AnimCanvas
// draw 2D info. string
}
KVM repaint request
update()
{ // increment world time
AnimCanvas // call animate() on world
// call repaint()
}
update the canvas
AnimTimer run()
(in AnimM3G) { animCanvas.update(); }
call run() every PERIOD ms
240-571 J2ME: M3G/1 timer 30
AnimCanvas
// global timing information
private int appTime = 0;
private int nextTimeToAnimate;
public AnimCanvas(AnimM3G top)
{ // other code...
// start the animation
nextTimeToAnimate = scene.animate(appTime);
}
public void update()
// called by TimerTask every PERIOD (50) ms
{ appTime++;
if (appTime >= nextTimeToAnimate) {
nextTimeToAnimate =
scene.animate(appTime) + appTime;
repaint();
}
}
240-571 J2ME: M3G/1 31
Rendering the Scene
private Graphics3D iG3D; // global
public AnimCanvas(AnimM3G top)
{ // other code...
iG3D = Graphics3D.getInstance();
}
protected void paint(Graphics g)
{ iG3D.bindTarget(g);
try {
iG3D.render(scene);
}
catch(Exception e) safer coding style
{ e.printStackTrace(); }
finally {
iG3D.releaseTarget();
}
// show the model's coordinates in MIDP
g.drawString( animModel.getPosition(),
5,5, Graphics.TOP|Graphics.LEFT);
}
240-571 J2ME: M3G/1 32