■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                      2008年08月31日

    楽しいJava講座 - 初心者から達人へのパスポート
                  vol.118

                                セルゲイ・ランダウ
 バックナンバー: http://www.flsi.co.jp/Java_text/
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


[このメールマガジンは、画面を最大化して見てください。]


========================================================
◆ 01.3Dグラフィックスのアプリケーション開発
========================================================

では、球体を地球に見立て、立方体を人工衛星に見立てて、立方体を球体の周りに
グルグル回らせるようなアニメーションを作ってみましょう。


実は、Java 3Dには、このアニメーションを簡単に作れる機能が予め用意されて
います。


まず、アニメーションというのは、複数の画像のコマを速い時間間隔で送っていく
ことによって描きますね。
昔のフィルムを使っていた時代の映画で言えば、フィルム上に複数の写真が並んで
いますが、この一つの写真がコマと呼ばれるものです。
このコマをとても速い時間間隔で次々と映写していくことによって、動きのある画像
(映像)が見られるわけです。

そして、このコマのことを英語でフレーム(frame)と呼びます。
(フレームウインドウのフレーム(frame)と同じ単語なので紛らわしいですが、
区別して下さい。)


Java 3Dでは、コマを速い時間間隔で送っていく動作を次のようにして指定する
ことができます。

universe.getViewer().getView().setMinimumFrameCycleTime(10);

ここで、universeはこれまで使ってきたSimpleUniverseのインスタンスです。
getViewer()はViewer(universeの観察者を表現するオブジェクト)を取り出す
ためのメソッドです。
getView()はuniverseの観察者から見たView(眺望を表すオブジェクト)を取り
出すためのメソッドです。
そして、setMinimumFrameCycleTime()はViewにフレーム(コマ)を送る時間間隔(cycle time)
を設定するためのメソッドです。この引数には時間間隔をミリ秒(1000分の1秒)単位
で指定します(上記では10ミリ秒を指定している)。
ただし、メソッド名にMinimumという言葉が含まれていることからもわかるように、
ここに指定する時間間隔はあくまで最低これ以上という意味であり、コンピューター
のハードウエアの画像描画能力によっては、ここに指定した時間間隔より大きい間隔
になってしまうことがあります。


さて、次に立方体をグルグルと周回させる方法ですが、このためにRotationInterpolator
というクラスがJava 3Dによって提供されています。

RotationInterpolatorは、回転するときの位置の遷移を表すクラスで、ここでは、
(人工衛星に見立てた)立方体が球体の周りをグルグル周回するときの位置の
変化を表すために使います。

このためには、RotationInterpolatorのインスタンスを下記のように生成します。

RotationInterpolator rotator =   new RotationInterpolator(alpha, rotationTransGrp);

ここで、alphaはAlphaというクラスのインスタンスで、0から1までの数(たとえば、0,
0.01, 0.02, 0.03, ・・・,0.1, 0.11, 0.12, 0.13, ・・・, 0.97, 0.98, 0.99, 1と
いうふうに0から1まで変化する数)を表すオブジェクトで、360度の回転の場合は、
0から1までで1回転を表すことになります(要するに0から1までの変化が角度0度から
360度までの変化に対応する)。
また、rotationTransGrpはこの回転の対象となるTransformGroupオブジェクトです。
なお、RotationInterpolatorによる回転はデフォルトではY軸が回転軸になります。
別の軸を回転軸にする方法については、また後ほど説明いたします。

このTransformGroupオブジェクトは、アニメーションのために逐次座標変換を変える
(位置座標を変える)必要があるので、変換の書き換えを許可する必要があります。
これは、下記のようなコードで実行できます。

rotationTransGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

それから、alphaは以下のようにインスタンス生成します。

Alpha alpha = new Alpha(-1, 5000);

ここで、コンストラクターの第一引数は0から1までの変化を何回繰り返すかを
指定する数字で、無限に繰り返したいときには-1を指定します。
また、第二引数は0から1までの変化の周期を指定する数値でミリ秒単位になり
ます。つまり、上の指定では、周期を5000にしていますから、5秒で0から1まで
変化することになり、360度の回転の場合は、5秒で1回転することになります。

また、このRotationInterpolatorを使う際には、その回転がおよぶ空間の範囲を
次のようにして指定してやる必要があります。

rotator.setSchedulingBounds(rotationBounds);

ここで、rotationBoundsは光を照射する範囲を指定したときに使ったのと同じ
BoundingSphereクラスのインスタンスで、たとえば

BoundingSphere rotationBounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 1.0);

のようにインスタンス生成しておきます。

そして、rotatorをTransformGroupオブジェクトの子にする、つまり

rotationTransGrp.addChild(rotator);

を実行すると、rotationTransGrpの子(またはその子の子、あるいはさらにその子の
子の子、・・・・)になっている物体がRotationInterpolatorオブジェクトで指定し
た回転動作を行うことになります。

そして、このときの回転の周期は、上のAlphaのインスタンス生成のときに指定した
5秒という時間になりますが、実際の回転の様子をアニメーションとして描画する
ときのフレーム(コマ)の描画は、上のsetMinimumFrameCycleTime()メソッドで
指定した10ミリ秒、すなわち100分の1秒ごとに描画されることになります。(描画
のハードウエアの性能によっては、それより長い時間間隔になることもある。)


では、これらを踏まえて、下記のようにinitialize()メソッドを書き換えてみてください。

--------------------------------------------------------
   private void initialize() {
      this.setSize(300, 200);
      this.setContentPane(getJContentPane());
      this.setTitle("立方体と球体");

      GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
      Canvas3D canvas = new Canvas3D(config);
      SimpleUniverse universe = new SimpleUniverse(canvas);
      BranchGroup group = new BranchGroup();
      TransformGroup transGroup = new TransformGroup();
      transGroup.addChild(new ColorCube(0.02));
      Transform3D trans = new Transform3D();
      trans.setTranslation(new Vector3d(0.7, 0.0, 0.0));
      transGroup.setTransform(trans);

      TransformGroup rotationTransGrp = new TransformGroup();
      rotationTransGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
      Alpha alpha = new Alpha(-1, 5000);
      RotationInterpolator rotator =   new RotationInterpolator(alpha, rotationTransGrp);
      BoundingSphere rotationBounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 1.0);
      rotator.setSchedulingBounds(rotationBounds);
      rotationTransGrp.addChild(transGroup);
      rotationTransGrp.addChild(rotator);
      group.addChild(rotationTransGrp);

      BranchGroup group2 = new BranchGroup();
     
      Color3f darkColor = new Color3f(0.0f, 0.0f, 0.0f);
      Color3f ambiColor = new Color3f(0.0f, 0.1f, 0.0f);
      Color3f diffuColor = new Color3f(0.0f, 0.6f, 0.0f);
      Material mat = new Material(ambiColor, darkColor, diffuColor, darkColor, 0.0f);
      Appearance appear = new Appearance();
      appear.setMaterial(mat);
     
      Sphere sphere = new Sphere(0.5f, Sphere.GENERATE_NORMALS, 100, appear);
      group2.addChild(sphere);
      Color3f color = new Color3f(1.5f, 1.5f, 0.0f);
      BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 1.0);
      Vector3f lightDirection = new Vector3f(-1.0f, -1.0f, -1.0f);
      DirectionalLight light = new DirectionalLight(color, lightDirection);
      light.setInfluencingBounds(bounds);
      group2.addChild(light);
      AmbientLight ambiLight = new AmbientLight(color);
      ambiLight.setInfluencingBounds(bounds);
      group2.addChild(ambiLight);
      group.addChild(group2);

      universe.getViewingPlatform().setNominalViewingTransform();
      universe.getViewer().getView().setMinimumFrameCycleTime(5);
      group.compile();
      universe.addBranchGraph(group);
      getJContentPane().add(canvas);
   }
--------------------------------------------------------

なお、立方体は人工衛星らしく見せるために以前よりずっと小さくして、最初の位置も
適切な位置に修正しておきました。(これでも、地球に比べて人工衛星がずいぶん大き
すぎると思うけど。)

どこをどのように編集したかわかりますね。


編集が終わったら、保管して実行してみてください。

立方体がY軸の周り(球体の周り)をグルグル回るのが見えますね。



さて、実は、もし、これだけのものをJava 3Dなしに作ろうとすると、(一見簡単そう
に見えるかもしれませんが、実際は)非常に手間がかかる上に、普通に作るとパフォー
マンス(性能)の悪い(重い)プログラムになってしまいます。

ところが、Java 3Dでは、簡単に作れてしまう上に、さらに今までにプログラム内に
入れてきた

group.compile();
(groupはuniverseに追加(universe.addBranchGraph(group))したBranchGroup)

というコード指定によって、最適化(プログラムを自動調整してパフォーマンスの
よいプログラムにしてくれる)までしてくれます。


とにかく、Java 3Dを使えば、3Dグラフィックスのプログラムがずいぶん楽に作れる
ことがわかったと思います。



では、今度は、回転軸をちょっと傾けてみましょう。


(次回に続く)


では、今日はここまでにします。

何か、わからないところがありましたら、下記のWebページまで質問を
お寄せください。



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      http://www.flsi.co.jp/Java_text/
★このメールマガジンは
     「まぐまぐ(http://www.mag2.com)」
 を利用して発行しています。
★バックナンバーは
      http://www.flsi.co.jp/Java_text/
 にあります。
★このメールマガジンの登録/解除は下記Webページでできます。
      http://www.mag2.com/m/0000193915.html
★このメールマガジンへの質問は下記Webページにて受け付けて
 います。わからない所がありましたら、どしどしと質問をお寄
 せください。
      http://www.flsi.co.jp/Java_text/
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Copyright (C) 2008 Future Lifestyle Inc. 不許無断複製