M3G 1.1 -- Jun 22, 2005

javax.microedition.m3g
Class SkinnedMesh

java.lang.Object
  extended byjavax.microedition.m3g.Object3D
      extended byjavax.microedition.m3g.Transformable
          extended byjavax.microedition.m3g.Node
              extended byjavax.microedition.m3g.Mesh
                  extended byjavax.microedition.m3g.SkinnedMesh

public class SkinnedMesh
extends Mesh

A scene graph node that represents a skeletally animated polygon 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 smoothly deforming the polygon mesh "skin" with the vertices. This style of animation is highly efficient for animated characters.

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

A SkinnedMesh node is the parent of its skeleton group, and vice versa, the skeleton is the only child of the SkinnedMesh. In other words, this.getSkeleton().getParent() == this. The skeleton group and its descendants constitute a branch in the scene graph, and that branch is traversed just like any other branch during rendering and picking. Any sprites and meshes, including skinned meshes, contained in the skeleton group are therefore rendered as usual. This allows, for example, a game character to have a weapon in its hand, such that the weapon is a separate node that can be easily interchanged with another.

Vertex transformation

Each vertex is transformed once for each Node affecting it. The results are then blended together according to the weight factors of each node. To get an initial idea of how this works, see the figure below. A more formal definition follows.

Let us denote the set of nodes (bones) 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:

where

Finally, the blended vertex position v' is transformed from the chosen reference coordinate system to the camera space as usual. Note that when computing the normalized weights wi, 0 / 0 = 0.

If a vertex v has no transformations associated with it, as is the case for all vertices in a newly constructed SkinnedMesh, the vertex lies implicitly in the coordinate system of the SkinnedMesh node itself. That is, a SkinnedMesh in its initial state is equivalent to an ordinary Mesh. When a vertex is explicitly associated with any bone in the skeleton, the implicit association with the SkinnedMesh node is removed.

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. If any part of the skinned mesh is needed for picking or rendering, then every bone in that mesh must refer to a valid range of vertex indices, otherwise an IllegalStateException will be thrown. 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.

See Also:
Binary format

Field Summary
 
Fields inherited from class javax.microedition.m3g.Node
NONE, ORIGIN, X_AXIS, Y_AXIS, Z_AXIS
 
Constructor Summary
SkinnedMesh(VertexBuffer vertices, IndexBuffer[] submeshes, Appearance[] appearances, Group skeleton)
          Constructs a new SkinnedMesh with the given vertices, submeshes and skeleton.
SkinnedMesh(VertexBuffer vertices, IndexBuffer submesh, Appearance appearance, Group skeleton)
          Constructs a new SkinnedMesh with the given vertices, submesh and skeleton.
 
Method Summary
 void addTransform(Node bone, int weight, int firstVertex, int numVertices)
          Associates a weighted transformation, or "bone", with a range of vertices in this SkinnedMesh.
 void getBoneTransform(Node bone, Transform transform)
          Returns the at-rest transformation for a bone node.
 int getBoneVertices(Node bone, int[] indices, float[] weights)
          Returns the number of vertices influenced by the given bone, filling in the vertices and their weights to the given arrays.
 Group getSkeleton()
          Returns the skeleton Group of this SkinnedMesh.
 
Methods inherited from class javax.microedition.m3g.Mesh
getAppearance, getIndexBuffer, getSubmeshCount, getVertexBuffer, setAppearance
 
Methods inherited from class javax.microedition.m3g.Node
align, getAlignmentReference, getAlignmentTarget, getAlphaFactor, getParent, getScope, getTransformTo, isPickingEnabled, isRenderingEnabled, setAlignment, setAlphaFactor, setPickingEnable, setRenderingEnable, setScope
 
Methods inherited from class javax.microedition.m3g.Transformable
getCompositeTransform, getOrientation, getScale, getTransform, getTranslation, postRotate, preRotate, scale, setOrientation, setScale, setTransform, setTranslation, translate
 
Methods inherited from class javax.microedition.m3g.Object3D
addAnimationTrack, animate, duplicate, find, getAnimationTrack, getAnimationTrackCount, getReferences, getUserID, getUserObject, removeAnimationTrack, setUserID, setUserObject
   

Constructor Detail

SkinnedMesh

public SkinnedMesh(VertexBuffer vertices,
                   IndexBuffer submesh,
                   Appearance appearance,
                   Group skeleton)

Constructs a new SkinnedMesh with the given vertices, submesh and skeleton. Except for the skeleton, the behavior of this constructor is identical to the corresponding constructor in Mesh; refer to that for more information.

No transformations are initially associated with the vertices. The behavior of a newly constructed SkinnedMesh is therefore equivalent to an ordinary Mesh.

Parameters:
vertices - a VertexBuffer to use for this mesh
submesh - an IndexBuffer defining the triangle strips to draw
appearance - an Appearance to use for this mesh, or null
skeleton - a Group containing the skeleton of this SkinnedMesh
Throws:
java.lang.NullPointerException - if vertices is null
java.lang.NullPointerException - if submesh is null
java.lang.NullPointerException - if skeleton is null
java.lang.IllegalArgumentException - if skeleton is a World node
java.lang.IllegalArgumentException - if skeleton already has a parent

SkinnedMesh

public SkinnedMesh(VertexBuffer vertices,
                   IndexBuffer[] submeshes,
                   Appearance[] appearances,
                   Group skeleton)

Constructs a new SkinnedMesh with the given vertices, submeshes and skeleton. Except for the skeleton, the behavior of this constructor is identical to the corresponding constructor in Mesh; refer to that for more information.

No transformations are initially associated with the vertices. The behavior of a newly constructed SkinnedMesh is therefore equivalent to an ordinary Mesh.

Parameters:
vertices - a VertexBuffer to use for all submeshes in this mesh
submeshes - an IndexBuffer array defining the submeshes to draw
appearances - an Appearance array parallel to submeshes, or null
skeleton - a Group containing the skeleton of this SkinnedMesh
Throws:
java.lang.NullPointerException - if vertices is null
java.lang.NullPointerException - if submeshes is null
java.lang.NullPointerException - if any element in submeshes is null
java.lang.NullPointerException - if skeleton is null
java.lang.IllegalArgumentException - if submeshes is empty
java.lang.IllegalArgumentException - if (appearances != null) && (appearances.length < submeshes.length)
java.lang.IllegalArgumentException - if skeleton is a World node
java.lang.IllegalArgumentException - if skeleton already has a parent
Method Detail

getSkeleton

public Group getSkeleton()

Returns the skeleton Group of this SkinnedMesh. The skeleton group is set in the constructor and can not be removed or replaced with another Group afterwards. All transform reference nodes (bones) must be descendants of the skeleton group; this is enforced by addTransform.

Returns:
the skeleton Group of this SkinnedMesh

addTransform

public void addTransform(Node bone,
                         int weight,
                         int firstVertex,
                         int numVertices)

Associates a weighted transformation, or "bone", with a range of vertices in this SkinnedMesh. See the transformation equation in the class description for how the transformations are applied on vertices.

An integer weight is supplied as a parameter for each added transformation. Prior to solving the transformation equation, the weights are automatically normalized on a per-vertex basis such that the individual weights are between [0, 1] and their sum is 1.0. This is done by dividing each weight pertaining to a vertex by the sum of all weights pertaining to that vertex. For example, if two bones with any equal weights overlap on a vertex, each bone will get a final weight of 0.5.

Automatic normalization of weights is convenient because it significantly reduces the number of times that this method must be called (and hence the amount of data that must be stored and transmitted) in cases where more than one bone is typically associated with each vertex.

The same Node may appear multiple times among the bones. This is to allow multiple disjoint sets of vertices to be attached to the same bone.

The number of bones that can be associated with a single vertex is unlimited, except for the amount of available memory. However, there is an implementation defined limit (N) to the number of bones that can actually have an effect on any single vertex. If more than N bones are active on a vertex, the implementation is required to select the N bones with highest weights. In case of a tie (multiple bones with equal weights competing for the last slot), the selection method is undefined but must be deterministic. The limit N can be queried from getProperties.

The "at-rest" transformation from this SkinnedMesh to the given bone is set equal to this.getTransformTo(bone). If the at-rest transformation cannot be computed, an ArithmeticException is thrown; see Node.getTransformTo for more information. If addTransform is called more than once for the same bone, the final at-rest transformation of that bone can become any of the at-rest transformations that were in effect during those calls.

Parameters:
bone - a node in the skeleton group to transform the vertices with
weight - weight of bone; any positive integer is accepted
firstVertex - index of the first vertex to be affected by bone
numVertices - number of consecutive vertices to attach to the bone node
Throws:
java.lang.NullPointerException - if bone is null
java.lang.IllegalArgumentException - if bone is not the skeleton Group or one of its descendants
java.lang.IllegalArgumentException - if weight <= 0
java.lang.IllegalArgumentException - if numVertices <= 0
java.lang.IndexOutOfBoundsException - if firstVertex < 0
java.lang.IndexOutOfBoundsException - if firstVertex + numVertices > 65535
java.lang.ArithmeticException - if the at-rest transformation cannot be computed

getBoneTransform

public void getBoneTransform(Node bone,
                             Transform transform)
Returns the at-rest transformation for a bone node. This is the transformation stored in addTransform as described in the documentation there.

If the given node is in the skeleton group of this Mesh, but has no vertices associated with it according to getBoneVertices, the returned transformation is undefined.

Parameters:
bone - the bone node
transform - the Transform object to receive the bone transformation
Throws:
java.lang.NullPointerException - if bone is null
java.lang.NullPointerException - if transform is null
java.lang.IllegalArgumentException - if bone is not in the skeleton group of this mesh
Since:
M3G 1.1
See Also:
getBoneVertices, addTransform

getBoneVertices

public int getBoneVertices(Node bone,
                           int[] indices,
                           float[] weights)
Returns the number of vertices influenced by the given bone, filling in the vertices and their weights to the given arrays. If either or both of the arrays are null, only the number of vertices is returned.

Each bone node may be associated with disjoint sets of vertices via multiple addTransform calls. The vertices are therefore returned as explicit vertex indices with corresponding per-vertex bone weights. The order of the returned index-weight pairs is implementation-dependent. Duplicate indices and indices with zero weight are not returned. The returned weights are normalized so that all weights (from all contributing bones) corresponding to a single vertex sum to one.

Implementations are only required to associate with a vertex the N bones with the highest weights, where N is the maximum number of transformations per vertex as queried from Graphics3D.getProperties. For the other bones, a weight of zero can be assumed. The returned weights for each vertex must still sum to one.

The minimum precision requirements for vertex weights are less than the general requirements given in the package description. The returned weights must have a precision equivalent to a minimum internal precision of 8-bit fixed point.

Parameters:
bone - the bone node
indices - an array to store the vertex indices, or null to only query the number of vertices that will be returned
weights - an array to store the vertex weights, or null to only query the number of vertices that will be returned
Returns:
the number of vertices influenced by bone
Throws:
java.lang.NullPointerException - if bone is null
java.lang.IllegalArgumentException - if bone is not in the skeleton group of this mesh
java.lang.IllegalArgumentException - if neither of indices and weights is null, and the length of either is less than the number of vertices queried
Since:
M3G 1.1
See Also:
addTransform, getBoneTransform

M3G 1.1 -- Jun 22, 2005

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