JSR-184 Public Review Draft - Apr. 30, 2003.

javax.microedition.m3d
Class SkinnedMesh

java.lang.Object
  |
  +--javax.microedition.m3d.Object3D
        |
        +--javax.microedition.m3d.Node
              |
              +--javax.microedition.m3d.Mesh
                    |
                    +--javax.microedition.m3d.SkinnedMesh

public class SkinnedMesh
extends Mesh

A skeletally animated mesh. Vertex positions in a SkinnedMesh can be associated with multiple separately transforming Nodes, with a weight factor specified for each. This enables groups of vertices to transform independently of each other while still smoothly deforming the polygon mesh "skin" with the vertices. This style of animation is highly efficient for animated characters. Also, using ordinary Nodes in place of more specialized "bone" nodes allows rigid-body attachments on skinned objects, such as weapons on a game character.

The structure of a SkinnedMesh is shown in the figure below.

Vertex transformation

Each vertex is transformed once for each Node affecting it, as if it was defined in the coordinate system of that node. The results are then blended together according to the weight factors of each node. Let us denote the set of nodes associated with a vertex by {N1, N2, ..., NN}. Let us also denote by Mi the transformation from the local coordinate system of node Ni to a reference coordinate system. The choice of the reference coordinate system is not critical; depending on the implementation, good choices may include the world coordinate system, the coordinate system of the SkinnedMesh node, or the coordinate system of the current camera. Finally, let us denote the weight associated with node Ni as Wi. The blended position of a vertex in the reference coordinate system is then:

v' = w1M1v + w2M2v + ... + wNMNv

where v is the original vertex position in the source vertex buffer, and wi = Wi / (W1 + ... + WN). When computing the normalized weights wi, 0 / 0 = 0. Finally, the blended vertex position is transformed from the chosen reference coordinate system to camera space as usual.

If a vertex v has no transformations associated with it, as is the case for all vertices in a newly constructed SkinnedMesh, the vertex is taken to be in the coordinate system of the SkinnedMesh node itself. That is, a SkinnedMesh in its initial state is equivalent to an ordinary Mesh.

The transformation of vertices is illustrated in the figure below.

Deferred exceptions

Any special cases and exceptions that are defined for Mesh also apply for SkinnedMesh. An extra exception case is introduced due to the vertex indices set by addTransform. The indices cannot be validated until when they are actually needed, that is, when rendering or picking. This is because the application may change the length of the associated VertexBuffer, and consequently make the indices invalid or valid, at any time.

Another extra exception case is introduced due to the requirement that all transform reference nodes of a SkinnedMesh must be descendants of that SkinnedMesh. This condition cannot be enforced by addTransform, because again the application may attach and detach the reference nodes at will. Their validity is therefore checked only when the transformations are actually done, that is, when rendering or picking.

See Also:
Binary format

Field Summary
 
Fields inherited from class javax.microedition.m3d.Node
NONE, ORIGIN, X_AXIS, Y_AXIS, Z_AXIS
 
Fields inherited from class javax.microedition.m3d.Object3D
userObject
 
Constructor Summary
SkinnedMesh(VertexBuffer vertices, IndexBuffer[] triangles, Appearance[] appearances)
          Constructs a new SkinnedMesh with the given VertexBuffer and submeshes.
SkinnedMesh(VertexBuffer vertices, IndexBuffer triangles, Appearance appearance)
          Constructs a new SkinnedMesh consisting of only one submesh.
 
Method Summary
 void addTransform(Node transform, int weight, int firstVertex, int lastVertex)
          Sets a weighted transformation on a range of vertices in the VertexBuffer associated with this SkinnedMesh.
 Group getSkeleton()
          Returns the skeleton Group of this SkinnedMesh.
 void setSkeleton(Group skeleton)
          Sets the Group to use as the skeleton of this SkinnedMesh.
 
Methods inherited from class javax.microedition.m3d.Mesh
getAppearance, getIndexBuffer, getSubmeshCount, getVertexBuffer, setAppearance
 
Methods inherited from class javax.microedition.m3d.Node
getAlphaFactor, getOrientation, getParent, getScale, getScopeID, getTransform, getTransformTo, getTranslation, isEnabled, setAlignment, setAlphaFactor, setEnable, setOrientation, setScale, setScopeID, setTransform, setTranslation
 
Methods inherited from class javax.microedition.m3d.Object3D
addAnimationTrack, animate, clone, find, getAnimationTrack, getAnimationTrackCount, getReferences, getUserID, removeAnimationTrack, setUserID
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

SkinnedMesh

public SkinnedMesh(VertexBuffer vertices,
                   IndexBuffer triangles,
                   Appearance appearance)

Constructs a new SkinnedMesh consisting of only one submesh. All transform references are initialized to null, and all weights to zero. This means that the mesh is not rendered at all, because all vertices will be mapped to the zero vector (see the transformation equation in the class description above).

Parameters:
vertices - a VertexBuffer to use for this mesh
triangles - an IndexBuffer defining the triangle strips to draw
appearance - an Appearance to use for this mesh, or null

SkinnedMesh

public SkinnedMesh(VertexBuffer vertices,
                   IndexBuffer[] triangles,
                   Appearance[] appearances)

Constructs a new SkinnedMesh with the given VertexBuffer and submeshes. The number of submeshes is set equal to the length of triangles. The appearances array is parallel to that, and must have at least as many elements. Alternatively, it may be null, in which case all the Appearances are initialized to null.

All transform references are initialized to null, and all weights to zero. This means that the mesh is not rendered at all, because all vertices will be mapped to the zero vector (see the transformation equation in the class description above).

Parameters:
vertices - a VertexBuffer to use for all submeshes in this mesh
triangles - an IndexBuffer array defining the triangle strips to draw
appearances - an Appearance array parallel to triangles; a null element disables rendering of that submesh, and a null array initializes all appearances to null
Throws:
java.lang.IllegalArgumentException - if triangles is empty
java.lang.IllegalArgumentException - if appearances.length < triangles.length
Method Detail

addTransform

public void addTransform(Node transform,
                         int weight,
                         int firstVertex,
                         int lastVertex)

Sets a weighted transformation on a range of vertices in the VertexBuffer associated with this SkinnedMesh. When applying a transformation on a vertex, its weight is normalized by dividing it with the sum of all weights pertaining to that vertex. See the class description for a more formal definition. Due to the normalization, the weights are integers instead of floating point values between [0, 1]. The implementation does not need to check the validity of the incoming weights, because all values are equally valid.

Note that for the SkinnedMesh to be valid, each Node used to transform vertices must be in the skeleton Group set by setSkeleton. However, this check is postponed until rendering or picking; see the class description for more information.

Parameters:
transform - node transformation to apply on the specified range of vertices
weight - weight of transform; all values are accepted
firstVertex - index of the first vertex to be affected by transform
lastVertex - index of the last vertex to be affected by transform
Throws:
java.lang.IllegalArgumentException - if firstVertex is greater than lastVertex

setSkeleton

public void setSkeleton(Group skeleton)

Sets the Group to use as the skeleton of this SkinnedMesh. Every Node used to transform vertices of this mesh must be in the given skeleton Group; not immediately, but at the latest when the transformations are actually done, that is, when rendering or picking. Note that the skeleton group may also contain an arbitrary number of nodes that are not referenced by this mesh; those are treated as usual when rendering or picking.

A SkinnedMesh node is a parent in the scene graph for its skeleton Group. In other words, this.getSkeleton().getParent() == this.

Parameters:
skeleton - the Group containing the Nodes used in transforming this SkinnedMesh
Throws:
java.lang.IllegalArgumentException - if skeleton is a World node
java.lang.IllegalArgumentException - if skeleton already has a parent
java.lang.IllegalArgumentException - if skeleton is an ancestor of this node
See Also:
addTransform, getSkeleton

getSkeleton

public Group getSkeleton()

Returns the skeleton Group of this SkinnedMesh.

Returns:
the Group currently set as the skeleton for this mesh
See Also:
setSkeleton

JSR-184 Public Review Draft - Apr. 30, 2003.

Copyright © 2003 Nokia Corporation. See the Copyright Notice for details.