Humanoid Animation Working Group

Specification for a Standard VRML Humanoid

Version 1.0
 
Goals
Overview
The Nodes
Modeling the Humanoid
The Joint Hierarchy
Eyepoints
Additional Features
Future Enhancements

Goals

As the 3D Internet continues to grow, there will be an increasing need to represent human beings in online virtual environments. Achieving that goal will require the creation of libraries of interchangeable humanoids, as well as authoring tools that make it easy to create new humanoids and animate them in various ways.

This document specifies a standard way of representing humanoids in VRML 2.0. This standard will allow humanoids created using authoring tools from one vendor to be animated using tools from another. VRML humanoids can be animated using keyframing, inverse kinematics, performance animation systems and other techniques.

Our design goals are as follows:

Much of the design is driven by these three goals. The compatibility requirement has led us to avoid the use of scripting, since the VRML 2.0 specification does not require any particular scripting language to be implemented. The flexibility requirement has led us to make the spec fairly "low-level", in that it allows direct access to the joints of the humanoid's body. The simplicity requirement has led us to focus specifically on humanoids, instead of trying to deal with arbitrary articulated figures.

Overview

The human body consists of a number of segments (such as the forearm, hand and foot) that are connected to each other by joints (such as the elbow, wrist and ankle). In order for an application to animate a humanoid, it needs to obtain access to the joints and alter the joint angles. The application may also need to retrieve information about such things as joint limits and segment masses.

A VRML Humanoid file contains a set of Joint nodes that are arranged to form a hierarchy. Each Joint node can contain other Joint nodes, and may also contain a Segment node which describes the body part associated with that joint. The file also contains a single Humanoid node which stores human-readable data about the humanoid such as author and copyright information. That node also stores references to all the Joint and Segment nodes. Additional nodes can optionally be included in the file, such as Viewpoints and possibly a NavigationInfo node.

Keyframe animation sequences can be stored in the same file, with the outputs of various VRML interpolator nodes being ROUTEd to the joints of the body. Alternatively, the file may include Script nodes which access the joints directly. In addition, applications can obtain references to the individual joints and segments from the Humanoid node. Such applications will typically animate the humanoid by setting the joint rotations.

The Nodes

In order to simplify the creation of humanoids, three new node types are introduced. Each node is defined by a PROTO. The basic implementation of all the nodes is very straightforward, yet each provides enough flexibility to allow more advanced techniques to be used.

The Joint Node

Each joint in the body is represented by a Joint node. The most common implementation for a Joint will be a Transform node, which is used to define the relationship of each body segment to its immediate parent. However, that's just one possible implementation -- humanoid authors are free to implement the Joint node however they choose. In particular, some systems may choose to use a single polygonal mesh to represent a humanoid, rather than having a separate IndexedFaceSet for each body segment. In such a case, a Joint would be responsible for moving the vertices that correspond to a particular body segment and all the segments descended from it. Many computer games use such a single-mesh representation in order to create smooth, seamless figures.

The Joint node is also used to store other joint-specific information.  In particular, a joint name is provided so that applications can identify each Joint node at runtime. In addition, joint limits are provided in order to support inverse-kinematics systems. Note that these limits are not enforced by the humanoid, but are provided for information purposes only. Enforcement is up to the application.

The Joint PROTO looks like this:

    PROTO Joint [
        exposedField   SFString    name                ""
        exposedField   SFVec3f     translation         0 0 0
        exposedField   SFRotation  rotation            0 0 1 0
        exposedField   SFVec3f     scale               1 1 1
        exposedField   SFRotation  scaleOrientation    0 0 1 0
        exposedField   SFVec3f     center              0 0 0
        exposedField   MFNode      children            []
        exposedField   MFFloat     ulimit              [ 0 0 0 ]
        exposedField   MFFloat     llimit              [ 0 0 0 ] 
    ]
Notice that most of the fields correspond to those of the Transform node. This is because the typical implementation of the Joint PROTO will be:
    {
        Transform {
                translation IS translation
                rotation IS rotation
                scale IS scale
                scaleOrientation IS scaleOrientation
                center IS center
                children IS children
        }
    }
Other implementations are certainly possible. The only requirement is that a Joint be able to accept the events listed above. Note that the center field is not intended to receive events. The locations of the joint centers are available by reading the center fields of the Joints (see Modeling the Humanoid for details). That information may be used to support inverse kinematics applications.

The ulimit and llimit fields of the Joint PROTO set the upper and lower joint rotation limits. Both fields are three-element MFFloats containing separate values for the X, Y and Z rotation limits. The ulimit field stores the upper (i.e. maximum) values for rotation around the X, Y and Z axes. The llimit field stores the lower (i.e. minimum) values for rotation around those axes.

Each Joint should have a DEF name that matches the name field for that Joint, but with a distinguishing prefix in front of it. That prefix can be anything, but must be the same for all the Joints in a particular humanoid. The distinguishing prefix is useful in the case of static routing to the Joints of multiple humanoids in the same file.

If only a single humanoid is stored in a file, the prefix should be "hanim_" (for Humanoid Animation). For example, the left shoulder would have a DEF name of "hanim_l_shoulder".

The DEF name is used for static routing, which would typically connect OrientationInterpolators in the humanoid file to the joints. The name field is used for identifying the joints at runtime, since the DEF names would not necessarily be available.

It will occasionally be useful for the person creating a humanoid to be able to add additional joints to the body. The body remains humanoid in form, and is still generally expected to have the basic joints described later in this document. However, they may be thought of as a minimal set to which extensions may be added (such as a prehensile tail). If necessary, some of the joints (such as the many vertebrae) may be omitted.

The top-level Joint node should be given the DEF name "hanim_HumanoidRoot".

The Segment Node

Each body segment is stored in a Segment node. The Segment node will typically be implemented as a Shape node containing the representation of that body part. However, it might also be a Group node containing multiple Shapes, or a Transform node that positions the body part within its coordinate system (see Modeling the Humanoid for details).
    PROTO Segment [
        exposedField   SFString    name                ""
        exposedField   SFFloat     mass                0
        exposedField   SFVec3f     centerOfMass        0 0 0
        field          SFVec3f     bboxCenter          0 0 0
        field          SFVec3f     bboxSize            -1 -1 -1
        exposedField   MFNode      children            [ ]
    ]
The mass is the total mass of the segment, and the centerOfMass is the location within the segment of its center of mass. The bounding box information can be used to indicate the rough dimensions of the segment. All the fields are optional.

It is expected that additional fields will be added to the Segment PROTO in future versions of this specification.

Humanoids that are modeled as a continuous mesh will still have Segment nodes, in order to store per-segment information. In such a case, the Segment wouldn't necessarily contain any geometry, though it should still be a child of a Joint node.

The Humanoid Node

The Humanoid node is used to store human-readable data such as author and copyright information, as well as to store references to the joints and segments.
    PROTO Humanoid [
        exposedField   SFString    version             "1.0"
        exposedField   SFString    name                ""
        exposedField   MFString    info                []
        exposedField   MFNode      joints              []
        exposedField   MFNode      segments            []
        field          SFVec3f     bboxCenter          0 0 0
        field          SFVec3f     bboxSize            -1 -1 -1
    ]
The version field stores the version of this specification that the Humanoid file conforms to. The document you're now reading describes version "1.0" of the specification.

The bboxCenter and bboxSize fields give the center and size of a bounding box that completely encloses humanoid when the humanoid is in its default (neutral) position.

The info field consists of an array of strings, each of which is of the form "tag=value". The following tags are defined so far:

Additional tag=value pairs can be included as needed.

The joints field contains references (i.e. USEs) of each of the joints in the body. Each of the referenced joints should be a Joint node. The order in which they are listed is irrelevant, since the names of the joints are stored in the joints themselves. Similarly, the segments field contains references to each of the segments of the body.

The Humanoid node should be given a DEF name of "Humanoid", in order to make it easy to access using the External Authoring Interface. It should be the last node in the file, to make it easy for people to find when viewing the file.

The definition of the PROTO node can be anything. Either a Group or a WorldInfo node seems like a reasonable choice.

Modeling the Humanoid

The humanoid should be modeled in a standing position, facing in the +Z direction with +Y up and +X to the humanoid's left. The origin (0, 0, 0) should be located at ground level, between the humanoid's feet.

The feet should be flat on the ground, spaced apart about the same distance as the width of the hips. The bottom of the feet should be at Y=0.The arms should be straight and parallel to the sides of the body with the palms of the hands facing inwards towards the thighs.

The humanoid should be built with actual human size ranges in mind. All dimensions are in meters. A typical human is roughly 1.75 meters tall.

This is the default position of the humanoid:

(illustration courtesy of the SNHC group)

In this position, all the joint angles should be zero. In other words, all the rotation fields in all the Joint nodes should be left at their default value of (0 0 1 0). In addition, the translation fields should be left at their default value of (0 0 0) and the scale factors should be left at their default value of (1 1 1). The only field which should have a non-default value is center, which is used to specify the point around which the joint (and its attached children and body segment if any) will rotate. Sending the default values for translation, rotation and scaling to all the Joints in the body must return the body to the neutral position described above.

The center field of each joint should be placed so that the joints rotate in the same way that they would on a real human body.

It is suggested, but not required, that all of the body segments should be built in place. That is, they should require no translation, rotation, or scaling to be connected with their neighbors. For example, the hand should be built so that it's in the correct position in relation to the forearm. The forearm should be built so that it's in the correct position in relation to the upper arm, and so on. All the body's coordinates will share a common origin, which is that of the humanoid itself. If this proves difficult for an authoring tool to implement, it is acceptable to use a Transform node inside each Segment, or even several Transforms, in order to position the geometry for that segment correctly.

Note that the coordinate system for each Joint is oriented to align with that of the overall humanoid.

The Joint Hierarchy

The body is typically built as a series of nested Joints, each of which may have a Segment associated with it. For example:
...
DEF hanim_l_shoulder Joint {  name "l_shoulder"
  center 0.167 1.36 -0.0518
  children    [
    DEF hanim_l_elbow Joint {  name "l_elbow"
      center 0.196 1.07 -0.0518
      children        [
        DEF hanim_l_wrist Joint {  name "l_wrist"
          center 0.213 0.811 -0.0338
          children    [
            DEF hanim_r_hand Segment {  name "r_hand"
              ...
            }
          ]
        }
        DEF hanim_l_forearm Segment {  name "l_forearm"
          ...
        }
      ]
    }
    DEF hanim_l_upperArm Segment {  name "l_upperArm"
      ...
    }
  ]
}
...
Sample humanoids in the correct format will be available in the near future, and will be linked from the Humanoid Animation Working Group Home Page

The Body

The names of the Joint nodes for the body are listed in the following table:
 
l_hip l_knee l_ankle l_subtalar l_midtarsal l_metatarsal
r_hip r_knee r_ankle r_subtalar r_midtarsal r_metatarsal
vl5 vl4 vl3 vl2 vl1
vt12 vt11 vt10 vt9 vt8 vt7
vt6 vt5 vt4 vt3 vt2 vt1
vc7 vc6 vc5 vc4 vc3 vc2 vc1
l_sternoclavicular l_acromioclavicular l_shoulder l_elbow l_wrist
r_sternoclavicular r_acromioclavicular r_shoulder r_elbow r_wrist
sacroiliac (pelvis) skullbase HumanoidRoot

The vl5 and sacroiliac Joints are children of a Joint labelled HumanoidRoot, which is not technically considered a "joint" but is used for positioning the humanoid in space. All the other Joints are descended from either vl5 or sacroiliac.

The Hands

The hands, if present, should use the following naming convention:
 
l_pinky1 l_pinky2 l_pinky3 l_ring1 l_ring2 l_ring3
l_middle1 l_middle2 l_middle3 l_index1 l_index2 l_index3
l_thumb1 l_thumb2 l_thumb3
r_pinky1 r_pinky2 r_pinky3 r_ring1 r_ring2 r_ring3
r_middle1 r_middle2 r_middle3 r_index1 r_index2 r_index3
r_thumb1 r_thumb2 r_thumb3

Hierarchy

The complete hierarchy is as follows, with the segment names listed beside the joints to which they're attached:
HumanoidRoot
  sacroiliac : pelvis
    l_hip : l_thigh
      l_knee : l_calf
        l_ankle : l_hindfoot
          l_subtalar : l_midproximal
            l_midtarsal : l_middistal
              l_metatarsal : l_forefoot
    r_hip : r_thigh
      r_knee : r_calf
        r_ankle : r_hindfoot
          r_subtalar :  r_midproximal
            r_midtarsal : r_middistal
              r_metatarsal : r_forefoot
  vl5 * : l5
    vl4 : l4
      vl3 * : l3
        vl2 : l2
          vl1 * : l1
            vt12 : t12
              vt11 : t11
                vt10 * : t10
                  vt9 : t9
                    vt8 : t8
                      vt7 : t7
                        vt6 * : t6
                          vt5 : t5
                            vt4 : t4
                              vt3 : t3
                                vt2 : t2
                                  vt1 : t1
                                    vc7 * : c7
                                    | vc6 : c6
                                    |   vc5 : c5
                                    |     vc4 * : c4
                                    |       vc3 : c3
                                    |         vc2 * : c2
                                    |           vc1 : c1
                                    |             skullbase : skull
                                    l_sternoclavicular : l_clavicle
                                    | l_acromioclavicular : l_scapula
                                    |   l_shoulder : l_upperarm
                                    |     l_elbow : l_forearm
                                    |       l_wrist : l_hand
                                    |         l_thumb1 : l_thumb_metacarpal
                                    |           l_thumb2 : l_thumb_proximal
                                    |             l_thumb3 : l_thumb_distal
                                    |         l_index1 : l_index_proximal
                                    |           l_index2 : l_index_middle
                                    |             l_index3 : l_index_distal
                                    |         l_middle1 : l_middle_proximal
                                    |           l_middle2 : l_middle_middle
                                    |             l_middle3 : l_middle_distal
                                    |         l_ring1 : l_ring_proximal
                                    |           l_ring2 l_ring_middle
                                    |             l_ring3 : l_ring_distal
                                    |         l_pinky1 : l_pinky_proximal
                                    |           l_pinky2 : l_pinky_middle
                                    |             l_pinky3 : l_pinky_distal
                                    r_sternoclavicular : r_clavicle
                                      r_acromioclavicular : r_scapula
                                        r_shoulder : r_upperarm
                                          r_elbow : r_forearm
                                            r_wrist : r_hand
                                              r_thumb1 : r_thumb_metacarpal
                                                r_thumb2 : r_thumb_proximal
                                                  r_thumb3 : r_thumb_distal
                                              r_index1 : r_index_proximal
                                                r_index2 : r_index_middle
                                                  r_index3 : r_index_distal
                                              r_middle1 : r_middle_proximal
                                                r_middle2 : r_middle_middle
                                                  r_middle3 : r_middle_distal
                                              r_ring1 : r_ring_proximal
                                                r_ring2 : r_ring_middle
                                                  r_ring3 : r_ring_distal
                                              r_pinky1 : r_pinky_proximal
                                                r_pinky2 : r_pinky_middle
                                                  r_pinky3 : r_pinky_distal
Some notes on the preceeding hierarchy: Many Joints may be omitted, such as most of the vertebrae, the midtarsal, and the acromioclavicular. The spinal joints that are marked with a * are the ones that should be given priority if a full spine is not implemented. A minimally spec-compliant humanoid would not need to have any Joints at all, except the HumanoidRoot.

Other Joints

The names in the preceeding sections are based mostly on those used by the SNHC group for their Body Animation Parameters.

Additional joints and body segments may be defined, but are not required. The only requirement is that the joints listed in the tables above, if present, must use the specified names.

Eyepoints

A number of special Viewpoint nodes may optionally be included in the humanoid file. Two of them correspond to the left and right eyes of the humanoid figure, and are given the DEF names hanim_LeftEyeView and hanim_RightEyeView. A third is named hanim_CyclopeanView, and is positioned at the same Y and Z coordinates as the hanim_LeftEyeView and hanim_RightEyeView but with an X coordinate half-way between the two. They should be children of the skullbase node, which corresponds to the head.

The purpose of these viewpoints is to allow applications to provide users with a humanoid's-eye view of the world. Both left and right eyes are provided for those browsers which support stereoscopic viewing.

A fourth special Viewpoint is hanim_FaceView, which gives a view of the face while looking in the -Z direction and centered on the nose. Two others are hanim_FaceLeft and hanim_FaceRight, which give a 3/4 view of the face from each side.

Each of these Viewpoint nodes should have a description field that matches the DEF name, so that they can be distinguished at runtime even if the DEF names are not available.

Additional Useful Features

In addition to the nodes described above (the Joint node tree of the humanoid itself and the Humanoid node), it is recommended that the file containing the humanoid include a number of Viewpoint nodes that may be used to display the figure from several different perspectives. These views should include one called FrontView, one called SideView, one called TopView and one called InclinedView. They should be stored in a Group node with a DEF name of "Viewpoints".

For example:

DEF Viewpoints Group {
    children [

        DEF FrontView Viewpoint {
            description "Front view"
            position 0 1 0
            orientation 0 0 1 0
        }
    ...

    ]

}
The FrontView Viewpoint should face in the -Z direction, the SideView should face in the -X direction, the TopView should face in the -Y direction, and the InclinedView should face towards (-1 -1 -1). All the viewpoints should be displaced from the center of the humanoid by a sufficient distance to show the entire humanoid from that view.

These views not only provide an easy way for a user to examine the humanoid using a VRML browser, they also provide standard views for the purpose of creating catalogs of humanoid bodies (which might be useful for selecting an avatar in a multi-user system).

In addition, a NavigationInfo node should be included to put the VRML browser into Examine mode:

    NavigationInfo { type "EXAMINE" }
This makes it easy to examine the humanoid from all angles.

Suggested Practices

There are a number of issues surrounding the use of VRML Humanoids that are beyond the scope of this proposal.  However, some of those issues are worth addressing here. Note that these are suggested practices only, not a requirement of this specification.

Multiple Humanoids Per File

There are some cases in which it's useful to have multiple humanoids in the same file, perhaps alongside other elements of a 3D world. In such a case, it is recommended that the humanoids be assigned unique DEF names (rather than "DEF Humanoid") and that those names be referenced as the children of a Group node named "HumanoidGroup".

In other words,

DEF Fred Humanoid { ... }
DEF Jane Humanoid { ... }
DEF Sally Humanoid { ... }
DEF HumanoidGroup Group { children [ USE Fred, USE Jane, Use Sally ] }
An EAI-based application can obtain a reference to the HumanoidGroup for the scene, and by iterating over the children of that group it can obtain references to the individual humanoids.

Future Enhancements

There are a number of additional areas that could be addressed in a future revision of this document.

The question of how best to handle facial animation is currently not addressed in this proposal. However, it is hoped that we may be able to benefit from the efforts of the SNHC group in this area.

Storing animations with the humanoid is also not yet addressed here.

In the future, it may be desireable to add some additional fields to the Joint and Segment nodes in order to support certain types of kinematics and physical simulation.

At some point, we may decide to add additional Joint and Segment names.

This document can be found at http://H-Anim.org/Specifications/H-Anim1.0/.
The home page of the VRML Humanoid Animation Working Group is http://H-Anim.org.