Articulation and Mesh Deformation


Moving a Limb

MoveableLimb allows a limb to be moved around the x-, y-, and z-axes. This is achieved by affecting the xAxisTG, yAxisTG, and zAxisTG TransformGroups in the limb's subgraph.

MoveableLimb maintains range information for the three axes and ignores rotations that would move the limb outside of those ranges. If a range isn't specified, then it will be assumed to be 0 (i.e., rotation is not possible around that axis). The programmer calls setRanges( ) or setRange( ) to initialize the range details for different axes:

     // globals: the axis ranges     private double xMin, xMax, yMin, yMax, zMin, zMax;     public void setRanges(double x1, double x2, double y1, double y2,                                     double z1, double z2)     { setRange(X_AXIS, x1, x2);       setRange(Y_AXIS, y1, y2);       setRange(Z_AXIS, z1, z2);     }     public void setRange(int axis, double angle1, double angle2)     // set the range for axis only     {       if (angle1 > angle2) {         System.out.println(limbName + ": wrong order... swapping");         double temp = angle1;         angle1 = angle2;         angle2 = temp;       }       if (axis == X_AXIS) {         xMin = angle1;  xMax = angle2;       }       else if (axis == Y_AXIS) {         yMin = angle1;  yMax = angle2;       }       else {  // Z_AXIS         zMin = angle1;  zMax = angle2;       }     }  // end of setRange( )

The methods initialize the xMin, xMax, yMin, yMax, zMin, and zMax globals and ensure the ranges are given in the right order.

Rotations are processed by updateLimb( ), which is called from the Figure object with axis and angle arguments:

     public void updateLimb(int axis, double angleStep)     // Attempt to rotate this limb by angleStep around axis     {       if (axis == X_AXIS)         applyAngleStep(angleStep, xCurrAng, axis, xMax, xMin);       else if (axis == Y_AXIS)         applyAngleStep(angleStep, yCurrAng, axis, yMax, yMin);       else    // Z_AXIS         applyAngleStep(angleStep, zCurrAng, axis, zMax, zMin);     }     private void applyAngleStep(double angleStep, double currAngle,                                     int axis, double max, double min)     /* Before any rotation, check that the angle step moves the        limb within the ranges for this axis.        If not then rotate to the range limit, and no further. */     {       if ((currAngle >= max) && (angleStep > 0)) {  // will exceed max         System.out.println(limbName + ": no rot; already at max");         return;       }       if (currAngle <= min && (angleStep < 0)) { // will drop below min         System.out.println(limbName + ": no rot; already at min");         return;       }       double newAngle = currAngle + angleStep;       if (newAngle > max) {         System.out.println(limbName + ": reached max angle");         angleStep = max - currAngle;   // rotate to max angle only       }       else if (newAngle < min) {         System.out.println(limbName + ": reached min angle");         angleStep = min - currAngle;   // rotate to min angle only       }       makeUpdate(axis, angleStep);    // do the rotation     }  // end of applyAngleStep( )

updateLimb( ) uses the supplied axis value to pass the correct axis range to applyAngleStep( ). This method checks that the requested rotation stays within the allowed range. The range extends from some largest negative value to a largest positive angle (referred to by min and max). This may mean ignoring the rotation (if the min or max value has been reached), or reducing the rotation so the limb stops at min or max. Once the actual rotation angle has been calculated (and stored in angleStep), makeUpdate( ) is called:

     // globals: the current angle in three axes     private double xCurrAng, yCurrAng, zCurrAng;     private void makeUpdate(int axis, double angleStep)     // rotate the limb by angleStep around the given axis     {       if (axis == X_AXIS) {         rotTrans.rotX( Math.toRadians(angleStep));         xAxisTG.getTransform(currTrans);         currTrans.mul(rotTrans);         xAxisTG.setTransform(currTrans);         xCurrAng += angleStep;       }       else if (axis == Y_AXIS) {         rotTrans.rotY( Math.toRadians(angleStep));         yAxisTG.getTransform(currTrans);         currTrans.mul(rotTrans);         yAxisTG.setTransform(currTrans);         yCurrAng += angleStep;       }       else {  // z-axis         rotTrans.rotZ( Math.toRadians(angleStep));         zAxisTG.getTransform(currTrans);         currTrans.mul(rotTrans);         zAxisTG.setTransform(currTrans);         zCurrAng += angleStep;       }     } // end of makeUpdate( )

makeUpdate( ) applies a rotation to xAxisTG, yAxisTG, or zAxisTG depending on the axis value supplied by the user. The rotational transform is multiplied to the current value held in the relevant TRansformGroup, which is equivalent to adding the rotation to the current angle. rotTrans and currTrans are global transform3D variables to save on the cost of object creation and deletion. The new limb angle is stored in xCurrAng, yCurrAng, or zCurrAng.

The limb can be reset to its initial orientation, via a call to reset( ) by the Figure object:

     public void reset( )     {       rotTrans.rotX( Math.toRadians(-xCurrAng));   // reset x angle       xAxisTG.getTransform(currTrans);       currTrans.mul(rotTrans);       xAxisTG.setTransform(currTrans);       xCurrAng = 0;       rotTrans.rotY( Math.toRadians(-yCurrAng));    // reset y angle       yAxisTG.getTransform(currTrans);       currTrans.mul(rotTrans);       yAxisTG.setTransform(currTrans);       yCurrAng = 0;       rotTrans.rotZ( Math.toRadians(-zCurrAng));    // reset z angle       zAxisTG.getTransform(currTrans);       currTrans.mul(rotTrans);       zAxisTG.setTransform(currTrans);       zCurrAng = 0;     }  // end of reset( )

The rotations maintained by xAxisTG, yAxisTG, and zAxisTG are undone by rotating each one by the negative of their current angle, as stored in xCurrAng, yCurrAng, and zCurrAng. The simplicity of this operation is due to the separation of the three degrees of freedom into three TRansformGroups.

Moving an Elliptical Limb

MoveableEllipticLimb shows how little code is required to adjust the limb's shape. Only makeShape( ) must be overridden to use EllipseShape3D instead of the version in the Limb class that utilizes LatheShape3D:

     protected void makeShape( )     {       EllipseShape3D es;       if (texPath != null) {         TextureLoader texLd =             new TextureLoader("textures/"+texPath, null);         Texture tex = texLd.getTexture( );         es = new EllipseShape3D(xsIn, ysIn, tex);       }       else         es = new EllipseShape3D(xsIn, ysIn, null);       zAxisTG.addChild(es);  // add the shape to the limb's graph     }



Killer Game Programming in Java
Killer Game Programming in Java
ISBN: 0596007302
EAN: 2147483647
Year: 2006
Pages: 340

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net