Scene を生成する

モデルが格納された Scene を生成する Loader の基礎です。
腕に自信のある方は「ローダーを開発して公開」して下さい。

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

空の Scene を作成

  1. Java3D には Wavefront で作成した OBJ ファイルのローダーと Lightwave で作成した LWS のローダーが用意されています。
    ところが OBJ のローダーはモデルを正常に描画できない場合が良くあります。
    はっきりした原因は不明ですが、一般的にモデルは専用のツールで作成されるので、それに対応したローダーを作成しなければなりません。
    LWS のローダーに至っては、今は使われていない一昔前のモデルしか描画出来ません。 (^_^;)
    もしかしたら開発当初は正常に動いていたものが、モデルソフトのバージョンアップにより対応できなくなったのかも知れません。
    ソースコードが公開されていれば、修正も出来るのですが探しても見当たりません。 (;_;)
    そこで私が知り得たローダーの開発方法を説明して、腕に自信のある方の協力を仰ぐことにしました。
  2. 最初に Scene の生成方法から説明しましょう。
    モデルが格納されていない「空の Scene」を作成しています。
    //★ Scene Test    前田 稔
    import java.awt.*;
    import javax.swing.*;
    import javax.media.j3d.*;
    import javax.vecmath.*;
    import com.sun.j3d.utils.universe.*;
    import java.io.*;
    import java.net.URL;
    import com.sun.j3d.loaders.*;
    
    public class Scene_Test extends JFrame
    {
        // main Method
        public static void main(String[] args)
        {   java.awt.EventQueue.invokeLater(new Runnable()
            {   public void run()
                {   new Scene_Test().setVisible(true);  }
            });
        }
    
        // Constructor
        public Scene_Test()
        {   // JFrame の初期化
            super("Scene test");
            setSize(512,512);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            // Java3D 関係の設定
            GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
            Canvas3D canvas = new Canvas3D(config);
            add(canvas);
    
            // SimpleUniverseを生成
            SimpleUniverse universe = new SimpleUniverse(canvas);
            universe.getViewingPlatform().setNominalViewingTransform();
    
            // Scene を生成
            universe.addBranchGraph(CreateScene());
        }
    
        // Scene の生成
        public BranchGroup CreateScene()
        {   BranchGroup objRoot = new BranchGroup();
    
            // 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);
    
            // モデルの入力
            Loader_Test f = new Loader_Test();
            Scene s = null;
            s = f.load("cube.obj");
    
            objRoot.addChild(s.getSceneGroup());
    
            // 背景色の設定
            Color3f bgColor = new Color3f(0.05f, 0.05f, 0.5f);
            Background bgNode = new Background(bgColor);
            bgNode.setApplicationBounds(bounds);
            objRoot.addChild(bgNode);
            return objRoot;
        }
    }
    
    class Loader_Test extends LoaderBase
    {
        @Override
        public Scene load(String filename)
        {   SceneBase base = new SceneBase();
            return base;
        }
    
        @Override
        public Scene load(URL aURL)
        {   SceneBase base = new SceneBase();
            return base;
        }
    
        @Override
        public Scene load(Reader reader)
        {   SceneBase base = new SceneBase();
            return base;
        }
    }
    
  3. main() メソッドと Constructor と CreateScene() は今までのプログラムを参照して下さい。
    Loader を作成するときは com.sun.j3d.loaders.*; を import します。
    モデルファイルを入力するので File 関係のライブラリを import しています。
  4. Loader_Test f = new Loader_Test(); でローダーを生成します。
    s = f.load("cube.obj"); でモデルを入力して Scene を設定します。
    今回は空の Scene なので "cube.obj" は書かれているだけです。
            // モデルの入力
            Loader_Test f = new Loader_Test();
            Scene s = null;
            s = f.load("cube.obj");
        
  5. Scene を生成する Loader_Test Class は LoaderBase を継承します。
    三種類のパラメータを持つ load() メソッドを Override して下さい。
    今回は空の Scene なので new SceneBase() で生成して return するだけです。
        class Loader_Test extends LoaderBase
        {
            @Override
            public Scene load(String filename)
            {   SceneBase base = new SceneBase();
                return base;
            }
    
            @Override
            public Scene load(URL aURL)
            {   SceneBase base = new SceneBase();
                return base;
            }
    
            @Override
            public Scene load(Reader reader)
            {   SceneBase base = new SceneBase();
                return base;
            }
        }
        

Scene に立方体を格納

  1. 空の Scene では面白く無いので、Scene に立方体を格納してみましょう。
    //★ Scene BoxTest  立方体に法線ベクトルを設定    前田 稔
    import java.awt.*;
    import javax.swing.*;
    import javax.media.j3d.*;
    import javax.vecmath.*;
    import com.sun.j3d.utils.universe.*;
    import com.sun.j3d.utils.geometry.*;
    import java.io.*;
    import java.net.URL;
    import com.sun.j3d.loaders.*;
    import com.sun.j3d.utils.behaviors.mouse.*;
    
    public class Scene_BoxTest extends JFrame
    {
        // main Method
        public static void main(String[] args)
        {   java.awt.EventQueue.invokeLater(new Runnable()
            {   public void run()
                {   new Scene_BoxTest().setVisible(true);  }
            });
        }
    
        // Constructor
        public Scene_BoxTest()
        {   // JFrame の初期化
            super(" Scene test");
            setSize(512,512);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            // Java3D 関係の設定
            GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
            Canvas3D canvas = new Canvas3D(config);
            add(canvas);
    
            // SimpleUniverseを生成
            SimpleUniverse universe = new SimpleUniverse(canvas);
            universe.getViewingPlatform().setNominalViewingTransform();
    
            // Scene を生成
            universe.addBranchGraph(CreateScene());
        }
    
        // Scene の生成
        public BranchGroup CreateScene()
        {   BranchGroup objRoot = new BranchGroup();
    
            // 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);
    
            // モデルの拡大・縮小
            TransformGroup objScale = new TransformGroup();
            Transform3D t3d = new Transform3D();
            t3d.setScale(0.4);
            objScale.setTransform(t3d);
            objRoot.addChild(objScale);
    
            // Mouse 操作の設定
            TransformGroup trans = new TransformGroup();
            SetMouse(objRoot, trans);
            objScale.addChild(trans);
    
            // モデルの入力("cube.obj" は書いているだけ)
            Loader_Test f = new Loader_Test();
            Scene s = null;
            s = f.load("cube.obj");
    
            trans.addChild(s.getSceneGroup());
    
            // 背景色の設定
            Color3f bgColor = new Color3f(0.05f, 0.05f, 0.5f);
            Background bgNode = new Background(bgColor);
            bgNode.setApplicationBounds(bounds);
            objRoot.addChild(bgNode);
            return objRoot;
        }
    
        // 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);
       }
    }
    
    // ★ Loader Object Class
    class Loader_Test extends LoaderBase
    {   SceneBase   base;
    
        @Override
        public Scene load(String filename)
        {   creatscene();
            return base;
        }
    
        @Override
        public Scene load(URL aURL)
        {   base = new SceneBase();
            return base;
        }
    
        @Override
        public Scene load(Reader reader)
        {   base = new SceneBase();
            return base;
        }
    
        // Scene を生成
        public void creatscene()
        {   base = new SceneBase();
            base.setSceneGroup(new BranchGroup());
    
            // 立方体の座標を定義
            Point3f[] vertices =
            {  new Point3f(-1.0f, -1.0f, -1.0f), new Point3f(1.0f, -1.0f, -1.0f),
               new Point3f(-1.0f, 1.0f, -1.0f),  new Point3f(1.0f, 1.0f, -1.0f),
               new Point3f(-1.0f, -1.0f, 1.0f),  new Point3f(1.0f, -1.0f, 1.0f),
               new Point3f(-1.0f, 1.0f, 1.0f),   new Point3f(1.0f, 1.0f, 1.0f)
            };
            // 法線ベクトルを定義
            Vector3f[] normal =
            {  new Vector3f(0.0f, 0.0f, -1.0f), new Vector3f(-1.0f, 0.0f, 0.0f),
               new Vector3f(1.0f, 0.0f, 0.0f),  new Vector3f(0.0f, -1.0f, 0.0f),
               new Vector3f(0.0f, 1.0f, 0.0f),  new Vector3f(0.0f, 0.0f, 1.0f),
            };
    
            // Index を定義
            int[] indices = { 0,2,3,1, 0,4,6,2, 1,3,7,5, 0,1,5,4, 2,6,7,3, 4,5,7,6 };
            int[] normidx = { 0,0,0,0, 1,1,1,1, 2,2,2,2, 3,3,3,3, 4,4,4,4, 5,5,5,5 };
            // 矩形の区切りを定義(4角形ポリゴン*6個)
            int[] stripCount = { 4,4,4,4,4,4 };
    
            // 立方体を作成
            GeometryInfo gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
            gi.setCoordinates(vertices);
            gi.setCoordinateIndices(indices);
            gi.setStripCounts(stripCount);
            gi.setNormals(normal);
            gi.setNormalIndices(normidx);
    
            // Material を設定して SceneBase に追加
            Shape3D shape = new Shape3D(gi.getGeometryArray());
            shape.setAppearance(createAppearance());
            base.getSceneGroup().addChild(shape);
        }
    
        // Material の設定
        private Appearance createAppearance()
        {   Material mat = new Material();
            mat.setDiffuseColor(new Color3f(0.8f, 0.8f, 0.0f));
            Appearance ap = new Appearance();
            ap.setMaterial(mat);
            return ap;
        }
    }
    
  2. 多くのモデルファイルは、頂点座標の定義とポリゴンを構成するインデックスの定義に分かれています。
    また、法線ベクトルもベクトルの定義とインデックスの定義に分かれています。
    ポリゴンはモデルによって三角形と四角形ポリゴンで構成される場合と五角形以上のポリゴンが使われる場合があります。
    多角形ポリゴンにも対応できるように GeometryInfo() の POLYGON_ARRAY でモデルを生成しています。
            // 立方体の座標を定義
            Point3f[] vertices =
            {  new Point3f(-1.0f, -1.0f, -1.0f), new Point3f(1.0f, -1.0f, -1.0f),
               new Point3f(-1.0f, 1.0f, -1.0f),  new Point3f(1.0f, 1.0f, -1.0f),
               new Point3f(-1.0f, -1.0f, 1.0f),  new Point3f(1.0f, -1.0f, 1.0f),
               new Point3f(-1.0f, 1.0f, 1.0f),   new Point3f(1.0f, 1.0f, 1.0f)
            };
            // 法線ベクトルを定義
            Vector3f[] normal =
            {  new Vector3f(0.0f, 0.0f, -1.0f), new Vector3f(-1.0f, 0.0f, 0.0f),
               new Vector3f(1.0f, 0.0f, 0.0f),  new Vector3f(0.0f, -1.0f, 0.0f),
               new Vector3f(0.0f, 1.0f, 0.0f),  new Vector3f(0.0f, 0.0f, 1.0f),
            };
    
            // Index を定義
            int[] indices = { 0,2,3,1, 0,4,6,2, 1,3,7,5, 0,1,5,4, 2,6,7,3, 4,5,7,6 };
            int[] normidx = { 0,0,0,0, 1,1,1,1, 2,2,2,2, 3,3,3,3, 4,4,4,4, 5,5,5,5 };
            // 矩形の区切りを定義(4角形ポリゴン*6個)
            int[] stripCount = { 4,4,4,4,4,4 };
    
            // 立方体を作成
            GeometryInfo gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
            gi.setCoordinates(vertices);
            gi.setCoordinateIndices(indices);
            gi.setStripCounts(stripCount);
            gi.setNormals(normal);
            gi.setNormalIndices(normidx);
        
  3. モデルをマウスで操作してみて下さい。
     ・マウスの左ボタンを押しながらドラッグすると ColorCube が回転します。
     ・マウスの右ボタンを押しながらドラッグすると ColorCube が移動します。
     ・マウスの中央ボタンを押しながらドラッグすると ColorCube がズームイン・ズームアウトします。
  4. ここから先はモデルファイルを入力して、頂点座標と法線ベクトルとポリゴンを構成する Index の配列を作成すれば初歩のローダーの完成です。
    腕に自信のある方の奮闘を期待しています。 (^_^;)
    ローダーが完成した暁には、ぜひメールで知らせて下さい。

超初心者のプログラム入門(Java2)