
| Goals |
| Overview |
| The Nodes |
| Modeling the Humanoid |
| The Joint Hierarchy |
| Eyepoints |
| Additional Features |
| Future Enhancements |
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:
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 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".
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.
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:
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.
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.
...
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
| 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.
| 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 |
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_distalSome notes on the preceeding hierarchy:
The letter 'l' is for Lumbar, the letter 't' is for Thoraic, and the letter 'c' is for Cervical.
The term "proximal" means "the nearer" segment, and "distal" means "the farther" segment.
Both the sacroiliac and the vl5 vertebrae are children of the HumanoidRoot node.
The l_sternoclavicular and r_sternoclavicular joints are children of vt1, and siblings of vc7.
The skullbase joint is technically the "atlanto-occipital" joint.
The left and right metatarsals are technically the left and right "tarsometatarsal" joints.
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.
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.
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.
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.
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.