チューブを描画

プログラムでチューブ(円筒)の座標を計算します。

Java Applet の実行は、次のリンクをクリックして下さい。
チューブを描画

前田稔の超初心者のプログラム入門

プログラムの作成

  1. メモ帳などでタイプして applet_tube.java の名前で保存して下さい。
    //★ Tube に法線ベクトルを設定する    前田 稔
    import java.applet.Applet;
    import java.awt.*;
    import javax.swing.*;
    import javax.media.j3d.*;
    import javax.vecmath.*;
    import com.sun.j3d.utils.universe.*;
    import com.sun.j3d.utils.applet.MainFrame;
    import com.sun.j3d.utils.behaviors.mouse.*;
    import com.sun.j3d.utils.geometry.*;
    
    public class applet_tube extends Applet
    {   private SimpleUniverse universe = null;
        int     KAKU = 6;       // チューブの角数
        int     VNUM = KAKU+1;  // 頂点座標の数
    
        // main Method
        public static void main(String[] args)
        {   new MainFrame(new applet_tube(), 300, 300);  }
    
        // Constructor
        public applet_tube() {  }
    
        // Applet 初期化
        public void init()
        {   setLayout(new BorderLayout());
    
            // Java3D関係の設定
            GraphicsConfiguration g_config = SimpleUniverse.getPreferredConfiguration();
            Canvas3D canvas = new Canvas3D(g_config);
            add(canvas);
    
            // SimpleUniverseを生成
            universe = new SimpleUniverse(canvas);
            universe.getViewingPlatform().setNominalViewingTransform();
    
            // シーンの生成
            universe.addBranchGraph(createSceneGraph());
            setVisible(true);
        }
    
        // シーンを生成する
        private BranchGroup createSceneGraph()
        {   int i;
            BranchGroup objRoot = new BranchGroup();
    
            // チューブの座標
            Point3d[] vect = new Point3d[VNUM*2];
            for(i=0; i<VNUM*2; i++) vect[i] = new Point3d();
            for(i=0; i<VNUM; i++)
            {   RotY(360.0f/KAKU*i, 0.5f, vect[i*2+1]);
                vect[i*2].x = vect[i*2+1].x;
                vect[i*2].z = vect[i*2+1].z;
                vect[i*2].y = 0.5f;
            }
            int[]   stripCounts = { VNUM*2 };
    
            // Light の設定
            BoundingSphere bounds = new BoundingSphere(new Point3d(),100.0);
            DirectionalLight dlight =
                new DirectionalLight(true, new Color3f(1.0f,1.0f,1.0f), new Vector3f(0.3f,-0.3f,-0.3f));
            dlight.setInfluencingBounds(bounds);
            objRoot.addChild(dlight);
            AmbientLight alight = new AmbientLight();
            alight.setInfluencingBounds(bounds);
            objRoot.addChild(alight);
    
            // Mouse 操作の設定
            TransformGroup trans = new TransformGroup();
            SetMouse(objRoot, trans);
    
            // チューブを作成
            GeometryInfo ginfo = new GeometryInfo(GeometryInfo.TRIANGLE_STRIP_ARRAY);
            ginfo.setStripCounts(stripCounts);
            ginfo.setCoordinates(vect);
    
            // 法線ベクトルの設定
            NormalGenerator gen = new NormalGenerator();
            gen.generateNormals(ginfo);
    
            // Appearance を設定して BranchGroup に追加
            Shape3D shape = new Shape3D(ginfo.getGeometryArray());
            shape.setAppearance(createAppearance());
    
            // BranchGroup に登録
            trans.addChild(shape);
            objRoot.addChild(trans);
            return objRoot;
        }
    
        // Y軸で回転計算(rt=度)、中心(0,0)、半径(len)
        public void RotY(float rt, float len, Point3d vect)
        {   vect.x = (float)(Math.sin(rt / 180 * Math.PI)) * len;
            vect.z = (float)(Math.cos(rt / 180 * Math.PI)) * len;
            vect.y = -0.5;
        }
    
        // Material の設定
        private Appearance createAppearance()
        {
            Material mat = new Material();
            mat.setDiffuseColor( new Color3f(0.8f, 0.8f, 0.0f) );
    
            // カリングしない
            PolygonAttributes pattr = new PolygonAttributes();
            pattr.setCullFace(PolygonAttributes.CULL_NONE); //両面を描画
            Appearance ap = new Appearance();
            ap.setMaterial(mat);
            ap.setPolygonAttributes(pattr);
            return ap;
        }
    
        // Mouse 操作の設定
        public void SetMouse(BranchGroup objRoot, TransformGroup trans)
        {
            // Model の修正を許可
            trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
            trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    
            // 回転を設定
            BoundingSphere bounds = new BoundingSphere(new Point3d(), 100.0);
            MouseRotate rotator = new MouseRotate(trans);
            rotator.setSchedulingBounds(bounds);
            objRoot.addChild(rotator);
    
            // 移動を設定
            MouseTranslate translator = new MouseTranslate(trans);
            translator.setSchedulingBounds(bounds);
            objRoot.addChild(translator);
    
            // ズームを設定
            MouseZoom zoomer = new MouseZoom(trans);
            zoomer.setSchedulingBounds(bounds);
            objRoot.addChild(zoomer);
        }
    
        // 終了処理
        public void destroy()
        {   universe.cleanup();  }
    }
    
  2. Java Applet を起動する HTMLファイルは、何時もと同じです。
    ソースプログラムをコンパイルして class オブジェクトを実行して下さい。
    Java Applet を使ったプログラムですが、コマンドラインから普通の Java と同様に実行することが出来ます。
    アプレットの実行は HTMLファイルをダブルクリックして起動して下さい。
    アプレットを実行しようとするとセキュリティの警告画面が表示されますが、解除して下さい。
     ・マウスの左ボタンを押しながらドラッグすると四面体が回転します。
     ・マウスの右ボタンを押しながらドラッグすると四面体が移動します。
     ・マウスの中央ボタンを押しながらドラッグすると四面体がズームイン・ズームアウトします。

プログラムの説明

  1. 基本的な説明は 四面体に法線ベクトルを設定する を参照して下さい。
    大域領域で KAKU と VNUM を定義します。
    KAKU の初期値は6なので、6角形のチューブが作成されます。
    円筒にするには、16以上の値を設定して下さい。
        public class applet_tube extends Applet
        {   private SimpleUniverse universe = null;
            int     KAKU = 6;       // チューブの角数
            int     VNUM = KAKU+1;  // 頂点座標の数
        
  2. プログラムでチューブ(円筒)の座標と法線ベクトルを設定する計算する createSceneGraph() メソッドです。
    チューブは TriangleStripArray を使って三角形ポリゴンを組み合わせて作成します。
    Point3d[VNUM*2]; が頂点座標の領域です。
    KAKU, VNUM は大域領域で宣言された変数で、この値を変えると円柱(角柱)の角数が変わります。
    回転座標を求める専用のメソッド RotY() を使って頂点座標を計算します。
    Y座標がチューブの高さで -0.5 と 0.5 に設定します。
    Y軸を基点に、X座標とZ座標に回転座標を求めます。
        // シーンを生成する
        private BranchGroup createSceneGraph()
        {   int i;
            BranchGroup objRoot = new BranchGroup();
    
            // チューブの座標
            Point3d[] vect = new Point3d[VNUM*2];
            for(i=0; i<VNUM*2; i++) vect[i] = new Point3d();
            for(i=0; i<VNUM; i++)
            {   RotY(360.0f/KAKU*i, 0.5f, vect[i*2+1]);
                vect[i*2].x = vect[i*2+1].x;
                vect[i*2].z = vect[i*2+1].z;
                vect[i*2].y = 0.5f;
            }
            int[]   stripCounts = { VNUM*2 };
        
  3. Light の設定と Mouse 操作の設定は何時もと同じ要領ですが、Mouse 操作をメソッドとして定義してみました。
  4. TriangleStrip で三角形ポリゴンを組み合わせてチューブを作成するのですが、今回は法線ベクトルを設定するので GeometryInfo を使います。
    法線ベクトルの設定は NormalGenerator を生成して generateNormals(ginfo); を実行するだけです。
    createAppearance() メソッドでマテリアルとカリングの設定を行います。
            // チューブを作成
            GeometryInfo ginfo = new GeometryInfo(GeometryInfo.TRIANGLE_STRIP_ARRAY);
            ginfo.setStripCounts(stripCounts);
            ginfo.setCoordinates(vect);
    
            // 法線ベクトルの設定
            NormalGenerator gen = new NormalGenerator();
            gen.generateNormals(ginfo);
    
            // Appearance を設定して BranchGroup に追加
            Shape3D shape = new Shape3D(ginfo.getGeometryArray());
            shape.setAppearance(createAppearance());
    
            // BranchGroup に登録
            trans.addChild(shape);
            objRoot.addChild(trans);
            return objRoot;
        }
        
  5. Y軸を基点にして回転座標を計算する RotY() メソッドです。
    rt が回転角度で len が半径です。
    Point3d vect に回転座標を格納します。
    Y座標は、とりあえず -0.5 に設定しています。
        // Y軸で回転計算(rt=度)、中心(0,0)、半径(len)
        public void RotY(float rt, float len, Point3d vect)
        {   vect.x = (float)(Math.sin(rt / 180 * Math.PI)) * len;
            vect.z = (float)(Math.cos(rt / 180 * Math.PI)) * len;
            vect.y = -0.5;
        }
        
  6. createAppearance() メソッドでマテリアルとカリングの設定を行います。
    カリングを省略すると外側しか描画されないので、両面描画に設定しています。
        // Material の設定
        private Appearance createAppearance()
        {
            Material mat = new Material();
            mat.setDiffuseColor( new Color3f(0.8f, 0.8f, 0.0f) );
    
            // カリングしない
            PolygonAttributes pattr = new PolygonAttributes();
            pattr.setCullFace(PolygonAttributes.CULL_NONE); //両面を描画
            //pattr.setCullFace(PolygonAttributes.CULL_BACK); //裏面をカリング
            Appearance ap = new Appearance();
            ap.setMaterial(mat);
            ap.setPolygonAttributes(pattr);
            return ap;
        }
        

Java Game Program