|
3D Graphics in J2ME
An Introduction |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
Graphics3D class has a
getInstance() method that returns the
singleton Graphics3D object
render() method renders a
VertexBuffer containing a shape
setCamera() method is used to set
the position of the viewer
setLight() method is used to
bind/unbind lights
VertexArray:
VertexArray contains positions, colors,
normals, or texture coordinates for vertices
VertexBuffer:
VertexBuffer holds references
to the VertexArray objects (one of each "type")
needed to define a shape
Transform:
Camera:
Material:
Texture2D:
Appearance:
Material object, Texture2D
object, etc...
Light:
package java3d;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import drivers.*;
/**
* A simple example of immediate mode rendering using the
* Mobile 3D Graphics API for J2ME
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class CubeCanvas extends Canvas implements AnimatorObserver
{
private Appearance appearance;
private Background background;
private float angle;
private Graphics3D g3;
private IndexBuffer indexBuffer;
private Transform rotation;
private VertexBuffer cube;
// The vertices for the cube using a triangle strip that is organized
// as follows:
//
// 1 0
// o-------o
// | \ |
// | \ |
// | \ |
// o-------o
// 3 2
//
private static short[] vertices = {
1, 1, 1, -1, 1, 1, 1,-1, 1, -1,-1, 1, // Front
-1, 1,-1, 1, 1,-1, -1,-1,-1, 1,-1,-1, // Back
-1, 1, 1, -1, 1,-1, -1,-1, 1, -1,-1,-1, // Left
1, 1,-1, 1, 1, 1, 1,-1,-1, 1,-1, 1, // Right
1, 1,-1, -1, 1,-1, 1, 1, 1, -1, 1, 1, // Top
1,-1, 1, -1,-1, 1, 1,-1,-1, -1,-1,-1 // Bottom
};
private static int[] stripLengths = { 4, 4, 4, 4, 4, 4 };
// The normals
private static byte[] normals = {
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // Front
0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, // Back
-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // Left
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // Right
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // Top
0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0 // Bottom
};
/**
* Default Constructor
*/
public CubeCanvas()
{
// Add the Exit command to the menu
addCommand(new Command("Exit", Command.EXIT, 1));
// Initalize the rendering engine
init();
// Initialize the cube
createCube();
}
/**
* Handle a "tick" from the Animator
*/
public void animate()
{
repaint();
}
/**
* Create a cube
*/
private void createCube()
{
Material material;
VertexArray normalArray, vertexArray;
// Create a VertexArray for the vertices
vertexArray = new VertexArray(vertices.length/3, 3, 2);
vertexArray.set(0, vertices.length/3, vertices);
// Create a VertexArray for the normals
normalArray = new VertexArray(normals.length/3, 3, 1);
normalArray.set(0, normals.length/3, normals);
// Create the VertexBuffer for the cube
cube = new VertexBuffer();
cube.setPositions(vertexArray, 1.0f, null);
cube.setNormals(normalArray);
// Create the IndexBuffer for the cube
indexBuffer = new TriangleStripArray( 0, stripLengths );
// Create the Material for the cube
material = new Material();
material.setColor(Material.DIFFUSE, 0xC2A14D); // JMU Gold
material.setColor(Material.SPECULAR, 0xFFFFFFFF); // White
material.setShininess(100.0f);
// Create the Appearance for the cube
appearance = new Appearance();
appearance.setMaterial(material);
}
/**
* Initialize the rendering engine
*/
private void init()
{
Camera camera;
float aspect;
Light light;
Transform cameraTranslation;
angle = 0.0f;
// Create the Background
background = new Background();
background.setColor(0x450084); // JMU Purple
// Create the rotational transform
rotation = new Transform();
// get the singleton Graphics3D instance
g3 = Graphics3D.getInstance();
// Create the Camera
aspect = (float)getWidth()/ (float)getHeight();
camera = new Camera();
camera.setPerspective(60.0f, // Field of View (Vertical)
aspect, // Aspect Ratio
1.0f, // Near Clipping Plane
1000.0f ); // Far Clipping Plane
// Move the camera
cameraTranslation = new Transform();
cameraTranslation.postTranslate(0.0f, 0.0f, 3.0f);
g3.setCamera(camera, cameraTranslation);
// Create a light at the camera position
g3.resetLights();
light = new Light();
light.setColor(0xFFFFFF);
light.setIntensity(1.0f);
g3.addLight(light, cameraTranslation);
}
/**
* Render this component
*
* @param g The underlying rendering engine
*/
protected void paint(Graphics g)
{
// Bind the Graphics object to the Graphics3D object
g3.bindTarget(g, true, Graphics3D.DITHER |Graphics3D.TRUE_COLOR);
// Clear the pixel and depth buffers
g3.clear(background);
// Rotate the cube
angle += 1.0f;
rotation.setIdentity();
rotation.postRotate(angle,
1.0f, 0.0f, 0.0f); // Rotate around the x-axis
// Render the cube
g3.render(cube, indexBuffer, appearance, rotation);
// Flush the rendering engine
g3.releaseTarget();
}
}
MIDlet
package drivers;
import java.util.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java3d.*;
/**
* A simple example of immediate mode rendering using the
* Mobile 3D Graphics API for J2ME
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class CubeDriver extends MIDlet implements CommandListener
{
Animator animator;
CubeCanvas canvas;
Timer timer;
/**
* Default Constructor
*/
public CubeDriver()
{
// Construct the Displayable
canvas = new CubeCanvas();
canvas.setCommandListener(this);
// Construct the Timer
timer = new Timer();
// Construct the Timer "callback"
animator = new Animator(canvas);
}
/**
* Handle commandAction events
* (required by CommandListener)
*
* @param c The Command
* @param d The Displayable that generated the event
*/
public void commandAction(Command c, Displayable d)
{
if (c.getCommandType() == Command.EXIT)
{
destroyApp(true);
}
}
/**
* Destroy this MIDlet
*/
public void destroyApp(boolean unconditional)
{
}
/**
* Entry point
*/
public void startApp()
{
Display.getDisplay(this).setCurrent(canvas);
timer.schedule(animator, 0, 40 );
}
/**
* Pause this MIDlet
*/
public void pauseApp()
{
}
}
World class
Group class
AnimationController
AnimationTrack
KeyframeSequence