#VRML V2.0 utf8 PROTO SpiderLeg [ field SFVec3f base 0 0 0 # hip position in space field SFVec3f target 1 0 0 # where should foot go? eventIn SFVec3f set_base eventIn SFVec3f set_target ] { Group { children [ # shadow DEF SHADOW Transform { children Shape { appearance Appearance { material Material { emissiveColor 0 0 0 } } geometry IndexedLineSet { coord DEF SHADCOORDS Coordinate { point [ 0 .01 0, 2 .01 0 ] } coordIndex [ 0 1 ] } } } # leg DEF HIPY Transform { translation IS base set_translation IS set_base children DEF HIPZ Transform { children [ DEF LINE Shape { appearance Appearance { material Material { emissiveColor .7 .3 .2 } } geometry IndexedLineSet { coord Coordinate { point [ 0 0 0, 1 0 0 ] } coordIndex [ 0 1 ] } } DEF KNEE Transform { translation 1 0 0 children USE LINE } ] } } # do IK and calc shadow DEF SCRIPT Script { eventIn SFVec3f set_base IS set_base eventIn SFVec3f set_target IS set_target field SFVec3f base IS base field SFVec3f target IS target eventOut SFRotation hipYRotation eventOut SFRotation hipZRotation eventOut SFRotation kneeRotation eventOut MFVec3f shadowPoints eventOut SFVec3f shadowPosition url "vrmlscript: function calcJointAngles() { // calc shoulder y rotation (angle to rotate 1 0 0 to point at target) a = new SFVec3f(1, 0, 0); b = new SFVec3f(target.x-base.x, 0, target.z-base.z); b = b.normalize(); angle = Math.acos(a.dot(b)); if(target.z > base.z) angle = 2*Math.PI - angle; hipYRotation = new SFRotation(0, 1, 0, angle); // calc shoulder z rotation (to get knee calfLength away from target) thighLength = 1; thighLength2 = Math.pow(thighLength,2); calfLength = 1; calfLength2 = Math.pow(calfLength,2); targDist = target.subtract(base).length(); targDist2 = Math.pow(targDist,2); shadowPoints = new MFVec3f(); shadowPoints[0] = new SFVec3f(0, 0.01, 0); legLength = thighLength + calfLength; xztarg = new SFVec3f(target.x-base.x, 0, target.z-base.z); if(targDist > legLength) { theta = 0; alpha = 0; shadowPoints[1] = new SFVec3f(legLength, 0.01, 0); } else { a = new SFVec3f(1, 0, 0); b = new SFVec3f(xztarg.length(), -base.y, 0); b = b.normalize(); angle = Math.acos(a.dot(b)); theta = Math.acos((calfLength2 - thighLength2 - targDist2) / (-2 * thighLength * targDist)); theta -= angle; alpha = Math.PI - Math.acos((targDist2 - calfLength2 - thighLength2) / (-2 * calfLength * thighLength)); alpha = -alpha; shadowPoints[1] = new SFVec3f(xztarg.length(), .01, 0); } hipZRotation = new SFRotation(0, 0, 1, theta); kneeRotation = new SFRotation(0, 0, 1, alpha); } // reposition hip attachment function set_base(val) { base = val; shadowPosition = new SFVec3f(base.x, 0, base.z); calcJointAngles(); } // reposition foot function set_target(val) { target = val; calcJointAngles(); } function initialize() { calcJointAngles(); } " } ] } ROUTE SCRIPT.hipYRotation TO HIPY.rotation ROUTE SCRIPT.hipYRotation TO SHADOW.rotation ROUTE SCRIPT.hipZRotation TO HIPZ.rotation ROUTE SCRIPT.kneeRotation TO KNEE.rotation ROUTE SCRIPT.shadowPoints TO SHADCOORDS.point ROUTE SCRIPT.shadowPosition TO SHADOW.translation }