next up previous
Next: 6.10 TickTockCollision Up: 6 Java3Dのプログラミング Previous: 6.8 Background

6.9 Billboard

Mouseで環境を軸あるいは点を中心に 回転することができる例である.
/java/jdk1.4/demo/java3d/Billboard> wc *.java
    236     849    8665 Bboard.java
    250     921    9386 BboardPt.java
    180     662    5440 MouseRotateY.java
    666    2432   23491 total
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import com.sun.j3d.utils.image.TextureLoader;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.mouse.*;

public class Bboard extends Applet {
  private String fontName = "TestFont";
  private String textString = "Billboard";
  float sl = textString.length();
  public BranchGroup createSceneGraph() {
    BranchGroup objRoot = new BranchGroup();
    TransformGroup objScale = new TransformGroup();
    Transform3D textMat = new Transform3D();
    textMat.setScale(1.2/sl);
    objScale.setTransform(textMat);
    TransformGroup objTrans = new TransformGroup();
    objTrans.setCapability(
      TransformGroup.ALLOW_TRANSFORM_WRITE);
    objTrans.setCapability(
      TransformGroup.ALLOW_TRANSFORM_READ);
    objRoot.addChild(objTrans);
    BoundingSphere bounds =
      new BoundingSphere(
        new Point3d(0.0,0.0,0.0), 100.0);
    Appearance apText = new Appearance();
    Material m = new Material();
    m.setLightingEnable(true);
    apText.setMaterial(m);
    Appearance apEarth= new Appearance();
    Material mm = new Material();
    mm.setLightingEnable(true);
    apEarth.setMaterial(mm);
    Appearance apStone = new Appearance();
    apStone.setMaterial(mm);
    Font3D f3d = new Font3D(
      new Font(fontName, Font.PLAIN, 2),
      new FontExtrusion());
    Text3D txt = new Text3D(
      f3d, textString, 
      new Point3f( -sl/2.0f, 3.0f, 0.0f));
    Shape3D textShape = new Shape3D();
    textShape.setGeometry(txt);
    textShape.setAppearance(apText);
    TransformGroup bbTransY =
      new TransformGroup();
    bbTransY.setCapability(
      TransformGroup.ALLOW_TRANSFORM_WRITE);
    bbTransY.setCapability(
      TransformGroup.ALLOW_TRANSFORM_READ);
    Billboard bboardY = new Billboard( bbTransY );
    objTrans.addChild( bboardY );
    bboardY.setSchedulingBounds( bounds );
    bboardY.setAlignmentAxis( 0.0f, 1.0f, 0.0f);
    objScale.addChild( bbTransY );
    bbTransY.addChild( textShape );

    Transform3D cubeMat = new Transform3D();
    TransformGroup cubeTrans =
      new TransformGroup(cubeMat);
    cubeMat.set(new Vector3d(0.9, 0.0, -1.0));
    cubeTrans.setTransform(cubeMat);
    cubeTrans.addChild(new ColorCube(0.3));
    objTrans.addChild(cubeTrans);

    TextureLoader stoneTex =
      new TextureLoader(
        new String("../images/stone.jpg"),
        new String("RGB"), this);
    if (stoneTex != null)
      apStone.setTexture(stoneTex.getTexture());

    TextureAttributes texAttr =
      new TextureAttributes();
    texAttr.setTextureMode(
      TextureAttributes.MODULATE);
    apStone.setTextureAttributes(texAttr);
    Transform3D coneMat = new Transform3D();
    TransformGroup coneTrans =
      new TransformGroup(coneMat);
    coneMat.set(new Vector3d(0.0, 0.0, 0.0));
    coneTrans.setTransform(coneMat);
    coneTrans.addChild(
      new Cone(.2f, 0.8f,
               Cone.GENERATE_NORMALS |
               Cone.GENERATE_TEXTURE_COORDS,
               apStone));
    objTrans.addChild(coneTrans);
    
    TextureLoader earthTex =
      new TextureLoader(
        new String("../images/earth.jpg"),
        new String("RGB"), this);
    if (earthTex != null)
      apEarth.setTexture(earthTex.getTexture());

    apEarth.setTextureAttributes(texAttr);

    Transform3D cylinderMat = new Transform3D();
    TransformGroup cylinderTrans =
      new TransformGroup(cylinderMat);
    cylinderMat.set(new Vector3d(-0.9, 0.5, -1.0));
    cylinderTrans.setTransform(cylinderMat);
    cylinderTrans.addChild(
      new Cylinder(.35f, 2.0f,
                   Cylinder.GENERATE_NORMALS |
                   Cylinder.GENERATE_TEXTURE_COORDS,
                   apEarth));
    objTrans.addChild(cylinderTrans);
    objTrans.addChild(objScale);
    Color3f bgColor =
      new Color3f(0.05f, 0.05f, 0.5f);
    Background bgNode = new Background(bgColor);
    bgNode.setApplicationBounds(bounds);
    objRoot.addChild(bgNode);

    Color3f ambientColor =
      new Color3f(0.1f, 0.1f, 0.1f);
    AmbientLight ambientLightNode =
      new AmbientLight(ambientColor);
    ambientLightNode.setInfluencingBounds(bounds);
    objRoot.addChild(ambientLightNode);
    Color3f light1Color =
      new Color3f(1.0f, 1.0f, 0.9f);
    Vector3f light1Direction  =
      new Vector3f(4.0f, -7.0f, -12.0f);
    Color3f light2Color =
      new Color3f(0.3f, 0.3f, 0.4f);
    Vector3f light2Direction  =
      new Vector3f(-6.0f, -2.0f, -1.0f);
    DirectionalLight light1
      = new DirectionalLight(light1Color,
                             light1Direction);
    light1.setInfluencingBounds(bounds);
    objRoot.addChild(light1);
    DirectionalLight light2
      = new DirectionalLight(light2Color,
                             light2Direction);
    light2.setInfluencingBounds(bounds);
    objRoot.addChild(light2);
    apText.setMaterial(mm);
    MouseRotateY behavior =
      new MouseRotateY();
    behavior.setTransformGroup(objTrans);
    objTrans.addChild(behavior);
    behavior.setSchedulingBounds(bounds);
    MouseZoom behavior2 = new MouseZoom();
    behavior2.setTransformGroup(objTrans);
    objTrans.addChild(behavior2);
    behavior2.setSchedulingBounds(bounds);
    MouseTranslate behavior3 =
      new MouseTranslate();
    behavior3.setTransformGroup(objTrans);
    objTrans.addChild(behavior3);
    behavior3.setSchedulingBounds(bounds);
    objRoot.compile();
    return objRoot;
  }
  public Bboard() {
    setLayout(new BorderLayout());
    GraphicsConfiguration config =
      SimpleUniverse.getPreferredConfiguration();
    Canvas3D c = new Canvas3D(config);
    add("Center", c);
    BranchGroup scene = createSceneGraph();
    SimpleUniverse u = new SimpleUniverse(c);
    u.getViewingPlatform().setNominalViewingTransform();
    u.addBranchGraph(scene);
  }
  public static void main(String[] args) {
    new MainFrame(new Bboard(), 400, 400);
  }
}
図 15: Billboard
\includegraphics[width=6.0cm]{/home/inaba/eps/lecture/fig/Billboard.eps}
MouseRotateYクラスは以下のようになっている.
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.mouse.*;

public class MouseRotateY
  extends MouseBehavior {
  double  y_angle;
  double  y_factor;
  public MouseRotateY(TransformGroup
                      transformGroup) {
    super(transformGroup);
  }
  public MouseRotateY() {
    super(0);
  }
  public MouseRotateY(int flags) {
    super(flags);
  }
  public void initialize() {
    super.initialize();
    y_angle = 0;
    y_factor = .03;
    if ((flags & INVERT_INPUT) ==
        INVERT_INPUT) {
      invert = true;
      y_factor *= -1;
    }
  }
  public double getYFactor() {
    return y_factor;
  }
  public void setFactor( double factor) {
    y_factor = factor;
  }
  public void
  processStimulus(Enumeration criteria) {
    WakeupCriterion wakeup;
    AWTEvent[] event;
    int id;
    int  dx;
    while (criteria.hasMoreElements()) {
      wakeup =
        (WakeupCriterion) criteria.nextElement();
      if (wakeup instanceof WakeupOnAWTEvent) {
        event =
          ((WakeupOnAWTEvent)wakeup).getAWTEvent();
        for (int i=0; i<event.length; i++) { 
          processMouseEvent((MouseEvent) event[i]);
          if (((buttonPress)&&
               ((flags & MANUAL_WAKEUP) == 0)) ||
              ((wakeUp)&&
               ((flags & MANUAL_WAKEUP) != 0))){
                
            id = event[i].getID();
            if ((id == MouseEvent.MOUSE_DRAGGED) && 
                !((MouseEvent)event[i]).isMetaDown() && 
                !((MouseEvent)event[i]).isAltDown()){
                  
              x = ((MouseEvent)event[i]).getX();

              dx = x - x_last;

              if (!reset){            
                y_angle = dx * y_factor;
                    
                transformY.rotY(y_angle);
                    
                transformGroup.getTransform(currXform);
                    
                Matrix4d mat = new Matrix4d();
                currXform.get(mat);
                    
                currXform.setTranslation(
                  new Vector3d(0.0,0.0,0.0));
                if (invert) {
                  currXform.mul(currXform, transformX);
                  currXform.mul(currXform, transformY);
                } else {
                  currXform.mul(transformX, currXform);
                  currXform.mul(transformY, currXform);
                }
                Vector3d translation = new 
                  Vector3d(mat.m03, mat.m13, mat.m23);
                currXform.setTranslation(translation);
                transformGroup.setTransform(currXform);
              }
              else {
                reset = false;
              }
              x_last = x;
            }
            else if (id ==
                     MouseEvent.MOUSE_PRESSED) {
              x_last =
                ((MouseEvent)event[i]).getX();
            }
          }
        }
      }
    }
    wakeupOn (mouseCriterion);
  }
}


generated through LaTeX2HTML. M.Inaba 平成18年5月7日