Scene XTest

DirectX のモデルを生成する Loader の基礎です。

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

プログラムの作成

  1. 私が持っている3Dモデルの多くは DirectX で使われている XFILE 形式です。
    そこで XFILE をロードするローダーを開発することにしました。
    XモデルはOBJモデルと違って Face と呼ばれる多角形ごとにマテリアルを設定します。
    そこで Scene に立方体を格納するプログラムを XFILE に合わせて作成してみました。
    Scene を生成する基本的なプログラムは Scene を生成する を参照して下さい。
  2. Scene に立方体を格納するプログラムです。
    //★ Face Test  立方体に法線を追加する    前田 稔
    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 FaceV2 extends JFrame
    {
        // main Method
        public static void main(String[] args)
        {   java.awt.EventQueue.invokeLater(new Runnable()
            {   public void run()
                {   new FaceV2().setVisible(true);  }
            });
        }
    
        // Constructor
        public FaceV2()
        {   // 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);
    
            // Mouse 操作の設定
            TransformGroup trans = new TransformGroup();
            SetMouse(objRoot, trans);
            objRoot.addChild(trans);
    
            // モデルの入力("Cube.x" は書いているだけ)
            Loader_Test f = new Loader_Test();
            Scene s = null;
            s = f.load("Cube.x");
            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)
        {   SceneBase base = new SceneBase();
            return base;
        }
    
        @Override
        public Scene load(Reader reader)
        {   SceneBase base = new SceneBase();
            return base;
        }
    
        // Scene を生成
        public void creatscene()
        {   int i,j,n;
            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 };
    
            for(i=0; i<6; i++)
            {
                Point3f[] vw = new Point3f[4];
                Vector3f[] nw = new Vector3f[4];
                for(j=0; j<4; j++)
                {  n = indices[i*4+j];
                   vw[j] = vertices[n];
                   n = normidx[i*4+j];
                   nw[j] = normal[n];
                }
                face(base,vw,nw);
            }
        }
    
        // Face(Polygon) を生成
        public void face(SceneBase base, Point3f[] vertices, Vector3f[] normal)
        {
            int[] stripCount = new int[1];
    
            stripCount[0] = vertices.length;
            // Face を作成
            GeometryInfo ginfo = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
            ginfo.setCoordinates(vertices);
            ginfo.setStripCounts(stripCount);
            ginfo.setNormals(normal);
    
            // Material を設定して SceneBase に追加
            Shape3D shape = new Shape3D(ginfo.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;
        }
    }
    

プログラムの説明

  1. main() メソッドと Constructor と CreateScene() は今までのプログラムを参照して下さい。
    Loader を作成するときは com.sun.j3d.loaders.*; を import します。
  2. Loader_Test f = new Loader_Test(); でローダーを生成します。
    s = f.load("Cube.x"); でモデルを入力して Scene を設定します。
    今回は立方体の座標を直接定義しているので "Cube.x" は書かれているだけです。
            // モデルの入力("Cube.x" は書いているだけ)
            Loader_Test f = new Loader_Test();
            Scene s = null;
            s = f.load("Cube.x");
        
  3. Scene を生成する Loader_Test Class は LoaderBase を継承します。
    三種類のパラメータを持つ load() メソッドを Override して下さい。
  4. 多くのモデルファイルは、頂点座標の定義とポリゴンを構成するインデックスの定義に分かれています。
    また、法線ベクトルもベクトルの定義とインデックスの定義に分かれています。
    ポリゴンはモデルによって三角形と四角形ポリゴンで構成される場合と五角形以上のポリゴンが使われる場合があります。
    X-FILE では五角形以上のポリゴンも使われています。
    立方体の座標の定義と法線ベクトルの定義と Index の定義は OBJ のときと同じです。
  5. Xモデルでは Face と呼ばれる多角形ごとにマテリアルを設定します。
    立方体のモデルでは Face は四角形ポリゴンが6個です。
    face(base,vw,nw); を呼び出して、Face を SceneBase に追加します。
            for(i=0; i<6; i++)
            {
                Point3f[] vw = new Point3f[4];
                Vector3f[] nw = new Vector3f[4];
                for(j=0; j<4; j++)
                {  n = indices[i*4+j];
                   vw[j] = vertices[n];
                   n = normidx[i*4+j];
                   nw[j] = normal[n];
                }
                face(base,vw,nw);
            }
        
  6. Face を SceneBase に追加する face(); メソッドです。
    GeometryInfo() で Face(多角形)を生成します。
        // Face(Polygon) を生成
        public void face(SceneBase base, Point3f[] vertices, Vector3f[] normal)
        {
            int[] stripCount = new int[1];
    
            stripCount[0] = vertices.length;
            // Face を作成
            GeometryInfo ginfo = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
            ginfo.setCoordinates(vertices);
            ginfo.setStripCounts(stripCount);
            ginfo.setNormals(normal);
    
            // Material を設定して SceneBase に追加
            Shape3D shape = new Shape3D(ginfo.getGeometryArray());
            shape.setAppearance(createAppearance());
            base.getSceneGroup().addChild(shape);
        }
        

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