|
M3G 1.1 -- Jun 22, 2005 | |||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object javax.microedition.m3g.Object3D javax.microedition.m3g.Transformable javax.microedition.m3g.Node javax.microedition.m3g.Mesh javax.microedition.m3g.SkinnedMesh
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.
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.
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.
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 |
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.
vertices
- a VertexBuffer to use for this meshsubmesh
- an IndexBuffer defining the triangle strips to drawappearance
- an Appearance to use for this mesh,
or nullskeleton
- a Group containing the skeleton of this SkinnedMesh
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 parentpublic 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.
vertices
- a VertexBuffer to use for all submeshes in this meshsubmeshes
- an IndexBuffer array defining the submeshes to drawappearances
- an Appearance array parallel to
submeshes
, or nullskeleton
- a Group containing the skeleton of this SkinnedMesh
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 parentMethod Detail |
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
.
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.
bone
- a node in the skeleton group to transform the vertices withweight
- weight of bone
; any positive integer is
acceptedfirstVertex
- index of the first vertex to be affected by
bone
numVertices
- number of consecutive vertices to attach to
the bone node
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 computedpublic void getBoneTransform(Node bone, Transform transform)
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.
bone
- the bone nodetransform
- the Transform object to
receive the bone transformation
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 meshgetBoneVertices
,
addTransform
public int getBoneVertices(Node bone, int[] indices, float[] weights)
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.
bone
- the bone nodeindices
- an array to store the vertex indices,
or null to only query the number of vertices that will be
returnedweights
- an array to store the vertex weights,
or null to only query the number of vertices that will be
returned
bone
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
queriedaddTransform
,
getBoneTransform
|
M3G 1.1 -- Jun 22, 2005 | |||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |