■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                      2008年08月03日

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

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


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


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

さて、宇宙(SimpleUniverse)の中は基本的には真っ暗です。
そして、真っ暗闇の中では、光がなければ何も見えません。


実は、今まで使ってきたColorCubeという立方体は、わざわざ各面を
自分で光らせる(しかも面ごとに異なる色で光る)ように作られてい
るため、見えていたのですが、普通の物体は外から光を照射してやら
なければ見えません。


では試しに、ColorCubeJFrameに球体を追加してみましょう。

ColorCubeJFrameの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.3));
      Transform3D trans = new Transform3D();
      trans.setTranslation(new Vector3d(-2.0, -1.0, -5.0));
      transGroup.setTransform(trans);
      group.addChild(transGroup);

      BranchGroup group2 = new BranchGroup();
      Sphere sphere = new Sphere(0.1f);
      group2.addChild(sphere);
      group.addChild(group2);

      universe.getViewingPlatform().setNominalViewingTransform();
      group.compile();
      universe.addBranchGraph(group);
      getJContentPane().add(canvas);
   }
--------------------------------------------------------

ここで、Sphereは球体を表現するクラスで、Sphere(0.1f)というコンストラクター
を使ってインスタンス生成すると、半径が0.1の球体が作られます。つまり、この
引数は球体の半径です。

この球体に対しては変換を行うつもりはないので、TransformGroupは使わず、
立方体とは別のグループに所属させることにして、とりあえずgroup2という別の
BranchGroupに所属させて(つまりgroup2.addChild(sphere)して)います。

そしてそのgroup2をgroupの子として追加(つまりgroup.addChild(group2))して
います。

こうしておけば、原点を中心にした半径0.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.3));
      Transform3D trans = new Transform3D();
      trans.setTranslation(new Vector3d(-2.0, -1.0, -5.0));
      transGroup.setTransform(trans);
      group.addChild(transGroup);

      BranchGroup group2 = new BranchGroup();
      Sphere sphere = new Sphere(0.1f);
      group2.addChild(sphere);
      Color3f color = new Color3f(10.0f, 10.0f, 10.0f);
      BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 1.0);
      Vector3f lightDirection = new Vector3f(0.0f, 0.0f, -1.0f);
      DirectionalLight light   = new DirectionalLight(color, lightDirection);
      light.setInfluencingBounds(bounds);
      group2.addChild(light);
      group.addChild(group2);

      universe.getViewingPlatform().setNominalViewingTransform();
      group.compile();
      universe.addBranchGraph(group);
      getJContentPane().add(canvas);
   }
--------------------------------------------------------

ここで、Color3fは光の色を表現するクラスで、コンストラクターColor3f(10.0f, 10.0f, 10.0f)
の引数はそれぞれ、赤色(red), 緑色(green), 青色(blue)の光の強さを表し、
その数値が大きいほど強い光になります。(すべての引数が0のときは真っ暗になり
ます。)
ここでは、red, green, blueともに同じ数値を指定していますので、白色光になり
ます。

なお、光はスポットライトのように、決まった範囲に対して照射するのですが、
その範囲を指定するために、ここではBoundingSphereというクラスを使用しています。

BoundingSphereは球面状の境界を表現するクラスで、ここでは、
BoundingSphere(new Point3d(0.0,0.0,0.0), 1.0)というコンストラクターによって、
光を照射する範囲を、原点(new Point3d(0.0,0.0,0.0)で表現)を中心とした半径1.0
の球面内に指定するようにしています。

DirectionalLightは一方向に照射される光を表し、例えば太陽のように無限に遠い距離
を隔てた光源から照射される光が、地球上にはすべて一定方向に平行に照射している
ように見えるという状況を表現するために利用することができます。
ここでは、 DirectionalLight(color, lightDirection)というコンストラクターを使用
することによって、引数で光の色と方向を指定しており、光の色は先ほどの白色光で、
方向はVector3f(0.0f, 0.0f, -1.0f)という方向ベクトルのコンストラクターによって、
指定された方向、すなわち、原点から点(0.0, 0.0, -1.0)に向かう方向、つまり、
z軸の負の方向、つまり我々の目から画面に向かう方向、が指定されたことになります。

したがって、この球体は真正面に光が当たりますから、満月と同じように真ん丸に光る
はずです。

実際にこのソース・コードを保管して実行してみると、真ん中に満月のように光った
円形が見えますね。(円形が少しいびつに見える理由は次回解説いたします。)



では、今度は光を(左側の)真横から照射することによって、球体を半月のように光ら
せてみましょう。つまり、上のソース・コードのうち
      Vector3f lightDirection = new Vector3f(0.0f, 0.0f, -1.0f);
の部分を
      Vector3f lightDirection = new Vector3f(1.0f, 0.0f, 0.0f);
に変更してみましょう。

つまり、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.3));
      Transform3D trans = new Transform3D();
      trans.setTranslation(new Vector3d(-2.0, -1.0, -5.0));
      transGroup.setTransform(trans);
      group.addChild(transGroup);

      BranchGroup group2 = new BranchGroup();
      Sphere sphere = new Sphere(0.1f);
      group2.addChild(sphere);
      Color3f color = new Color3f(10.0f, 10.0f, 10.0f);
      BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 1.0);
      Vector3f lightDirection = new Vector3f(1.0f, 0.0f, 0.0f);
      DirectionalLight light   = new DirectionalLight(color, lightDirection);
      light.setInfluencingBounds(bounds);
      group2.addChild(light);
      group.addChild(group2);

      universe.getViewingPlatform().setNominalViewingTransform();
      group.compile();
      universe.addBranchGraph(group);
      getJContentPane().add(canvas);
   }
--------------------------------------------------------

編集したら、保管して実行してみてください。半月が見えましたか。



では、三日月のような状態にしたいときはどうしたらよいでしょうか。

この場合は、後方の斜め方向から光を照射すればいいのですね。

たとえば、光の方向を
      Vector3f lightDirection = new Vector3f(1.0f, 1.0f, 1.0f);
のようにすればいいですね。

したがって、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.3));
      Transform3D trans = new Transform3D();
      trans.setTranslation(new Vector3d(-2.0, -1.0, -5.0));
      transGroup.setTransform(trans);
      group.addChild(transGroup);

      BranchGroup group2 = new BranchGroup();
      Sphere sphere = new Sphere(0.1f);
      group2.addChild(sphere);
      Color3f color = new Color3f(10.0f, 10.0f, 10.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);
      group.addChild(group2);

      universe.getViewingPlatform().setNominalViewingTransform();
      group.compile();
      universe.addBranchGraph(group);
      getJContentPane().add(canvas);
   }
--------------------------------------------------------

編集したら、保管して実行してみてください。三日月が見えましたか。



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

何か、わからないところがありましたら、下記の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. 不許無断複製