Example usage for javax.media.j3d Appearance Appearance

List of usage examples for javax.media.j3d Appearance Appearance

Introduction

In this page you can find the example usage for javax.media.j3d Appearance Appearance.

Prototype

public Appearance() 

Source Link

Document

Constructs an Appearance component object using defaults for all state variables.

Usage

From source file:ExLinearFog.java

public ColumnScene(Component observer) {
    BoundingSphere worldBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), // Center
            1000.0); // Extent

    // Add a few lights
    AmbientLight ambient = new AmbientLight();
    ambient.setEnable(true);/*from w  ww .j  a va2  s.c  o  m*/
    ambient.setColor(new Color3f(0.2f, 0.2f, 0.2f));
    ambient.setInfluencingBounds(worldBounds);
    addChild(ambient);

    DirectionalLight dir1 = new DirectionalLight();
    dir1.setEnable(true);
    dir1.setColor(new Color3f(1.0f, 1.0f, 1.0f));
    dir1.setDirection(new Vector3f(0.8f, -0.35f, 0.5f));
    dir1.setInfluencingBounds(worldBounds);
    addChild(dir1);

    DirectionalLight dir2 = new DirectionalLight();
    dir2.setEnable(true);
    dir2.setColor(new Color3f(0.75f, 0.75f, 1.0f));
    dir2.setDirection(new Vector3f(-0.7f, -0.35f, -0.5f));
    dir2.setInfluencingBounds(worldBounds);
    addChild(dir2);

    // Load textures
    TextureLoader texLoader = new TextureLoader("grass06.jpg", observer);
    Texture grassTex = texLoader.getTexture();
    if (grassTex == null)
        System.err.println("Cannot load grass06.jpg texture");
    else {
        grassTex.setBoundaryModeS(Texture.WRAP);
        grassTex.setBoundaryModeT(Texture.WRAP);
        grassTex.setMinFilter(Texture.NICEST);
        grassTex.setMagFilter(Texture.NICEST);
        grassTex.setMipMapMode(Texture.BASE_LEVEL);
        grassTex.setEnable(true);
    }

    texLoader = new TextureLoader("marble10.jpg", observer);
    Texture walkTex = texLoader.getTexture();
    if (walkTex == null)
        System.err.println("Cannot load marble10.jpg texture");
    else {
        walkTex.setBoundaryModeS(Texture.WRAP);
        walkTex.setBoundaryModeT(Texture.WRAP);
        walkTex.setMinFilter(Texture.NICEST);
        walkTex.setMagFilter(Texture.NICEST);
        walkTex.setMipMapMode(Texture.BASE_LEVEL);
        walkTex.setEnable(true);
    }

    texLoader = new TextureLoader("granite07rev.jpg", observer);
    columnTex = texLoader.getTexture();
    if (columnTex == null)
        System.err.println("Cannot load granite07rev.jpg texture");
    else {
        columnTex.setBoundaryModeS(Texture.WRAP);
        columnTex.setBoundaryModeT(Texture.WRAP);
        columnTex.setMinFilter(Texture.NICEST);
        columnTex.setMagFilter(Texture.NICEST);
        columnTex.setMipMapMode(Texture.BASE_LEVEL);
        columnTex.setEnable(true);
    }

    //
    //  Build the ground
    //    +-----+---+-----+
    //    | | | |
    //    | G | W | G |
    //    | | | |
    //    +-----+---+-----+
    //
    //  where "G" is grass, and "W" is a walkway between columns
    //
    Vector3f trans = new Vector3f();
    Transform3D tr = new Transform3D();
    TransformGroup tg;

    //  Walkway appearance
    Appearance walkApp = new Appearance();

    Material walkMat = new Material();
    walkMat.setAmbientColor(0.5f, 0.5f, 0.5f);
    walkMat.setDiffuseColor(1.0f, 1.0f, 1.0f);
    walkMat.setSpecularColor(0.0f, 0.0f, 0.0f);
    walkApp.setMaterial(walkMat);

    TextureAttributes walkTexAtt = new TextureAttributes();
    walkTexAtt.setTextureMode(TextureAttributes.MODULATE);
    walkTexAtt.setPerspectiveCorrectionMode(TextureAttributes.NICEST);
    tr.setIdentity();
    tr.setScale(new Vector3d(1.0, 6.0, 1.0));
    walkTexAtt.setTextureTransform(tr);
    walkApp.setTextureAttributes(walkTexAtt);

    if (walkTex != null)
        walkApp.setTexture(walkTex);

    //  Grass appearance
    Appearance grassApp = new Appearance();

    Material grassMat = new Material();
    grassMat.setAmbientColor(0.5f, 0.5f, 0.5f);
    grassMat.setDiffuseColor(1.0f, 1.0f, 1.0f);
    grassMat.setSpecularColor(0.0f, 0.0f, 0.0f);
    grassApp.setMaterial(grassMat);

    TextureAttributes grassTexAtt = new TextureAttributes();
    grassTexAtt.setTextureMode(TextureAttributes.MODULATE);
    grassTexAtt.setPerspectiveCorrectionMode(TextureAttributes.NICEST);
    tr.setIdentity();
    tr.setScale(new Vector3d(2.0, 8.0, 1.0));
    grassTexAtt.setTextureTransform(tr);
    grassApp.setTextureAttributes(grassTexAtt);

    if (grassTex != null)
        grassApp.setTexture(grassTex);

    //  Left grass
    trans.set(-LawnWidth / 2.0f - WalkwayWidth / 2.0f, -1.6f, 0.0f);
    tr.set(trans);
    tg = new TransformGroup(tr);
    ElevationGrid grass1 = new ElevationGrid(2, // X dimension
            2, // Z dimension
            LawnWidth, // X spacing
            LawnDepth, // Z spacing
            grassApp); // appearance
    tg.addChild(grass1);
    addChild(tg);

    //  Right grass
    trans.set(LawnWidth / 2.0f + WalkwayWidth / 2.0f, -1.6f, 0.0f);
    tr.set(trans);
    tg = new TransformGroup(tr);
    ElevationGrid grass2 = new ElevationGrid(2, // X dimension
            2, // Z dimension
            LawnWidth, // X spacing
            LawnDepth, // Z spacing
            grassApp); // appearance
    tg.addChild(grass2);
    addChild(tg);

    //  Walkway
    trans.set(0.0f, -1.6f, 0.0f);
    tr.set(trans);
    tg = new TransformGroup(tr);
    ElevationGrid walk = new ElevationGrid(2, // X dimension
            2, // Z dimension
            WalkwayWidth, // X spacing
            WalkwayDepth, // Z spacing
            walkApp); // appearance
    tg.addChild(walk);
    addChild(tg);

    //
    // Build several columns on the floor
    //
    SharedGroup column = buildSharedColumn();
    Group columns = buildColumns(column);
    addChild(columns);
}

From source file:TickTockPicking.java

public Cube() {
    super();//  w w w. j a v a 2 s.com

    int i;

    QuadArray cube = new QuadArray(24, QuadArray.COORDINATES | QuadArray.NORMALS);

    cube.setCoordinates(0, verts);
    for (i = 0; i < 24; i++) {
        cube.setNormal(i, normals[i / 4]);
    }

    cube.setCapability(Geometry.ALLOW_INTERSECT);
    setGeometry(cube);
    setAppearance(new Appearance());
}

From source file:KeyNavigateTest.java

void createBookcase(Group mapGroup, int nPixelX, int nPixelY) {
    Point3d point = convertToWorldCoordinatesPixelCenter(nPixelX, nPixelY);

    if (m_BookcaseAppearance == null)
        m_BookcaseAppearance = new Appearance();

    Vector3d squareSize = getMapSquareSize();

    Cuboid bookcase = new Cuboid(this, mapGroup, ComplexObject.GEOMETRY | ComplexObject.TEXTURE);
    bookcase.createObject(m_BookcaseAppearance, new Vector3d(point.x, m_kFloorLevel, point.z),
            new Vector3d(squareSize.x / 2, m_kCeilingHeight / 2.7, squareSize.z / 2), "bookcase.gif", null,
            null);/*from   ww w  .j  a v  a 2 s .co m*/

}

From source file:LightTest.java

public void synchLightToUi() {
    super.synchLightToUi();

    // set some defaults if things go wrong...
    double x = 0;
    double y = 0;
    double z = 0;

    double constant = 0.01;
    double linear = 0;
    double quadratic = 0;

    try {//from w w w . j a va2  s  . co m
        x = Double.valueOf(m_XPositionTextField.getText()).doubleValue();
        y = Double.valueOf(m_YPositionTextField.getText()).doubleValue();
        z = Double.valueOf(m_ZPositionTextField.getText()).doubleValue();

        constant = Double.valueOf(m_ConstantAttenuationTextField.getText()).doubleValue();
        linear = Double.valueOf(m_LinearAttenuationTextField.getText()).doubleValue();
        quadratic = Double.valueOf(m_QuadraticAttenuationTextField.getText()).doubleValue();
    } catch (java.lang.NumberFormatException e) {
        // invalid numeric input - just ignore.
    }

    ((PointLight) m_Light).setPosition((float) x, (float) y, (float) z);
    ((PointLight) m_Light).setAttenuation((float) constant, (float) linear, (float) quadratic);

    if (m_TransformGroup != null) {
        Transform3D t3d = new Transform3D();
        m_TransformGroup.getTransform(t3d);
        t3d.setTranslation(new Vector3d(x, y, z));
        m_TransformGroup.setTransform(t3d);
    }

    if (m_Sphere != null) {
        Appearance app = new Appearance();

        Color3f objColor = new Color3f();
        m_Light.getColor(objColor);
        Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
        app.setMaterial(new Material(objColor, black, objColor, black, 80.0f));
        m_Sphere.getShape(Sphere.BODY).setAppearance(app);
    }
}

From source file:TickTockPicking.java

public PickHighlightBehavior(Canvas3D canvas, BranchGroup root, Bounds bounds) {
    super(canvas, root, bounds);
    this.setSchedulingBounds(bounds);
    root.addChild(this);
    Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
    Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
    Color3f highlightColor = new Color3f(0.0f, 1.0f, 0.0f);
    Material highlightMaterial = new Material(highlightColor, black, highlightColor, white, 80.0f);
    highlightAppearance = new Appearance();
    highlightAppearance.setMaterial(new Material(highlightColor, black, highlightColor, white, 80.0f));

    pickCanvas.setMode(PickTool.BOUNDS);
}

From source file:LightTest.java

public Group createGeometry() {
    m_DirectionTransformGroup = new TransformGroup();
    m_DirectionTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    m_DirectionTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

    // create appearance and material for the Cone
    Appearance app = new Appearance();

    // create the Primitive and add to the parent BranchGroup
    m_Cone = new Cone(0.5f, 2, Primitive.ENABLE_APPEARANCE_MODIFY | Primitive.GENERATE_NORMALS, app);
    m_DirectionTransformGroup.addChild(m_Cone);

    Group superGroup = super.createGeometry();
    superGroup.addChild(m_DirectionTransformGroup);
    return superGroup;
}

From source file:ViewProj.java

public BranchGroup createProjViewSG() {
    // Create the root of the branch graph
    BranchGroup objRoot = new BranchGroup();
    objRoot.setCapability(BranchGroup.ALLOW_DETACH);

    // setup a transform group to hold the scaled scene
    TransformGroup objTrans = new TransformGroup();
    Transform3D scale = new Transform3D();
    scale.set(0.9);//  ww  w .j  a  va  2  s  .  c  o m
    objTrans.setTransform(scale);
    objRoot.addChild(objTrans);

    // create the clip limits line
    Point3f[] cpPoints = new Point3f[5];
    cpPoints[0] = new Point3f(-1, -1, 0.1f);
    cpPoints[1] = new Point3f(1, -1, 0.1f);
    cpPoints[2] = new Point3f(1, 1, 0.1f);
    cpPoints[3] = new Point3f(-1, 1, 0.1f);
    cpPoints[4] = cpPoints[0];
    int[] cpLength = new int[1];
    cpLength[0] = 5;
    LineStripArray cpLines = new LineStripArray(5, LineArray.COORDINATES, cpLength);
    cpLines.setCoordinates(0, cpPoints);
    Appearance cpApp = new Appearance();
    ColoringAttributes cpCa = new ColoringAttributes(blue, ColoringAttributes.SHADE_FLAT);
    cpApp.setColoringAttributes(cpCa);
    LineAttributes cpLa = new LineAttributes();
    Shape3D cpShape = new Shape3D(cpLines, cpApp);
    objTrans.addChild(cpShape);

    // transform and render the clip grid points
    updateProjTrans();

    if (numClipGridPts > 0) {
        // transform the clipGridPts
        for (int i = 0; i < numClipGridPts; i++) {
            projectPoint(clipGridPtsVW[i], clipGridPtsProj[i]);
        }

        LineArray clipLn = new LineArray(numClipGridPts, LineArray.COORDINATES);
        clipLn.setCoordinates(0, clipGridPtsProj, 0, numClipGridPts);
        Appearance clipGridApp = new Appearance();
        ColoringAttributes clipCa = new ColoringAttributes(black, ColoringAttributes.SHADE_FLAT);
        clipGridApp.setColoringAttributes(clipCa);
        LineAttributes clipLa = new LineAttributes();
        Shape3D clipShape = new Shape3D(clipLn, clipGridApp);
        objTrans.addChild(clipShape);
    }

    // set up the circle
    Appearance circleApp = new Appearance();
    ColoringAttributes circleCa = new ColoringAttributes();
    circleCa.setColor(red);
    circleApp.setColoringAttributes(circleCa);
    PolygonAttributes pa = new PolygonAttributes();
    pa.setCullFace(PolygonAttributes.CULL_NONE);
    circleApp.setPolygonAttributes(pa);

    // transform the circlePts
    for (int i = 0; i < numCirclePts; i++) {
        projectPoint(circlePtsVW[i], circlePtsProj[i]);
    }

    int[] lineStripLength = new int[1];
    lineStripLength[0] = numCirclePts;
    //LineStripArray circleLineStrip = new LineStripArray(numCirclePts,
    //        LineArray.COORDINATES, lineStripLength);
    TriangleFanArray circleLineStrip = new TriangleFanArray(numCirclePts, LineArray.COORDINATES,
            lineStripLength);
    circleLineStrip.setCoordinates(0, circlePtsProj);
    Shape3D circleShape = new Shape3D(circleLineStrip, circleApp);
    objTrans.addChild(circleShape);

    return objRoot;
}

From source file:GearTest.java

public BranchGroup createGearBox(int toothCount) {
    Transform3D tempTransform = new Transform3D();

    // Create the root of the branch graph
    BranchGroup branchRoot = createBranchEnvironment();

    // Create a Transformgroup to scale all objects so they
    // appear in the scene.
    TransformGroup objScale = new TransformGroup();
    Transform3D t3d = new Transform3D();
    t3d.setScale(0.4);//from w  w w .j a v  a 2s. c om
    objScale.setTransform(t3d);
    branchRoot.addChild(objScale);

    // Create an Appearance.
    Appearance look = new Appearance();
    Color3f objColor = new Color3f(0.5f, 0.5f, 0.6f);
    Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
    Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
    look.setMaterial(new Material(objColor, black, objColor, white, 100.0f));

    // Create the transform group node and initialize it to the
    // identity. Enable the TRANSFORM_WRITE capability so that
    // our behavior code can modify it at runtime. Add it to the
    // root of the subgraph.
    TransformGroup gearboxTrans = new TransformGroup();
    gearboxTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    gearboxTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    objScale.addChild(gearboxTrans);

    // Create a bounds for the mouse behavior methods
    BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);

    // Define the shaft base information
    int shaftCount = 4;
    int secondsPerRevolution = 8000;

    // Create the Shaft(s)
    Shaft shafts[] = new Shaft[shaftCount];
    TransformGroup shaftTGs[] = new TransformGroup[shaftCount];
    Alpha shaftAlphas[] = new Alpha[shaftCount];
    RotationInterpolator shaftRotors[] = new RotationInterpolator[shaftCount];
    Transform3D shaftAxis[] = new Transform3D[shaftCount];

    // Note: the following arrays we're incorporated to make changing
    // the gearbox easier.
    float shaftRatios[] = new float[shaftCount];
    shaftRatios[0] = 1.0f;
    shaftRatios[1] = 0.5f;
    shaftRatios[2] = 0.75f;
    shaftRatios[3] = 5.0f;

    float shaftRadius[] = new float[shaftCount];
    shaftRadius[0] = 0.2f;
    shaftRadius[1] = 0.2f;
    shaftRadius[2] = 0.2f;
    shaftRadius[3] = 0.2f;

    float shaftLength[] = new float[shaftCount];
    shaftLength[0] = 1.8f;
    shaftLength[1] = 0.8f;
    shaftLength[2] = 0.8f;
    shaftLength[3] = 0.8f;

    float shaftDirection[] = new float[shaftCount];
    shaftDirection[0] = 1.0f;
    shaftDirection[1] = -1.0f;
    shaftDirection[2] = 1.0f;
    shaftDirection[3] = -1.0f;

    Vector3d shaftPlacement[] = new Vector3d[shaftCount];
    shaftPlacement[0] = new Vector3d(-0.75, -0.9, 0.0);
    shaftPlacement[1] = new Vector3d(0.75, -0.9, 0.0);
    shaftPlacement[2] = new Vector3d(0.75, 0.35, 0.0);
    shaftPlacement[3] = new Vector3d(-0.75, 0.60, -0.7);

    // Create the shafts.
    for (int i = 0; i < shaftCount; i++) {
        shafts[i] = new Shaft(shaftRadius[i], shaftLength[i], 25, look);
    }

    // Create a transform group node for placing each shaft
    for (int i = 0; i < shaftCount; i++) {
        shaftTGs[i] = new TransformGroup();
        gearboxTrans.addChild(shaftTGs[i]);
        shaftTGs[i].getTransform(tempTransform);
        tempTransform.setTranslation(shaftPlacement[i]);
        shaftTGs[i].setTransform(tempTransform);
        shaftTGs[i].addChild(shafts[i]);
    }

    // Add rotation interpolators to rotate the shaft in the appropriate
    // direction and at the appropriate rate
    for (int i = 0; i < shaftCount; i++) {
        shaftAlphas[i] = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,
                (long) (secondsPerRevolution * shaftRatios[i]), 0, 0, 0, 0, 0);
        shaftAxis[i] = new Transform3D();
        shaftAxis[i].rotX(Math.PI / 2.0);
        shaftRotors[i] = new RotationInterpolator(shaftAlphas[i], shafts[i], shaftAxis[i], 0.0f,
                shaftDirection[i] * (float) Math.PI * 2.0f);
        shaftRotors[i].setSchedulingBounds(bounds);
        shaftTGs[i].addChild(shaftRotors[i]);
    }

    // Define the gear base information. Again, these arrays exist to
    // make the process of changing the GearBox via an editor faster
    int gearCount = 5;
    float valleyToCircularPitchRatio = .15f;
    float pitchCircleRadius = 1.0f;
    float addendum = 0.05f;
    float dedendum = 0.05f;
    float gearThickness = 0.3f;
    float toothTipThickness = 0.27f;

    // Create an array of gears and their associated information
    SpurGear gears[] = new SpurGear[gearCount];
    TransformGroup gearTGs[] = new TransformGroup[gearCount];

    int gearShaft[] = new int[gearCount];
    gearShaft[0] = 0;
    gearShaft[1] = 1;
    gearShaft[2] = 2;
    gearShaft[3] = 0;
    gearShaft[4] = 3;

    float ratio[] = new float[gearCount];
    ratio[0] = 1.0f;
    ratio[1] = 0.5f;
    ratio[2] = 0.75f;
    ratio[3] = 0.25f;
    ratio[4] = 1.25f;

    Vector3d placement[] = new Vector3d[gearCount];
    placement[0] = new Vector3d(0.0, 0.0, 0.0);
    placement[1] = new Vector3d(0.0, 0.0, 0.0);
    placement[2] = new Vector3d(0.0, 0.0, 0.0);
    placement[3] = new Vector3d(0.0, 0.0, -0.7);
    placement[4] = new Vector3d(0.0, 0.0, 0.0);

    // Create the gears.
    for (int i = 0; i < gearCount; i++) {
        gears[i] = new SpurGearThinBody(((int) ((float) toothCount * ratio[i])), pitchCircleRadius * ratio[i],
                shaftRadius[0], addendum, dedendum, gearThickness, toothTipThickness,
                valleyToCircularPitchRatio, look);
    }

    // Create a transform group node for arranging the gears on a shaft
    // and attach the gear to its associated shaft
    for (int i = 0; i < gearCount; i++) {
        gearTGs[i] = new TransformGroup();
        gearTGs[i].getTransform(tempTransform);
        tempTransform
                .rotZ((shaftDirection[gearShaft[i]] == -1.0) ? gears[i].getCircularPitchAngle() / -2.0f : 0.0f);
        tempTransform.setTranslation(placement[i]);
        gearTGs[i].setTransform(tempTransform);
        gearTGs[i].addChild(gears[i]);
        shafts[gearShaft[i]].addChild(gearTGs[i]);
    }

    // Have Java 3D perform optimizations on this scene graph.
    branchRoot.compile();

    return branchRoot;
}

From source file:LightTest.java

public void synchLightToUi() {
    super.synchLightToUi();

    // set some defaults if things go wrong...
    double x = 0;
    double y = 0;
    double z = 0;

    double conc = 1;
    double spread = 2;

    try {//w  ww.  j  av a  2  s.  co  m
        x = Double.valueOf(m_XDirectionTextField.getText()).doubleValue();
        y = Double.valueOf(m_YDirectionTextField.getText()).doubleValue();
        z = Double.valueOf(m_ZDirectionTextField.getText()).doubleValue();

        conc = Double.valueOf(m_ConcentrationTextField.getText()).doubleValue();
        spread = Double.valueOf(m_SpreadAngleTextField.getText()).doubleValue();
    } catch (java.lang.NumberFormatException e) {
        // invalid numeric input - just ignore.
    }

    ((SpotLight) m_Light).setDirection((float) x, (float) y, (float) z);
    ((SpotLight) m_Light).setConcentration((float) conc);
    ((SpotLight) m_Light).setSpreadAngle((float) spread);

    if (m_DirectionTransformGroup != null) {
        Vector3d coneVector = new Vector3d(0, -1, 0);
        Vector3d lightVector = new Vector3d(x, y, z);

        coneVector.normalize();
        lightVector.normalize();

        Vector3d axisVector = new Vector3d();
        axisVector.cross(coneVector, lightVector);
        double angle = java.lang.Math.acos(coneVector.dot(lightVector));

        AxisAngle4d rotAxis = new AxisAngle4d(axisVector.x, axisVector.y, axisVector.z, angle);

        Transform3D t3d = new Transform3D();
        t3d.setRotation(rotAxis);

        m_DirectionTransformGroup.setTransform(t3d);
    }

    if (m_Cone != null) {
        Appearance app = new Appearance();

        Color3f objColor = new Color3f();
        m_Light.getColor(objColor);
        Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
        app.setMaterial(new Material(objColor, black, objColor, black, 80.0f));
        m_Cone.getShape(Cone.CAP).setAppearance(app);
    }
}

From source file:ExSpotLight.java

public AnnotationArrow(float x, float y, float z, float x2, float y2, float z2) {
    super(x, y, z, x2, y2, z2);
    setLineWidth(lineWidth);//from ww w .j a  v  a 2  s. c  om

    // Compute the length and direction of the line
    float deltaX = x2 - x;
    float deltaY = y2 - y;
    float deltaZ = z2 - z;

    float theta = -(float) Math.atan2(deltaZ, deltaX);
    float phi = (float) Math.atan2(deltaY, deltaX);
    if (deltaX < 0.0f) {
        phi = (float) Math.PI - phi;
    }

    // Compute a matrix to rotate a cone to point in the line's
    // direction, then place the cone at the line's endpoint.
    Matrix4f mat = new Matrix4f();
    Matrix4f mat2 = new Matrix4f();
    mat.setIdentity();

    // Move to the endpoint of the line
    mat2.setIdentity();
    mat2.setTranslation(new Vector3f(x2, y2, z2));
    mat.mul(mat2);

    // Spin around Y
    mat2.setIdentity();
    mat2.rotY(theta);
    mat.mul(mat2);

    // Tilt up or down around Z
    mat2.setIdentity();
    mat2.rotZ(phi);
    mat.mul(mat2);

    // Tilt cone to point right
    mat2.setIdentity();
    mat2.rotZ(-1.571f);
    mat.mul(mat2);

    arrowTrans = new TransformGroup();
    arrowTrans.setCapability(Group.ALLOW_CHILDREN_WRITE);
    Transform3D trans = new Transform3D(mat);
    arrowTrans.setTransform(trans);

    // Create an appearance
    arrowAppearance = new Appearance();
    arrowAppearance.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);

    getLineColor(arrowColor);
    coloringAttributes = new ColoringAttributes();
    coloringAttributes.setColor(arrowColor);
    coloringAttributes.setShadeModel(ColoringAttributes.SHADE_FLAT);
    arrowAppearance.setColoringAttributes(coloringAttributes);

    // Build a cone for the arrow head
    arrowHead = new Cone(arrowRadius, // base radius
            arrowLength, // height
            0, // don't generate normals
            radialDivisions, // divisions radially
            sideDivisions, // divisions vertically
            arrowAppearance); // appearance

    arrowTrans.addChild(arrowHead);
    addChild(arrowTrans);
}