java left logo
java middle logo
java right logo
 

Home arrow Other API Tips arrow Java3D arrow How to use point lights in Java3D
 
 
Main Menu
Home
Java Tutorials
Book Reviews
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Sitemap
Java Network
Java Forums
Java Tips Blog




Most Visited Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews
Top Rated Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews


Statistics
Registered Users: 769
Java SE Tips: 614
Java ME Tips: 201
Java EE Tips: 184
Other API Tips: 779
Java Applications: 298
Java Libraries: 209
Java Games: 16
Book Reviews:
 
 
 
How to use point lights in Java3D E-mail
User Rating: / 0
PoorBest 

This Java tip illustrates the use of point lights in Java 3D scenes.


Image

import java.applet.Applet;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.CheckboxMenuItem;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Frame;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.util.Enumeration;
import java.util.EventListener;

import javax.media.j3d.Appearance;
import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.Group;
import javax.media.j3d.Light;
import javax.media.j3d.LineArray;
import javax.media.j3d.LineAttributes;
import javax.media.j3d.Material;
import javax.media.j3d.PointLight;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnAWTEvent;
import javax.media.j3d.WakeupOnElapsedFrames;
import javax.media.j3d.WakeupOr;
import javax.vecmath.Color3f;
import javax.vecmath.Matrix4d;
import javax.vecmath.Matrix4f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.geometry.Cone;
import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.universe.PlatformGeometry;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.universe.Viewer;
import com.sun.j3d.utils.universe.ViewingPlatform;

public class ExPointLight extends Java3DFrame {
  //--------------------------------------------------------------
  //  SCENE CONTENT
  //--------------------------------------------------------------

  //
  //  Nodes (updated via menu)
  //
  private PointLight light = null;

  //
  //  Build scene
  //
  public Group buildScene() {
    // Get the current color, position, and attenuation
    Color3f color = (Color3fcolors[currentColor].value;
    Point3f pos = (Point3fpositions[currentPosition].value;
    Point3f atten = (Point3fattenuations[currentAttenuation].value;

    // Turn off the example headlight
    setHeadlightEnable(false);

    // Build the scene root
    Group scene = new Group();

    // BEGIN EXAMPLE TOPIC
    // Create influencing bounds
    BoundingSphere worldBounds = new BoundingSphere(new Point3d(0.00.0,
        0.0)// Center
        1000.0)// Extent

    // Set the light color and its influencing bounds
    light = new PointLight();
    light.setEnable(lightOnOff);
    light.setColor(color);
    light.setPosition(pos);
    light.setAttenuation(atten);
    light.setCapability(PointLight.ALLOW_STATE_WRITE);
    light.setCapability(PointLight.ALLOW_COLOR_WRITE);
    light.setCapability(PointLight.ALLOW_POSITION_WRITE);
    light.setCapability(PointLight.ALLOW_ATTENUATION_WRITE);
    light.setInfluencingBounds(worldBounds);
    scene.addChild(light);
    // END EXAMPLE TOPIC

    // Build foreground geometry
    scene.addChild(new SphereGroup());

    // Add arrows in a fan to show light ray directions
    scene.addChild(buildArrows());

    return scene;
  }

  //--------------------------------------------------------------
  //  FOREGROUND AND ANNOTATION CONTENT
  //--------------------------------------------------------------

  //
  //  Create a fan of annotation arrows aiming in all directions,
  //  but in the XY plane. Next, build an array of Transform3D's,
  //  one for each of the light positions shown on the positions
  //  menu. Save these Transform3Ds and a top-level TransformGroup
  //  surrounding the arrows. Later, when the user selects a new
  //  light position, we poke the corresponding Transform3D into
  //  the TransformGroup to cause the arrows to move to a new
  //  position.
  //
  private Transform3D[] arrowPositionTransforms = null;

  private TransformGroup arrowPositionTransformGroup = null;

  private Group buildArrows() {
    // Create a transform group surrounding the arrows.
    // Enable writing of its transform.
    arrowPositionTransformGroup = new TransformGroup();
    arrowPositionTransformGroup
        .setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

    // Create a group of arrows in a fan and add that group
    // to the transform group.
    AnnotationArrowFan af = new AnnotationArrowFan(0.0f0.0f0.0f// center
        // position
        2.5f// arrow length
        0.0f// start angle
        (float) (Math.PI * 2.0 7.0 8.0),// end angle
        8)// number of arrows
    arrowPositionTransformGroup.addChild(af);

    // Create a set of Transform3Ds for the different
    // arrow positions.
    arrowPositionTransforms = new Transform3D[positions.length];
    Point3f pos;
    Vector3f v = new Vector3f();
    for (int i = 0; i < positions.length; i++) {
      // Create a Transform3D, setting its translation.
      arrowPositionTransforms[inew Transform3D();
      pos = (Point3fpositions[i].value;
      v.set(pos);
      arrowPositionTransforms[i].setTranslation(v);
    }

    // Set the initial transform to be the current position
    arrowPositionTransformGroup
        .setTransform(arrowPositionTransforms[currentPosition]);

    return arrowPositionTransformGroup;
  }

  //--------------------------------------------------------------
  //  USER INTERFACE
  //--------------------------------------------------------------

  //
  //  Main
  //
  public static void main(String[] args) {
    ExPointLight ex = new ExPointLight();
    ex.initialize(args);
    ex.buildUniverse();
    ex.showFrame();
  }

  //  On/off choices
  private boolean lightOnOff = true;

  private CheckboxMenuItem lightOnOffMenu;

  //  Color menu choices
  private NameValue[] colors = new NameValue("White", White),
      new NameValue("Gray", Gray)new NameValue("Black", Black),
      new NameValue("Red", Red)new NameValue("Yellow", Yellow),
      new NameValue("Green", Green)new NameValue("Cyan", Cyan),
      new NameValue("Blue", Blue)new NameValue("Magenta", Magenta)};

  private int currentColor = 0;

  private CheckboxMenu colorMenu = null;

  //  Position menu choices
  private NameValue[] positions = new NameValue("Origin", Origin),
      new NameValue("+X", PlusX)new NameValue("-X", MinusX),
      new NameValue("+Y", PlusY)new NameValue("-Y", MinusY),
      new NameValue("+Z", PlusZ)new NameValue("-Z", MinusZ)};

  private int currentPosition = 0;

  private CheckboxMenu positionMenu = null;

  //  Attenuation menu choices
  private NameValue[] attenuations = {
      new NameValue("Constant"new Point3f(1.0f0.0f0.0f)),
      new NameValue("Linear"new Point3f(0.0f1.0f0.0f)),
      new NameValue("Quadratic"new Point3f(0.0f0.0f1.0f))};

  private int currentAttenuation = 0;

  private CheckboxMenu attenuationMenu = null;

  //
  //  Initialize the GUI (application and applet)
  //
  public void initialize(String[] args) {
    // Initialize the window, menubar, etc.
    super.initialize(args);
    exampleFrame.setTitle("Java 3D Point Light Example");

    //
    //  Add a menubar menu to change node parameters
    //    Light on/off
    //    Color -->
    //    Position -->
    //    Attenuation -->
    //

    Menu m = new Menu("PointLight");

    lightOnOffMenu = new CheckboxMenuItem("Light on/off", lightOnOff);
    lightOnOffMenu.addItemListener(this);
    m.add(lightOnOffMenu);

    colorMenu = new CheckboxMenu("Color", colors, currentColor, this);
    m.add(colorMenu);

    positionMenu = new CheckboxMenu("Position", positions, currentPosition,
        this);
    m.add(positionMenu);

    attenuationMenu = new CheckboxMenu("Attenuation", attenuations,
        currentAttenuation, this);
    m.add(attenuationMenu);

    exampleMenuBar.add(m);
  }

  //
  //  Handle checkboxes and menu choices
  //
  public void checkboxChanged(CheckboxMenu menu, int check) {
    if (menu == colorMenu) {
      // Change the light color
      currentColor = check;
      Color3f color = (Color3fcolors[check].value;
      light.setColor(color);
      return;
    }
    if (menu == positionMenu) {
      // Change the light position
      currentPosition = check;
      Point3f pos = (Point3fpositions[check].value;
      light.setPosition(pos);

      // Change the arrow group position
      arrowPositionTransformGroup
          .setTransform(arrowPositionTransforms[check]);
      return;
    }
    if (menu == attenuationMenu) {
      // Change the light attenuation
      currentAttenuation = check;
      Point3f atten = (Point3fattenuations[check].value;
      light.setAttenuation(atten);
      return;
    }

    // Handle all other checkboxes
    super.checkboxChanged(menu, check);
  }

  public void itemStateChanged(ItemEvent event) {
    Object src = event.getSource();
    if (src == lightOnOffMenu) {
      // Turn the light on or off
      lightOnOff = lightOnOffMenu.getState();
      light.setEnable(lightOnOff);
      return;
    }

    // Handle all other checkboxes
    super.itemStateChanged(event);
  }
}

//
//CLASS
//AnnotationArrowFan - A group of arrows in a fan
//
//DESCRIPTION
//This class creates one or more 3D, unlighted arrows arranged in a
//fan around the xyz position. Such arrow fans can be used to indicate
//point light directions, and so forth.
//
//The arrow fan is drawn in the XY plane, pointing right (middle arrow).
//The fan origin, arrow length, start and end angles, and number of
//arrows all may be controlled.
//
//SEE ALSO
//AnnotationArrow
//AnnotationArrowGroup
//
//AUTHOR
//David R. Nadeau / San Diego Supercomputer Center
//
//

class AnnotationArrowFan extends Group {
  // 3D nodes
  AnnotationArrow[] arrows;

  //  Constructors
  public AnnotationArrowFan() {
    //    xyz length start/end angles count
    this(0.0f0.0f0.0f1.0f1.571f, -1.571f5);
  }

  public AnnotationArrowFan(float x, float y, float z, float length,
      float startAngle, float endAngle, int count) {
    arrows = new AnnotationArrow[count];
    float x2, y2;
    float angle = startAngle;
    float deltaAngle = (endAngle - startAngle(float) (count - 1);

    for (int i = 0; i < count; i++) {
      x2 = (float) (length * Math.cos(angle));
      y2 = (float) (length * Math.sin(angle));
      arrows[inew AnnotationArrow(x, y, z, x2, y2, z);
      addChild(arrows[i]);
      angle += deltaAngle;
    }
  }
}

//
//CLASS
//AnnotationArrowGroup - A group of parallel arrows
//
//DESCRIPTION
//This class creates one or more parallel 3D, unlighted arrows.
//Such arrow groups can be used to indicate directional light
//directions, and so forth.
//
//The arrow group is drawn in the XY plane, pointing right.
//The X start and end values, and the Y start and end values
//can be set, along with the count of the number of arrows to
//build.
//
//SEE ALSO
//AnnotationArrow
//AnnotationArrowFan
//
//AUTHOR
//David R. Nadeau / San Diego Supercomputer Center
//
//

class AnnotationArrowGroup extends Group {
  // 3D nodes
  AnnotationArrow[] arrows;

  //  Constructors
  public AnnotationArrowGroup() {
    //    xStart xEnd yStart yEnd count
    this(-1.0f1.0f1.0f, -1.0f3);
  }

  public AnnotationArrowGroup(float xStart, float xEnd, float yStart,
      float yEnd, int count) {
    arrows = new AnnotationArrow[count];
    float y = yStart;
    float deltaY = (yEnd - yStart(float) (count - 1);
    for (int i = 0; i < count; i++) {
      arrows[inew AnnotationArrow(xStart, y, 0.0f, xEnd, y, 0.0f);
      addChild(arrows[i]);
      y += deltaY;
    }
  }
}

//
//CLASS
//AnnotationArrow - 3D arrow used for annotation & diagrams
//
//DESCRIPTION
//This class creates a 3D, unlighted line between two 3D coordinates
//plus a cone-shaped arrow at the line's endpoint. The line's width
//and color can be controlled. The arrow head's width and length
//can be controlled.
//
//SEE ALSO
//AnnotationLine
//AnnotationAxes
//AnnotationArrowFan
//AnnotationArrowGroup
//
//AUTHOR
//David R. Nadeau / San Diego Supercomputer Center
//

class AnnotationArrow extends AnnotationLine {
  // Parameters
  private Color3f arrowColor = new Color3f(1.0f1.0f1.0f);

  private float arrowRadius = 0.1f;

  private float arrowLength = 0.20f;

  private float lineWidth = 3.0f;

  private int radialDivisions = 8;

  private int sideDivisions = 1;

  // 3D Nodes
  private Cone arrowHead = null;

  private Appearance arrowAppearance = null;

  private TransformGroup arrowTrans = null;

  private ColoringAttributes coloringAttributes = null;

  //
  //  Construct a straight line
  //
  public AnnotationArrow(float x2, float y2, float z2) {
    //    origin to given coordinate
    this(0.0f0.0f0.0f, x2, y2, z2);
  }

  public AnnotationArrow(float x, float y, float z, float x2, float y2,
      float z2) {
    super(x, y, z, x2, y2, z2);
    setLineWidth(lineWidth);

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

    float theta = -(floatMath.atan2(deltaZ, deltaX);
    float phi = (floatMath.atan2(deltaY, deltaX);
    if (deltaX < 0.0f) {
      phi = (floatMath.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);
  }

  //
  //  Control the arrow head size
  //
  public void setArrowHeadRadius(float radius) {
    arrowRadius = radius;

    arrowTrans.removeChild(0);
    arrowHead = new Cone(arrowRadius, // base radius
        arrowLength, // height
        0// don't generate normals
        radialDivisions, // divisions radially
        sideDivisions, // divisions vertically
        arrowAppearance)// appearance
    arrowTrans.addChild(arrowHead);
  }

  public void setArrowHeadLength(float length) {
    arrowLength = length;

    arrowTrans.removeChild(0);
    arrowHead = new Cone(arrowRadius, // base radius
        arrowLength, // height
        0// don't generate normals
        radialDivisions, // divisions radially
        sideDivisions, // divisions vertically
        arrowAppearance)// appearance
    arrowTrans.addChild(arrowHead);
  }

  public float getArrowHeadRadius() {
    return arrowRadius;
  }

  public float getArrowHeadLength() {
    return arrowLength;
  }

  //
  //  Control the line color
  //
  public void setLineColor(Color3f color) {
    super.setLineColor(color);

    getLineColor(arrowColor);
    coloringAttributes.setColor(arrowColor);
    arrowAppearance.setColoringAttributes(coloringAttributes);
    arrowHead.setAppearance(arrowAppearance);
  }

  public void setLineColor(float r, float g, float b) {
    super.setLineColor(r, g, b);

    getLineColor(arrowColor);
    coloringAttributes.setColor(arrowColor);
    arrowAppearance.setColoringAttributes(coloringAttributes);
    arrowHead.setAppearance(arrowAppearance);
  }

  public void setLineColor(float[] color) {
    super.setLineColor(color);

    getLineColor(arrowColor);
    coloringAttributes.setColor(arrowColor);
    arrowAppearance.setColoringAttributes(coloringAttributes);
    arrowHead.setAppearance(arrowAppearance);
  }

  //
  //  Control the appearance
  //
  public void setAppearance(Appearance app) {
    super.setAppearance(app);

    arrowAppearance = app;
    arrowAppearance
        .setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);
    arrowAppearance.setColoringAttributes(coloringAttributes);
    arrowHead.setAppearance(arrowAppearance);
  }

  //
  //  Provide info on the shape and geometry
  //
  public Shape3D getShape(int partid) {
    if (partid == Cone.BODY)
      return arrowHead.getShape(Cone.BODY);
    else if (partid == Cone.CAP)
      return arrowHead.getShape(Cone.CAP);
    else
      return super.getShape(partid);
  }

  public int getNumTriangles() {
    return arrowHead.getNumTriangles();
  }

  public int getNumVertices() {
    return arrowHead.getNumVertices() super.getNumVertices();
  }
}

//
//CLASS
//AnnotationLine - 3D line used for annotation & diagrams
//
//DESCRIPTION
//This class creates a 3D, unlighted line between two 3D coordinates.
//The line's width and color can be controlled.
//
//SEE ALSO
//AnnotationArrow
//
//AUTHOR
//David R. Nadeau / San Diego Supercomputer Center
//
//

class AnnotationLine extends Primitive {
  // Parameters
  private float lineWidth = 1;

  private Color3f lineColor = new Color3f(1.0f1.0f1.0f);

  // 3D nodes
  private Shape3D shape = null;

  private LineAttributes lineAttributes = null;

  private ColoringAttributes coloringAttributes = null;

  private LineArray line = null;

  protected Appearance mainAppearance = null;

  //
  //  Construct a straight line
  //
  public AnnotationLine(float x2, float y2, float z2) {
    //    origin to given coordinate
    this(0.0f0.0f0.0f, x2, y2, z2);
  }

  public AnnotationLine(float x, float y, float z, float x2, float y2,
      float z2) {
    float[] coord = new float[3];
    float[] texcoord = new float[2];

    // Build a shape
    shape = new Shape3D();
    shape.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);

    // Create geometry for a 2-vertex straight line
    line = new LineArray(2, GeometryArray.COORDINATES
        | GeometryArray.TEXTURE_COORDINATE_2);
    line.setCapability(GeometryArray.ALLOW_COLOR_WRITE);

    // Starting point
    coord[0= x;
    coord[1= y;
    coord[2= z;
    texcoord[00.0f;
&