The BillboardBehavior

It is often the case that the programmer wants some scene graph elements to always face a particular way. This situation arises in 3D text labeling of axis and other objects where it would look strange to see the side of the text object.

Java 3D provides an extension to the Behavior class called Billboard that forces the +z direction of an object to always face the viewer. The Billboard class can be quite useful in this regard as we demonstrate in Listing 12.15.

Recall from our MRPhysics visualization that our axes were missing labels. This is a severe limitation in our ability to see where all the movement is oriented. In other words, we cannot tell which way is up as we rotate the axis. We now modify AxisBody by adding a billboard behavior for keeping the axis labels facing the user.

Listing 12.15 AxisBody.java
import java.lang.Math.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import javax.media.j3d.Text3D;
import java.awt.Font;

public class AxisBody extends TransformGroup {

    float length, radius;
    int nsegs;
    Appearance app;

     float xDirection, yDirection;
     float xVecBody, yVecBody;
     float endcapPos;
     float basecapPos;

     private String fontName = "TestFont";
     int nFaces;      // #(vertices) per VecBody face
     int VecBodyFaceTotalVertexCount;      // total #(vertices) in all teeth
     int nStrips[] = new int[1]; // per VecBody vertex count

     int VecBodyVertexCount;      // #(vertices) for VecBody
     int VecBodyStripCount[] = new int[1]; // #(vertices) in strip/strip

     Point3f coord = new Point3f(0.0f, 0.0f, 0.0f);


    // The angle subtended by a single segment
    double segmentAngle = 2.0 * Math.PI/nsegs;
    double tempAngle;

    public AxisBody(int nsegs, float length, float radius, Appearance app) {

        this.nsegs = nsegs;
        this.length = length;
        this.radius = radius;
        this.app = app;

        //allow capability to write and read at runtime

    this.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        this.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

        Transform3D tempTrans = new Transform3D();

        //create an empty shape to add Geometry

        Shape3D zaxis =  new Shape3D();
        zaxis.setAppearance(app);
        zaxis.addGeometry(this.makeBody(-length/2, length/2));

        this.addChild(zaxis);
        Point3f zlabelpt = new Point3f( 0.f, 0.f, length/2);
        this.addChild(MakeLabels("X",zlabelpt));


        Shape3D ztxt = new Shape3D();

        TransformGroup xTG = new TransformGroup();

        tempTrans.rotX(Math.PI/2);
        xTG.setTransform(tempTrans);

        Shape3D xaxis =  new Shape3D();
        xaxis.setAppearance(app);
        xaxis.addGeometry(this.makeBody(-length/2, length/2));

        xTG.addChild(xaxis);
        this.addChild(xTG);
        Point3f xlabelpt = new Point3f(length/2, 0.f, 0.f);
        this.addChild(MakeLabels("Y",xlabelpt));


        tempTrans.setIdentity();
        TransformGroup yTG = new TransformGroup();
        tempTrans.rotY(Math.PI/2);
        yTG.setTransform(tempTrans);
        Shape3D yaxis =  new Shape3D();
        yaxis.setAppearance(app);
        yaxis.addGeometry(this.makeBody(-length/2, length/2));
        yTG.addChild(yaxis);
        this.addChild(yTG);
        Point3f ylabelpt = new Point3f(0.f, length/2, 0.f);
        this.addChild(MakeLabels("Z",ylabelpt));

    }
    public TransformGroup MakeLabels(String s, Point3f p) {

        Font3D f3d = new Font3D(new Font(fontName, Font.PLAIN, 1),
                                new FontExtrusion());

        int sl = s.length();

        Appearance apText = new Appearance();
. . .

        Text3D txt = new Text3D(f3d, s, p);
        Shape3D textShape = new Shape3D();
        textShape.setGeometry(txt);
        textShape.setAppearance(apText);

   // Using billboard behavior on text3d

        TransformGroup bbTransPt = new TransformGroup();
        bbTransPt.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        bbTransPt.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        Billboard bboardPt = new Billboard( bbTransPt );
        this.addChild( bboardPt );
        BoundingSphere bounds =
        new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);

        bboardPt.setSchedulingBounds( bounds );
    bboardPt.setAlignmentMode(Billboard.ROTATE_ABOUT_POINT);

    // text is centered around 0, 3, 0.  Make it rotate around 0,5,0
    Point3f rotationPt = new Point3f(0.0f, 5.0f, 0.0f);
    bboardPt.setRotationPoint(p);
        bbTransPt.addChild( textShape );

        return bbTransPt;
    }


Figure 12.8 shows the output of the BasicRecipeJ3D using the AxisBody class added to the scene graph. Note how the axis labels always face the viewer.

Figure 12.8. Screenshot from BasicRecipeJ3D using the new AxisBody class.


Note that we could have achieved the same effect using the OrientedShape3D class. The difference is that usage between the Billboard class and the OrientedShape3D class can be subtle. Another difference is that the OrientedShape3D can function well when multiple View objects are specified. A Billboard object will stay aligned with the primary View only (that is, the first View added to the Canvas3D). Also, remember that the OrientedShape3D extends Shape3D, and the Billboard class extends Behavior. This means that the OrientedShape3D can be used in a SharedGroup, whereas a Billboard cannot.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset