This example demonstrates interchangeability of avatars (Nancy, Allen, Boxman) and animation behaviors (Stand, Run, Jump, Walk) via dynamic routing.
this example needs to be converted from HAnim Prototypes to HAnim native tags.
replace usages of original Boxman .wrl fragments, fix numerous warnings
Inconsistent validation problem with HAnimJoint, ProtoInstance USE nodes: required @name attribute must also be present
X3D-Edit 3.3, https://www.web3d.org/x3d/tools/X3D-Edit
"LOA1_StandAnimation.x3d#LOA1_StandAnimation" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/LOA1_StandAnimation.x3d#LOA1_StandAnimation" "LOA1_StandAnimation.wrl#LOA1_StandAnimation" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/LOA1_StandAnimation.wrl#LOA1_StandAnimation"
"LOA1_WalkAnimation.x3d#LOA1_WalkAnimation" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/LOA1_WalkAnimation.x3d#LOA1_WalkAnimation" "LOA1_WalkAnimation.wrl#LOA1_WalkAnimation" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/LOA1_WalkAnimation.wrl#LOA1_WalkAnimation"
"LOA1_RunAnimation.x3d#LOA1_RunAnimation" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/LOA1_RunAnimation.x3d#LOA1_RunAnimation" "LOA1_RunAnimation.wrl#LOA1_RunAnimation" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/LOA1_RunAnimation.wrl#LOA1_RunAnimation"
"LOA1_JumpAnimation.x3d#LOA1_JumpAnimation" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/LOA1_JumpAnimation.x3d#LOA1_JumpAnimation" "LOA1_JumpAnimation.wrl#LOA1_JumpAnimation" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/LOA1_JumpAnimation.wrl#LOA1_JumpAnimation"
"LOA1_KneelAnimation.x3d#LOA1_KneelAnimation" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/LOA1_KneelAnimation.x3d#LOA1_KneelAnimation" "LOA1_KneelAnimation.wrl#LOA1_KneelAnimation" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/LOA1_KneelAnimation.wrl#LOA1_KneelAnimation"
The Humanoid node serves as overall container for the Joint Segment Site and Viewpoint nodes which define the skeleton geometry and landmarks of the humanoid figure. Additionally the node provides a means for defining information about the author copyright and usage restrictions of the model.
Version of the humanoid being modeled. Hint: HAnim version 2.0
HAnim 1.1 field container for body head. Hint: replaced by 2.0 skeleton.
HAnim 2.0 field container for body geometry Hint: replaces 1.1 humanoidBody
The Joint node is used as a building block to describe the articulations of the humanoid figure. Each articulation of the humanoid figure is represented by a Joint node each of which is organized into a hierarchy that describes the overall skeleton of the humanoid.
The Segment node is used describe the attributes of the physical links between the joints of the humanoid figure. Each body part (pelvis thigh calf etc.) of the humanoid figure is represented by a Segment node.
The Site node can be used for three purposes: (a) to define an "end effector" location which can be used by an inverse kinematics system (b) to define an attachment point for accessories such as jewelry and clothing and (c) to define a location for a virtual camera in the reference frame of a Segment node (such as a view "through the eyes" of the humanoid for use in multi-user worlds).
A Displacer can be used in three different ways: (a) identify the vertices corresponding to a particular feature on a Segment (b) represent a particular muscular action which displaces the vertices in various directions (linearly or radially) and (c) represent a complete configuration of the vertices in a Segment.
"greenCamo.gif" "greenCamo.jpg" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/greenCamo.gif" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/greenCamo.jpg"
"clone.gif" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/clone.gif"
"humanoidVersion=Nancy V1.2b" "authorName=Cindy Ballreich" "authorEmail=cindy@ballreich.net" "copyright=1997 3Name3D / Yglesias Wallock Divekar Inc. all rights reserved." "creationDate=Tue Dec 30 08:30:08 PST 1997" "usageRestrictions=Noncommercial usage is ok if 3Name3D name and logo www.ballreich.net/vrml/HAnim/small_logo.gif is present and proper credit is given."
"small_logo.gif" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/small_logo.gif"
"centres/sacrum.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/sacrum.wrl"
"centres/l_thigh.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/l_thigh.wrl"
"centres/l_calf.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/l_calf.wrl"
"centres/l_hindfoot.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/l_hindfoot.wrl"
"centres/l_middistal.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/l_middistal.wrl"
"centres/l_middistal_tip.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/l_middistal_tip.wrl"
"centres/r_thigh.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/r_thigh.wrl"
"centres/r_calf.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/r_calf.wrl"
"centres/r_hindfoot.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/r_hindfoot.wrl"
"centres/r_middistal.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/r_middistal.wrl"
"centres/r_middistal_tip.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/r_middistal_tip.wrl"
"centres/l5.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/l5.wrl"
"centres/skull.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/skull.wrl"
"centres/skull_tip.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/skull_tip.wrl"
"centres/l_upperarm.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/l_upperarm.wrl"
"centres/l_forearm.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/l_forearm.wrl"
"centres/l_hand.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/l_hand.wrl"
"centres/l_hand_tip.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/l_hand_tip.wrl"
"centres/r_upperarm.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/r_upperarm.wrl"
"centres/r_forearm.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/r_forearm.wrl"
"centres/r_hand.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/r_hand.wrl"
"centres/r_hand_tip.wrl" "https://www.web3d.org/x3d/content/examples/HumanoidAnimation/CharactersLegacy/centres/r_hand_tip.wrl"
ecmascript: // Initialises the script function initialize() { // Copy coord list into local storage coordList = humanoid.skinCoord.point; } // Transforms the vertices related to a joint function Transform() { // Make sure that this is a joint var iNumJoints = humanoid.joints.length; var bIsJoint = false; var j; for (j=0; (j<iNumJoints) && (bIsJoint==false); j++) { if (humanoid.joints[j].name == joint.name) bIsJoint = true; } // If it is, we process the data if (bIsJoint) { // Read in current joint var currentJoint = joint; // Read in current matrix var currentMatrix = new VrmlMatrix(); currentMatrix.setTransform(translation, rotation, scale, new SFRotation(1,0,0,0), new SFVec3f(0,0,0)); // Create matrix corresponding to this joints transform var newMatrix = new VrmlMatrix(); newMatrix.setTransform(currentJoint.translation, currentJoint.rotation, currentJoint.scale, currentJoint.scaleOrientation, currentJoint.center); // Update current matrix with matrix from this joint currentMatrix = newMatrix.multRight(currentMatrix); // Transform all vertices associated with this joint // var iNumAffectedVertices = currentJoint.affectedVertices.length; var iNumAffectedVertices = currentJoint.skinCoordIndex.length; var v; for (v=0; v<iNumAffectedVertices; v++) { // var vertex = currentJoint.affectedVertices[v]; // var weight = currentJoint.vertexWeights[v]; var vertex = currentJoint.skinCoordIndex[v]; var weight = currentJoint.skinCoordWeight[v]; var newVertex = currentMatrix.multVecMatrix(coordList[vertex]).multiply(weight); humanoid.skinCoord.point[vertex] = humanoid.skinCoord.point[vertex].add(newVertex); } // Transform all children var children = currentJoint.children; var iNumChildren = children.length; var c; for (c=0; c<iNumChildren; c++) { joint = children[c]; currentMatrix.getTransform(translation,rotation,scale); Transform(); } } } // Update event handler function update(value,time) { // Zero output data. var iNumVertices = humanoid.skinCoord.point.length; var v; for (v=0; v<iNumVertices; v++) { humanoid.skinCoord.point[v].x = 0; humanoid.skinCoord.point[v].y = 0; humanoid.skinCoord.point[v].z = 0; } // Initialise transform data translation = new SFVec3f(0,0,0); scale = new SFVec3f(1,1,1); rotation = new SFRotation(0,0,1,0); // First (and only) item in humanoidBody should be the humanoid_root. // This is stored as the joint we want to do next // This could do with being more robust, rather than a'should be ok'. // joint = humanoid.humanoidBody[0]; joint = humanoid.skeleton[0]; // Call transform function Transform(); }
ecmascript: //Global Variables var currentAnimatorIndex; var avatarJoints; var animatorFields; function initialize() { //Avatar Joint Names avatarJoints = new Array(); avatarJoints[0] ='humanoid_root'; avatarJoints[1] ='sacroiliac'; avatarJoints[2] ='l_hip'; avatarJoints[3] ='l_knee'; avatarJoints[4] ='l_ankle'; avatarJoints[5] ='r_hip'; avatarJoints[6] ='r_knee'; avatarJoints[7] ='r_ankle'; avatarJoints[8] ='skullbase'; avatarJoints[9] ='l_shoulder'; avatarJoints[10] ='l_elbow'; avatarJoints[11] ='l_wrist'; avatarJoints[12] ='r_shoulder'; avatarJoints[13] ='r_elbow'; avatarJoints[14] ='r_wrist'; avatarJoints[15] ='l_midtarsal'; avatarJoints[16] ='r_midtarsal'; avatarJoints[17] ='vl_5'; //ANIMATOR field names will be used //as fromField value of created ROUTES animatorFields = new Array(); for(i = 0; i <= 17; i++) { if(avatarJoints[i] =='sacroiliac') { animatorFields[i] ='lower_body_rotation_changed'; } else { animatorFields[i] = avatarJoints[i] + '_rotation_changed'; } } //end for loop // Current Avatar Choice // 0 : Allen // 1 : Nancy // 2 : Boxman AvatarChoice = 0; // Current Animator Behavior Index // 0 : WALK // 1 : RUN // 2 : JUMP // 3 : STAND // 4 : KNEEL currentAnimatorIndex = 3; //Initial behavior: KNEEL createRoutes(); } function createRoutes() { //Add Routes for Allen which is current avatar if(AvatarChoice == 0) { //Exception routing for humanoid_Root translation Browser.addRoute(Behaviors[currentAnimatorIndex], avatarJoints[0] + '_translation_changed', AllenJointNodes[0],'set_translation'); for(i = 0; i < 15; i++) { Browser.addRoute(Behaviors[currentAnimatorIndex], animatorFields[i],AllenJointNodes[i],'set_rotation'); } } //Add Routes for Nancy which is current avatar if(AvatarChoice == 1) { //Exception routing for humanoid_Root translation Browser.addRoute(Behaviors[currentAnimatorIndex], avatarJoints[0] + '_translation_changed', NancyJointNodes[0],'set_translation'); for(i = 0; i < 15; i++) { Browser.addRoute(Behaviors[currentAnimatorIndex], animatorFields[i],NancyJointNodes[i],'set_rotation'); } } //Add Routes for Boxman which is current avatar if(AvatarChoice == 2) { //Exception routing for humanoid_Root translation Browser.addRoute(Behaviors[currentAnimatorIndex], avatarJoints[0] + '_translation_changed', BoxmanJointNodes[0],'set_translation'); for(i = 0; i <= 16; i++) { if(i != 1) { //no sacroiliac in Boxman Browser.addRoute(Behaviors[currentAnimatorIndex], animatorFields[i], BoxmanJointNodes[i],'set_rotation'); } } } } function removeRoutes() { //Remove Routes for Allen which is current avatar if(AvatarChoice == 0) { //Exception routing for humanoid_Root translation Browser.deleteRoute(Behaviors[currentAnimatorIndex], avatarJoints[0] + '_translation_changed', AllenJointNodes[0],'set_translation'); for(i = 0; i < 15; i++) { Browser.deleteRoute(Behaviors[currentAnimatorIndex], animatorFields[i],AllenJointNodes[i],'set_rotation'); } } //Remove Routes for Nancy which is current avatar if(AvatarChoice == 1) { //Exception routing for humanoid_Root translation Browser.deleteRoute(Behaviors[currentAnimatorIndex], avatarJoints[0] + '_translation_changed', NancyJointNodes[0],'set_translation'); //Exception routing for humanoid_Root translation Browser.deleteRoute(Behaviors[currentAnimatorIndex], avatarJoints[0] + '_translation_changed', NancyJointNodes[0],'set_translation'); for(i = 0; i < 15; i++) { Browser.deleteRoute(Behaviors[currentAnimatorIndex], animatorFields[i],NancyJointNodes[i],'set_rotation'); } } //Remove Routes for Boxman which is current avatar if(AvatarChoice == 2) { //Exception routing for humanoid_Root translation Browser.deleteRoute(Behaviors[currentAnimatorIndex], avatarJoints[0] + '_translation_changed', BoxmanJointNodes[0],'set_translation'); for(i = 0; i < 17; i++) { if(i != 1) { Browser.deleteRoute(Behaviors[currentAnimatorIndex], animatorFields[i],BoxmanJointNodes[i],'set_rotation'); } } } } function switchAvatarToAllen (bool, timeStamp) {//Invoked when Allen text is clicked. //A control structure to avoid excessive work. If current avatar is Allen, don't do anything. if(AvatarChoice != 0) { removeRoutes(); AvatarChoice = 0; createRoutes(); } } function switchAvatarToNancy (bool, timeStamp) {//Invoked when Nancy text is clicked. //A control structure to avoid excessive work. If current avatar is Nancy, don't do anything. if(AvatarChoice != 1) { removeRoutes(); AvatarChoice = 1; createRoutes(); } } function switchAvatarToBoxman (bool, timeStamp) {//Invoked when Boxman text is clicked. //A control structure to avoid excessive work. If current avatar is Boxman, don't do anything. if(AvatarChoice != 2) { removeRoutes(); AvatarChoice = 2; createRoutes(); } } function changeBehaviorToWalk(bool, timeStamp) { if(currentAnimatorIndex != 0) { removeRoutes(); currentAnimatorIndex = 0; createRoutes(); } } function changeBehaviorToRun(bool, timeStamp) { if(currentAnimatorIndex != 1) { removeRoutes(); currentAnimatorIndex = 1; createRoutes(); } } function changeBehaviorToJump(bool, timeStamp) { if(currentAnimatorIndex != 2) { removeRoutes(); currentAnimatorIndex = 2; createRoutes(); } } function changeBehaviorToStand(bool, timeStamp) { if(currentAnimatorIndex != 3) { removeRoutes(); currentAnimatorIndex = 3; createRoutes(); } } function changeBehaviorToKneel(bool, timeStamp) { if(currentAnimatorIndex != 4) { removeRoutes(); currentAnimatorIndex = 4; createRoutes(); } }