|
JSR-184 Public Review Draft - Apr. 30, 2003. | ||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
Class Summary | |
AnimationController | A set of methods for controlling multiple AnimationTracks as one. |
AnimationTrack | AnimationTrack associates a KeyframeSequence with an animatable property, and an AnimationController that controls the sequence. |
Appearance | Appearance defines attributes that are needed for rendering a Mesh or Sprite. |
Background | Attributes for clearing the color buffer. |
Camera | Camera defines parameters for projecting the 3D world to the display. |
CompositingMode | An Appearance component encapsulating per-pixel compositing attributes. |
Fog | An Appearance component encapsulating attributes for fogging. |
GeometryMode | An Appearance component encapsulating polygon-level attributes. |
Graphics3D | A singleton 3D graphics context that can be bound to a rendering target. |
Group | The Group node stores an unordered set of nodes as its children in the scene graph. |
Image2D | A two-dimensional image that can be used as a texture, background or sprite image. |
IndexBuffer | IndexBuffer defines how to connect vertices in a VertexBuffer to form 3D surface primitives, such as triangles. |
KeyframeSequence | KeyframeSequence encapsulates animation data as a sequence of time-stamped, vector-valued keyframes. |
Light | The Light node represents different kinds of light sources. |
Loader | A synchronous loader (deserializer) for entire scene graphs, individual branches, and attribute objects. |
Material | An Appearance component encapsulating material attributes for lighting computations. |
Mesh | Mesh is a renderable 3D geometry object, defined as a polygonal surface. |
MorphingMesh | A vertex morphing mesh. |
Node | An abstract base class for scene graph nodes, that is, instances of objects in a scene graph. |
Object3D | An abstract base class for all objects that can be part of a 3D world. |
RayIntersection | A RayIntersection object is filled in by the pick methods in Group
and Camera. |
SkinnedMesh | A skeletally animated mesh. |
Sprite | Sprite is a scene graph node representing a 2-dimensional image that has a 3D position. |
Texture2D | An Appearance component encapsulating a two-dimensional texture image and a set of attributes specifying how the image is to be applied on submeshes. |
Transform | A generic 4x4 floating point matrix, representing a transformation. |
TriangleStripArray | TriangleStripArray defines a set of triangle strips. |
VertexArray | An array of integer vectors representing vertex positions, normals, colors, or texture coordinates. |
VertexBuffer | VertexBuffer holds references to VertexArrays that contain the positions, colors, normals, and texture coordinates for a set of vertices. |
World | A top-level container for scene graphs. |
This package contains the whole Mobile 3D Graphics API (M3D), comprising about 250 methods in about 30 classes.
The function of this API is to provide Java application programmers with an efficient and flexible means to display animated 3D graphics in real time on embedded devices. To cater for the needs of different types of applications, both an easy-to-use scene graph structure and an immediate mode interface are provided. All animation and rendering features are available for scene graph objects and individually rendered objects alike.
In addition to the API itself, JSR-184 also defines a corresponding file format for efficient storage and transfer of all necessary data. This includes meshes, textures, scene hierarchies, material properties, animation data, and so on. Data is written into a file by content creation tools on a PC, and loaded into the API through the Loader class.
A good place to start reading the specification is in the example
applications at the end of this overview page. Of the individual classes,
Graphics3D
is perhaps the most important, because
all rendering is done there. The World
class is
crucial because it serves as the root of the scene graph structure. Object3D
is the base class of all objects that can
be rendered or loaded from a file, and also the place where animations are
applied. We also recommend you to read the short section about documentation
conventions below.
Null parameters. By default, all methods will throw a NullPointerException if a null object is passed in, either by itself or as an array element. NullPointerException is therefore not listed in any of the method descriptions. In cases where the treatment of null objects is different from the default, the behavior is documented explicitly at the level of individual methods.Deferred exceptions. Most exceptions are thrown immediately upon method invocation, when erroneous input is detected. However, the application is in some cases allowed to bring an object, or an aggregate of objects, into an invalid state. There are two operations that may throw an exception as a result of their input being in an invalid state: the render methods in Graphics3D and the pick methods in Group and Camera.
Matrix notation. Matrices are denoted as upper case bold letters, and vectors as lower case bold letters. For example, M denotes a matrix and v a vector. Matrices have 4x4 and vectors 4 elements, unless stated otherwise. Vectors are always column vectors, and are consequently multiplied from the left: v' = M × v.
Numeric ranges. Closed numeric ranges are denoted with square brackets and open ranges with round brackets. For example, [0,10) denotes the values from zero to ten, including zero but not including ten. Depending on the context, a numeric range may include all real numbers or only integers.
OpenGL references. All references to OpenGL in this documentation are to version 1.3. The OpenGL 1.3 specification is available here.
Coordinate systems. All 2D coordinate systems follow the MIDP convention where the origin is in the upper left corner and integer coordinates are at pixel boundaries. By default, the 3D coordinate systems are right-handed, and all rotations obey the right-hand rule: looking down the axis of rotation, positive angles are clockwise. However, the application is free to set up a left-handed 3D coordinate system by use of transformation matrices.
Diagram notation. The following common notation is used in diagrams that involve scene graph nodes and node components.
The input range must be at least [2-64, 263]. Any floating-point value in this range is legal as input to a method that requires floating point data. If the input value is not within that range, or is not a floating-point number, the results are undefined.These requirements apply to all arithmetic operations in this API, unless explicitly specified otherwise. In particular, they apply to node transformations in the scene graph, all vertex coordinate transformations, and all methods in the Transform class. These requirements do not apply to triangle rasterization and per-fragment operations, such as blending.Elementary operations must have a range of at least [2-64, 263]. If the operands and the result of an elementary arithmetic operation are within this range, the operation must not overflow or underflow. If the operands or the result are not within that range, the result is undefined.
The precision must be at least 16 significant bits. Provided that the operands and the result of an elementary arithmetic operation are within the range specified above, the result must be accurate to at least 16 significant bits.
All blending arithmetic is done component-wise and saturated to 1.0. Precision is not specified strictly, but the implementation must guarantee that the following holds true for all values of alpha and s between [0, 1]:
alpha × s + (1 - alpha) × s = s
The other example MIDlet is a retained mode application that plays back a ready-made animation that it downloads over http.
import javax.microedition.lcdui.*; import javax.microedition.m3d.*; public class MyCanvas extends Canvas { private Graphics3D iG3D; private Camera iCamera; private float iAngle = 0.0f; private Transform iTransform = new Transform(); private Background iBackground = new Background(); private VertexBuffer iVb; // vertex positions, normals, colors, texcoords private IndexBuffer iIb; // indices to VertexBuffer, forming tri-strips private Appearance iAppearance; // material, texture, compositing, etc. private Material iMaterial = new Material(); private Image iImage; // Construct the displayable public MyCanvas() { // set up this Displayable to listen to command events setCommandListener(new CommandListener() { public void commandAction(Command c, Displayable d) { if (c.getCommandType() == Command.EXIT) { // exit the MIDlet MIDletMain.quitApp(); } } }); try { init(); } catch(Exception e) { e.printStackTrace(); } } // Component initialization private void init() throws Exception { // add the Exit command addCommand(new Command("Exit", Command.EXIT, 1)); // set up the Graphics3D iG3D = Graphics3D.createGraphics3D(); // create a camera iCamera = new Camera(); iCamera.setPerspective( 60.0f, // field of view (float)getWidth()/ (float)getHeight(), // aspectRatio 1.0f, // near clipping plane 1000.0f ); // far clipping plane // create a transform for the camera Transform transform = new Transform(); transform.translate( 0.0f, 0.0f, 30.0f ); // set the camera for the Graphics3D and transform it to the desired position iG3D.setCamera( iCamera, transform ); // create a light to light the scene Light light = new Light(); light.setDirectionalEnable( true ); // the light is directional light.setColor( 0xffffff ); // white light light.setIntensity(1.25f); // set the intensity of the light // set the zeroth light for the Graphics3D iG3D.setLight( 0, light, transform ); // same position as the camera // init some arrays for our object (cube) // Each line in this array declaration represents a triangle strip for // one side of a cube. The only primitive we can draw with is the // triangle strip so if we want to make a cube with hard edges we // need to construct one triangle strip per face of the cube. // 1 * * * * * 0 // * * * // * * * // * * * // 3 * * * * * 2 // The ascii diagram above represents the vertices in the first line // (the first tri-strip) short[] vert = { 10, 10, 10, -10, 10, 10, 10,-10, 10, -10,-10, 10, // front -10, 10,-10, 10, 10,-10, -10,-10,-10, 10,-10,-10, // back -10, 10, 10, -10, 10,-10, -10,-10, 10, -10,-10,-10, // left 10, 10,-10, 10, 10, 10, 10,-10,-10, 10,-10, 10, // right 10, 10,-10, -10, 10,-10, 10, 10, 10, -10, 10, 10, // top 10,-10, 10, -10,-10, 10, 10,-10,-10, -10,-10,-10 }; // bottom // create a VertexArray to hold the vertices for the object VertexArray vertArray = new VertexArray( vert.length / 3, 3, 2 ); vertArray.set( 0, vert.length/3, vert ); // The per-vertex normals for the cube; these match with the vertices // above. Each normal is perpendicular to the surface of the object at // the corresponding vertex. byte[] norm = { 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0 }; // create a vertex array for the normals of the object VertexArray normArray = new VertexArray( norm.length / 3, 3, 1 ); normArray.set( 0, norm.length/3, norm ); // per vertex texture coordinates short[] tex = { 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1 }; // create a vertex array for the texture coordinates of the object VertexArray texArray = new VertexArray( tex.length / 2, 2, 2 ); texArray.set( 0, tex.length/2, tex ); int[] stripLen = { 4, 4, 4, 4, 4, 4 }; // the length of each triangle strip // create the VertexBuffer for our object VertexBuffer vb = iVb = new VertexBuffer(); vb.setPositions( vertArray, 1.0f, null ); // unit scale, zero bias vb.setNormals( normArray ); vb.setTexCoords( 0, texArray, 1.0f, null ); // unit scale, zero bias // create the index buffer our object (this tells how to create triangle // strips from the contents of the vertex buffer). iIb = new TriangleStripArray( 0, stripLen ); // load the image for the texture iImage = Image.createImage( "/texture.png" ); // create the Image2D (we need this so we can make a Texture2D) Image2D image2D = new Image2D( Image2D.FORMAT_RGB, iImage ); // create the Texture2D and enable mipmapping // texture color is to be modulated with the lit material color Texture2D texture = new Texture2D( image2D ); texture.setFiltering( Texture2D.FILTER_NEAREST, Texture2D.FILTER_NEAREST ); texture.setWrapping( Texture2D.WRAP_CLAMP, Texture2D.WRAP_CLAMP ); texture.setBlending( Texture2D.FUNC_MODULATE ); // create the appearance iAppearance = new Appearance(); iAppearance.setTexture( 0, texture ); // add the Texture2D to the Appearance iAppearance.setMaterial(iMaterial); iMaterial.setVertexColorTrackingEnable( true ); // track per-vertex colors iMaterial.setColor(Material.SPECULAR, 0xFFFFFFFF); // specular = white iMaterial.setShininess(100.0f); iBackground.setColor( 0xf54588 ); // set the background color } // paint the scene protected void paint(Graphics g) { iG3D.setTrueColorEnable( true ); // true color rendering iG3D.setDitheringEnable( true ); // combined with dithering iG3D.setAntialiasingEnable( false ); // but no antialiasing // Bind the Graphics of this Canvas to our Graphics3D. The viewport // is automatically set to cover the entire clipping rectangle of the // Graphics object. iG3D.bindTarget( g ); // clear the color and depth buffers iG3D.clear( Graphics3D.BUF_COLOR | Graphics3D.BUF_DEPTH, iBackground ); // update our transform (this will give us a rotating cube) iAngle += 1.0f; iTransform.setIdentity(); iTransform.rotate( iAngle, // rotate 1 degree 1.0f, 1.0f, 1.0f ); // rotate around this axis // Render our cube. We provide the vertex and index buffers to specify // the geometry; the appearance so we know what material and texture to // use; and the transform to tell where to render the object iG3D.render( iVb, iIb, iAppearance, iTransform ); // flush iG3D.releaseTarget(); } }
import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import java.util.*; public class MIDletMain extends MIDlet { static MIDletMain instance; MyCanvas displayable = new MyCanvas(); Timer iTimer = new Timer(); /**Construct the midlet*/ public MIDletMain() { this.instance = this; } /**Main method*/ public void startApp() { Display.getDisplay(this).setCurrent(displayable); iTimer.schedule( new MyTimerTask(), 0, 40 ); } /**Handle pausing the MIDlet*/ public void pauseApp() { } /**Handle destroying the MIDlet*/ public void destroyApp(boolean unconditional) { } /**Quit the MIDlet*/ public static void quitApp() { instance.destroyApp(true); instance.notifyDestroyed(); instance = null; } // our timer task for providing animation class MyTimerTask extends TimerTask { public void run() { if( displayable != null ) { displayable.repaint(); } } } }
import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.CommandListener; import java.util.Timer; import java.util.TimerTask; import javax.microedition.m3d.*; public class JesterTestlet extends MIDlet implements CommandListener { private Display myDisplay = null; private JesterCanvas myCanvas = null; private Timer myRefreshTimer = new Timer(); private TimerTask myRefreshTask = null; private Command exitCommand = new Command("Exit", Command.ITEM, 1); private Graphics3D myGraphics3D = null; private World myWorld = null; /** * JesterTestlet - default constructor. */ public JesterTestlet() { // Set up the user interface. myDisplay = Display.getDisplay(this); myCanvas = new JesterCanvas(this); myCanvas.setCommandListener(this); myCanvas.addCommand(exitCommand); } /** * startApp() */ public void startApp() throws MIDletStateChangeException { myDisplay.setCurrent(myCanvas); try { // Load a file. Object3D[] roots = Loader.load("http://www.example.com/m3d/samples/simple.m3d"); // Assume the world is the first root node loaded. myWorld = (World)roots[0]; // Create the Graphics3D instance and set rendering quality hints. myGraphics3D = Graphics3D.createGraphics3D(); myGraphics3D.setTrueColorEnable(false); myGraphics3D.setDitheringEnable(false); myGraphics3D.setAntialiasingEnable(false); // Force a repaint so that we get the update loop started. myCanvas.repaint(); } catch(Exception e) { e.printStackTrace(); } } /** * pauseApp() */ public void pauseApp() { // Release resources. myWorld = null; myGraphics3D = null; } /** * destroyApp() */ public void destroyApp(boolean unconditional) throws MIDletStateChangeException { myRefreshTimer.cancel(); myRefreshTimer = null; // Release resources. myGraphics3D = null; myWorld = null; } /** * MIDlet paint method. */ public void paint(Graphics g) { // We are not fully initialised yet; just return. if(myCanvas == null || myGraphics3D == null || myWorld == null) return; // Delete any pending refresh tasks. if(myRefreshTask != null) { myRefreshTask.cancel(); myRefreshTask = null; } // Get the current time. long currentTime = System.currentTimeMillis(); // Update the world to the current time. int validity = myWorld.animate((int)currentTime); // Render and blit to our Graphics. myGraphics3D.bindTarget(g); myGraphics3D.clear(Graphics3D.BUF_COLOR | Graphics3D.BUF_DEPTH, null); myGraphics3D.render(myWorld); myGraphics3D.releaseTarget(); // Subtract time taken to do the update. validity -= System.currentTimeMillis() - currentTime; if(validity < 1) { // The validity too small; allow a minimum of 1ms. validity = 1; } // If the validity is not infinite schedule a refresh task. if(validity < 0x7fffffff) { // Create a new refresh task. myRefreshTask = new RefreshTask(); // Schedule an update. myRefreshTimer.schedule(myRefreshTask, validity); } } /** * Handle commands. */ public void commandAction(Command cmd, Displayable disp) { if (cmd == exitCommand) { try { destroyApp(false); notifyDestroyed(); } catch(Exception e) { e.printStackTrace(); } } } /** * Inner class for refreshing the view. */ private class RefreshTask extends TimerTask { public void run() { // Get the canvas to repaint itself. myCanvas.repaint(); } } /** * Inner class for handling the canvas. */ class JesterCanvas extends Canvas { JesterTestlet myTestlet; /** * Construct a new canvas */ JesterCanvas(JesterTestlet Testlet) { myTestlet = Testlet; } /** * Initialize self. */ void init() { } /** * Cleanup and destroy. */ void destroy() { } /* * Ask myTestlet to paint itself */ protected void paint(Graphics g) { myTestlet.paint(g); } } }
|
JSR-184 Public Review Draft - Apr. 30, 2003. | ||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |