[x3d-public] Extrusions, take 3 - animated snake example works everywhere but Xj3D

Don Brutzman brutzman at nps.edu
Tue Jan 26 18:50:57 PST 2016


[added cc: source mailing list for Xj3D]

On 1/26/2016 5:11 PM, doug sanden wrote:
>
> http://dug9.users.sourceforge.net/web3d/tests/41.x3d
>
> snake animation animating extrusion spine

Hi Doug.  So that others might also know the genesis of this example, I believe X3D adaptations of the original version are found here:

X3D Example Archives: VRML 2.0 Sourcebook, Chapter 15 - Extrusion
http://www.web3d.org/x3d/content/examples/Vrml2.0Sourcebook/Chapter15-Extrusion/

Figure 15.17 Wiggling Snake
A wiggling snake whose spine is animated using a CoordinateInterpolator node.
http://www.web3d.org/x3d/content/examples/Vrml2.0Sourcebook/Chapter15-Extrusion/Figure15.17WigglingSnake.x3d
http://www.web3d.org/x3d/content/examples/Vrml2.0Sourcebook/Chapter15-Extrusion/Figure15.17WigglingSnake.xhtml

Figure 15.17 Wiggling Snake With Axes (which help you discern how the animation works)
A wiggling snake whose spine is animated using a CoordinateInterpolator node.
http://www.web3d.org/x3d/content/examples/Vrml2.0Sourcebook/Chapter15-Extrusion/Figure15.17WigglingSnakeWithAxes.x3d
http://www.web3d.org/x3d/content/examples/Vrml2.0Sourcebook/Chapter15-Extrusion/Figure15.17WigglingSnakeWithAxes.xhtml

X3D Scene Metadata for original authors:
creator:	Figure 15.17, The VRML 2.0 Sourcebook, Copyright [1997] By Andrea L. Ames, David R. Nadeau, and John L. Moreland
reference:	http://www.wiley.com/legacy/compbooks/vrml2sbk/ch15/15fig17.htm
reference:	http://www.wiley.com/legacy/compbooks/vrml2sbk/ch15/15fig17.wrl

The xhtml links listed above show that X3DOM works fine on this example.

I tested this scene with Cobweb by using X3D-Edit to generate a local html file in the same directory.  Works nicely!  Page and screenshot attached.

Hopefully the presence of this scene in your test suite means that FreeWrl supports this Extrusion animation OK... yes indeed, launching FreeWRL from X3D-Edit displays and animates correctly.  Screenshot attached.

Autolaunching other X3D players simultaneously from X3D-Edit shows everything else working OK: Instant Reality, BS Contact (plugin and application), H3DViewer, Octaga, amd view3dscene (with accompanying animation of bounding boxes).

Xj3D remains the problem child - our last holdout perhaps.  It animates the spine OK, but doesn't get the cross section computed correctly. Screenshot attached.  I haven't been able to figure out the error in that code.  Perhaps someone with close knowledge of Extrusion math will spot the computational error - source excerpts follow.

https://sourceforge.net/projects/xj3d/

https://sourceforge.net/p/xj3d/code/HEAD/tree/trunk/src/java/org/web3d/vrml/renderer/ogl/nodes/geom3d/OGLExtrusion.java
=========================================
     /**
      * Result: Completed "coords" array: An array of all the float information
      * describing each vertex in the extrusion, created by applying the
      * transforms to the vfCrossSection points
      *
      * @author Eric Fickenscher
      */
     private void createExtrusionCoordinates(){

         // calculate the number of coordinates needed for the sides
         // of the extrusion: 3 coordinates per vertex, one vertex per
         // crossSectionPoint, and one set of crossSectionPoints per spinePoint
         coords = new float[ numSpine * uniqueCrossSectionPoints * 3 ];

         for(int i = 0; i < numSpine; i++) {

             Matrix4f tx = transforms[i];

             for(int j = 0; j < uniqueCrossSectionPoints; j++) {

                 int ind = (i * uniqueCrossSectionPoints + j) * 3;

                 // basically a transform, in place
                 float c_x = vfCrossSection[j*2   ];
                 float c_z = vfCrossSection[j*2 +1];

                 float x = c_x * tx.m00 + c_z * tx.m02 + tx.m03;
                 float y = c_x * tx.m10 + c_z * tx.m12 + tx.m13;
                 float z = c_x * tx.m20 + c_z * tx.m22 + tx.m23;

                 coords[ind] = x;
                 coords[ind + 1] = y;
                 coords[ind + 2] = z;
             }
         }
     }
=========================================
     /**
      * Result: Completed "coordIndex" array: an int array representing an
      * IndexedFaceSet representation of the extrusion.
      *
      * @author Eric Fickenscher
      */
     private void createIndicesTriangleArray(){

         int sizeOfCoordIndex = 5*(numCrossSection-1) * (numSpine-1);
         if( vfBeginCap) sizeOfCoordIndex += uniqueCrossSectionPoints+1;
         if( vfEndCap)   sizeOfCoordIndex += uniqueCrossSectionPoints+1;

         coordIndex = new int[sizeOfCoordIndex];

         int indx = 0;
         int curIndex;

         // for each separate segment between two spine points
         for(int i = 0; i<numSpine-1; i++){

             curIndex = i*uniqueCrossSectionPoints;

             // build a quadrilateral for every crossSection-to-crossSection side around that segment
             // note that Xj3D wireframe mode shows triangulation even though quads are being built here
             for(int j = 0; j < numCrossSection-1; j++){

                 if(vfCCW){
                     coordIndex[ indx++ ] = j + curIndex;
                     coordIndex[ indx++ ] = j + curIndex +1;
                     coordIndex[ indx++ ] = j + curIndex + uniqueCrossSectionPoints +1;
                     coordIndex[ indx++ ] = j + curIndex + uniqueCrossSectionPoints;
                 } else {
                     coordIndex[ indx++ ] = j + curIndex + uniqueCrossSectionPoints;
                     coordIndex[ indx++ ] = j + curIndex + uniqueCrossSectionPoints +1;
                     coordIndex[ indx++ ] = j + curIndex +1;
                     coordIndex[ indx++ ] = j + curIndex;
                 }

                 coordIndex[ indx++ ] = -1;
             }

             if(crossSectionClosed){
                 coordIndex[indx -4] -= uniqueCrossSectionPoints;
                 coordIndex[indx -3] -= uniqueCrossSectionPoints;
             }
         }

         // note that Xj3D wireframe mode shows triangulation even though N-sided polygons are being built here
         if( vfBeginCap) {

             for(int i = 0; i < uniqueCrossSectionPoints; i++){
                 if(vfCCW) coordIndex[ indx++ ] = uniqueCrossSectionPoints -i -1;
                 else coordIndex[ indx++ ] = i;
             }
             coordIndex[ indx++ ] = -1;
         }
         if( vfEndCap) {

             for(int i = 0; i < uniqueCrossSectionPoints; i++){
                 if(vfCCW) coordIndex[ indx++ ] = (numSpine-1)*uniqueCrossSectionPoints + i;
                 else coordIndex[ indx++ ] = numSpine*uniqueCrossSectionPoints -i -1;
             }
             coordIndex[ indx ] = -1;
         }
     }
=========================================
     /**
      * Creates a rotation for each spine point to avoid twisting of the profile
      * when the orientation of SCP changes.
      * @author Pasi Paasiala
      * @param z the vector containing the z unit vectors for each spine point
      */
     private Matrix3f[] createCorrectionRotations(Vector3f[] z) {

         Matrix3f[] correctionRotations = new Matrix3f[spines.length];
         correctionRotations[0] = new Matrix3f();
         correctionRotations[0].setIdentity();
         AxisAngle4f checkAngle = new AxisAngle4f();

         // testPoint is used to find the angle that gives the smallest distance
         // between the previous and current rotation. Find a point that is not
         // in the origin.
         Point3f testPoint = new Point3f(vfCrossSection[0], 0, vfCrossSection[1]);

         for(int i = 0; i < numCrossSection; i++) {
             if(vfCrossSection[i*2] != 0 || vfCrossSection[i*2 +1] != 0) {
                 testPoint = new Point3f(vfCrossSection[i*2], 0, vfCrossSection[i*2 +1]);
                 break;
             }
         }

         // Fix the orientations by using the angle between previous z and current z
         for(int i = 1; i < spines.length; i++) {
             float angle = z[i].angle(z[i - 1]);
             correctionRotations[i] = correctionRotations[i - 1];
             if(angle != 0) {
                 correctionRotations[i] = new Matrix3f(correctionRotations[i - 1]);
                 Point3f previous = new Point3f();
                 //Point3f previous = testPoint;
                 // Test with negative angle:
                 Matrix3f previousRotation = new Matrix3f(rotations[i - 1]);
                 previousRotation.mul(correctionRotations[i - 1]);
                 previousRotation.transform(testPoint, previous);
                 Matrix3f delta = new Matrix3f();
                 delta.setIdentity();
                 delta.rotY(-angle);
                 correctionRotations[i].mul(delta);

                 Matrix3f negativeRotation = new Matrix3f(rotations[i]);
                 negativeRotation.mul(correctionRotations[i]);

                 Point3f pointNegative = new Point3f();
                 negativeRotation.transform(testPoint,pointNegative);

                 float distNegative = pointNegative.distance(previous);

                 // Test with positive angle
                 delta.rotY(angle*2);
                 correctionRotations[i].mul(delta);
                 Matrix3f positiveRotation = new Matrix3f(rotations[i]);
                 positiveRotation.mul(correctionRotations[i]);
                 Point3f pointPositive = new Point3f();
                 positiveRotation.transform(pointPositive);
                 float distPositive = pointPositive.distance(previous);

                 if(distPositive > distNegative) {
                     // Reset correctionRotations to negative angle
                     delta.rotY(-angle*2);
                     correctionRotations[i].mul(delta);
                 }

                 // Check that the angle is not more than PI.
                 // If it is subtract PI from angle
                 checkAngle.set(correctionRotations[i]);
                 if(((float)Math.PI - checkAngle.angle) < 0.001) {
                     correctionRotations[i].rotY((float)(checkAngle.angle - Math.PI));
                 }
             }
         }

         return correctionRotations;
     }
=========================================

There are also some trace methods available in there...

perhaps we should trace the some piece of the resulting IFS in another X3D player and compare? that might help us isolate where the math error occurs in Xj3D.

all the best, Don
-- 
Don Brutzman  Naval Postgraduate School, Code USW/Br       brutzman at nps.edu
Watkins 270,  MOVES Institute, Monterey CA 93943-5000 USA   +1.831.656.2149
X3D graphics, virtual worlds, navy robotics http://faculty.nps.edu/brutzman
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Figure15.17WigglingSnakeCobweb.png
Type: image/png
Size: 23836 bytes
Desc: not available
URL: <http://web3d.org/pipermail/x3d-public_web3d.org/attachments/20160126/45e17315/attachment-0003.png>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://web3d.org/pipermail/x3d-public_web3d.org/attachments/20160126/45e17315/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Figure15.17WigglingSnakeFreeWRL.png
Type: image/png
Size: 11571 bytes
Desc: not available
URL: <http://web3d.org/pipermail/x3d-public_web3d.org/attachments/20160126/45e17315/attachment-0004.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Figure15.17WigglingSnakeXj3D.png
Type: image/png
Size: 23897 bytes
Desc: not available
URL: <http://web3d.org/pipermail/x3d-public_web3d.org/attachments/20160126/45e17315/attachment-0005.png>


More information about the x3d-public mailing list