Java 3Dの座標系はどのようなものでしょうか。
簡単なサンプル・アプレットを見てください。
このアプレットは、地球の中心がちょうど原点(x = 0, y = 0, z = 0)になっています。
右方向がX軸、上方向がY軸の正方向です。
Z軸の正方向は、地球の中心(原点)から目の位置(このアプレットを見ている皆さんの目です)に向かう方向になります。数学座標と同じですね。
この座標系のことを特に右手座標系と呼ぶことがあります。
目の前で右手の3本の指を広げてみてください。
右手の親指がX軸、人差し指がY軸、水平にした中指がZ軸というわけです。
Java 3Dでは使いませんが、「左手座標系」と呼ばれる座標系もあります。
左手座標系のX軸、Y軸は右手座標系と同じですが、Z軸の正負は右手座標系と逆になります。
Java 3Dの長さの単位はメートルです。1.0が1メートルです。
Java 3Dでは256ビット固定小数点座標が採用されています。
宇宙規模からプランク長までの仮想空間が表現できます。
2n メートル | 単位 |
---|---|
87.29 | 宇宙 (2,000万光年) |
69.68 | 銀河系 (100,000 光年) |
53.07 | 光年 |
43.43 | 太陽系の直径 |
23.60 | 地球の直径 |
10.65 | マイル |
9.97 | キロメートル |
0.00 | メートル |
-19.93 | ミクロン |
-33.22 | オングストローム |
-115.57 | プランク長 |
Java 3Dの256ビット固定小数点座標を扱うためのオブジェクトとしてjavax.media.j3d.HiResCoord
オブジェクトが用意されています。
クラス継承 java.lang.Object | +--javax.media.j3d.HiResCoord クラス宣言 public class HiResCoord extends java.lang.Object
HiResCoord
オブジェクトには次のようなコンストラクターがあります。
public HiResCoord(int[] X, // X座標を表す、要素数8のintの配列 int[] Y, // Y座標を表す、要素数8のintの配列 int[] Z) // Z座標を表す、要素数8のintの配列
このコンストラクターでは、256ビット固定小数点値をあらわすために、要素数8のintの配列を使用します。
Java 3DTM API Specification の "3.5.3 Details of High-resolution Coordinates" での記述によると、
int配列の先頭要素(index 0)には、256ビット固定小数点数の最上位ビットが存在し、
int配列の最後の要素(index 7)には、256ビット固定小数点数の最下位ビットが存在し、
小数点位置は上位128ビットと下位128ビットの境界(index 3の要素とindex 4の要素の境界)だ、ということです。
Java 3Dでの描画のためにアプレットを書いてみます。
Javaアプリケーションを書いても良いのですが、アプレットはAppletViewerやブラウザーで表示することも可能ですし、main()
メソッドを書けばアプリケーションとして単独で実行することもできます。
FirstApplet.java1 // Java 3Dテスト用アプレット 2 // FirstApplet.java 3 4 import java.applet.*; 5 6 public class FirstApplet extends Applet { 7 public FirstApplet() { 8 } 9 }
これを表示するHTMLを書いてみます。
FirstApplet.html1 <HTML> 2 <HEAD> 3 <TITLE>Java 3D TestApplet</TITLE> 4 </HEAD> 5 <BODY> 6 <APPLET code="FirstApplet.class" width="500" height="500" codebase="."> 7 </APPLET> 8 </BODY> 9 </HTML>
AppletViewerで実行してみましょう。
>appletviewer FirstApplet.html
このアプレットをJavaアプリケーションとしても実行できるようにmain()
メソッドを書いてみましょう。
アプレットをアプリケーションとして実行させるには、main()
メソッドのなかで最低限次のことを行う必要があります。
java.awt.Frame
のインスタンスを生成するFrame
にアプレットのインスタンスをadd()
するinit(), start()
させるFrame
の幅、高さをsetSize()
するFrame
をshow()
する
Java 3Dにはこのような処理のための便利なクラスが用意されています。
com.sun.j3d.utils.applet.MainFrame
クラスです。
com.sun.j3d.utils.applet.MainFrame
クラスの場合、必要な処理はコンストラクターの引数にアプレットのインスタンスとFrameのサイズを指定するだけです。
FirstApplet.java1 // Java 3Dテスト用アプレット 2 // FirstApplet.java 3 4 import java.applet.*; 5 import com.sun.j3d.utils.applet.MainFrame;...(1) 6 7 public class FirstApplet extends Applet { 8 public FirstApplet() { 9 } 10 11 public static void main(String[] args) { 12 FirstApplet applet = new FirstApplet(); .............(2) 13 MainFrame frame = new MainFrame(applet, 500, 500);...(3) 14 } 15 }
(1)でMainFrame
クラスのimport
宣言を行っています。
main()
メソッドの中では、まず(2)でこのアプレット自身のインスタンスを生成しています。
(3)でcom.sun.j3d.utils.applet.MainFrame
クラスのインスタンスを生成し、そのコンストラクターの引数としてFirstApplet
アプレットのインスタンスとアプレットの幅、高さを与えています。
MainFrame
にはいくつかコンストラクターがありますが、今回使ったものは次の仕様のものです。
public MainFrame(java.applet.Applet applet, // MainFrameに表示したいアプレットのインスタンス int width, // アプレットの幅 int height) // アプレットの高さ
このアプレットをJavaアプリケーションとして実行してみます。
>java FirstApptet
MainFrameはjava.awt.Frameのサブクラスです。
クラス継承 java.lang.Object | +--java.awt.Component | +--java.awt.Container | +--java.awt.Window | +--java.awt.Frame | +--com.sun.j3d.utils.applet.MainFrame クラス宣言 public class MainFrame extends java.awt.Frame implements java.lang.Runnable, java.applet.AppletStub, java.applet.AppletContext コンストラクター public MainFrame(java.applet.Applet applet, // アプレットのインスタンス java.lang.String[] args, // アプレットパラメーター int width, // 幅 int height) // 高さ public MainFrame(java.applet.Applet applet, // アプレットのインスタンス java.lang.String[] args) // アプレットパラメーター public MainFrame(java.applet.Applet applet, // アプレットのインスタンス int width, // 幅 int height) // 高さ
今までは通常のアプレットでした。これから少しずつJava 3Dの描画を追加していきます。
通常のJavaプログラムではjava.awt.Canvas
を描画に使用しますが、Java 3Dでの描画にはjavax.media.j3d.Canvas3D
オブジェクトを使用します。
javax.media.j3d.Canvas3D
はjava.awt.Canvas
のサブクラスです。
クラス継承 java.lang.Object | +--java.awt.Component | +--java.awt.Canvas | +--javax.media.j3d.Canvas3D クラス宣言 public class Canvas3D extends java.awt.Canvas
Canvas3D
のコンストラクターは以下の通りです。
public Canvas3D(java.awt.GraphicsConfiguration graphicsConfiguration)
引数はjava.awt.GraphicsConfiguration
です。これは、現在のスクリーン解像度や色の数などのグラフィック・ディバイスの状況を抽象化したオブジェクトです。
この引数がnull
の場合、javax.media.j3d.GraphicsConfigTemplate3D
オブジェクトの初期値の状態のGraphicsConfiguration
が使用されます。
(Java 3DTM API Specification 8.9 "The Canvas3D Object", 8.9.3 "GraphicsConfig-Temp-late-3D Object" 参照)
Canvas3D
をFirstApplet
に追加してみます。
FirstApplet.java1 // Java 3Dテスト用アプレット 2 // FirstApplet.java 3 4 import java.applet.*; 5 import java.awt.*;..........(1) 6 import javax.media.j3d.*;...(2) 7 import com.sun.j3d.utils.applet.MainFrame; 8 9 public class FirstApplet extends Applet { 10 public FirstApplet() { 11 Canvas3D canvas = new Canvas3D(null);....(3) 12 this.setLayout(new BorderLayout());......(4) 13 this.add(canvas, BorderLayout.CENTER);...(5) 14 } 15 16 public static void main(String[] args) { 17 FirstApplet applet = new FirstApplet(); 18 MainFrame frame = new MainFrame(applet, 500, 500); 19 } 20 }
(1)ではレイアウトマネジャーjava.awt.BorderLayout
を使うためにjava.awt
パッケージのimport
宣言を行っています。
(2)ではCanvas3D
を使うためにjavax.media.j3d
パッケージのimport
宣言を行っています。
(3)ではCanvas3D
のインスタンスを生成しています。
引数はnull
にしたので、GraphicsConfiguration
はデフォルトのものが使われます。
(4)ではBorderLayout
のインスタンスを生成し、このアプレットのレイアウトマネジャーとしてsetLayout()
しています。
(5)ではCanvas3D
をこのアプレットにadd()
しています。
レイアウトマネジャーでの配置条件としてBorderLayout.CENTER
を指定しているので、Canvas3D
は中央に配置されます。この場合、他にComponent
が存在しないのでCanvas3D
はアプレットいっぱいに表示されます。
Canvas3D
を追加したアプレットを実行してみます。
>java FirstApptet
Canvas3D
の追加前と特に変化はありません。
Java 3Dでの描画では、まずjavax.media.j3d.VirtualUniverse
オブジェクトを生成する必要があります。
VirtualUniverse
オブジェクトは、Java 3Dのシーン・グラフのすべての根(root)となる唯一のオブジェクトです。
VirtualUniverse
の生成
次に、VirtualUniverse
を親オブジェクトとするjavax.media.j3d.Locale
オブジェクトを生成する必要があります。
Locale
オブジェクトは、VirtualUniverse
オブジェクトのインスタンスをそのコンストラクターの引数にとります。
public Locale(VirtualUniverse universe)
Locale
の生成
生成されたLocale
オブジェクトの座標はX = 0, Y = 0, Z = 0 (0, 0, 0)
です。
Locale
オブジェクトの座標系は256ビット固定小数点座標です。
Locale
オブジェクトには、256ビット固定小数点でその座標を指定するコンストラクターも用意されています。
public Locale(VirtualUniverse universe, // 親となるVirtuualUniverseオブジェクト int[] x, // X座標を示す、要素数8のint配列 int[] y, // Y座標を示す、要素数8のint配列 int[] z) // Z座標を示す、要素数8のint配列 public Locale(VirtualUniverse universe, // 親となるVirtuualUniverseオブジェクト HiResCoord hiRes) // このLocaleの座標となるjavax.media.j3d.HiResCoordオブジェクト
これらのコンストラクターを使えば、仮想空間の任意の位置の座標を指定してLocale
オブジェクトを生成することができます。
Locale
オブジェクトには、2つの系統のツリーを追加する必要があります。
ひとつは物体側のツリーです。自分で定義した多角形や、あらかじめJava 3Dで定義されている球体や立方体などの目に見える物体をJavaオブジェクトとして生成し、ツリー構造に構築して行きます。
一方、物体を見ている側の、目、耳などの身体、視点、スクリーンやグラフィックス装置などの「見る側」をJavaオブジェクトとして生成し、ツリー構造に構築したものが必要になります。
こちらを「View側のツリー」と呼ぶことにします。
このVirtualUniverse, Locale
の生成と、View側のツリー構築をしてくれる便利なオブジェクトがあります。
com.sun.j3d.utils.universe.SimpleUniverse
オブジェクトです。
SimpleUniverse
はVirtualUniverse
のサブクラスです。
クラス継承 java.lang.Object | +--javax.media.j3d.VirtualUniverse | +--com.sun.j3d.utils.universe.SimpleUniverse クラス宣言 public class SimpleUniverse extends VirtualUniverse
FirstApplet
にSimpleUniverse
を追加してみましょう。
FirstApplet.java1 // Java 3Dテスト用アプレット 2 // FirstApplet.java 3 4 import java.applet.*; 5 import java.awt.*; 6 import javax.media.j3d.*; 7 import com.sun.j3d.utils.applet.MainFrame; 8 import com.sun.j3d.utils.universe.SimpleUniverse;...(1) 9 10 public class FirstApplet extends Applet { 11 public FirstApplet() { 12 Canvas3D canvas = new Canvas3D(null); 13 this.setLayout(new BorderLayout()); 14 this.add(canvas, BorderLayout.CENTER); 15 16 SimpleUniverse universe = new SimpleUniverse(canvas);...(2) 17 } 18 19 public static void main(String[] args) { 20 FirstApplet applet = new FirstApplet(); 21 MainFrame frame = new MainFrame(applet, 500, 500); 22 } 23 }
(1)でSimpleUniverse
のimport
を宣言しています。
(2)でSimpleUniverse
のインスタンスを生成しています。
引数はCanvas3D
オブジェクトです。
ここで使用したSimpleUniverse
のコンストラクターは次の通りです。
public SimpleUniverse(Canvas3D canvas)
SimpleUniverse
を追加したアプレットを実行してみます。
>java FirstApptet
背景が黒く塗りつぶされています。
SimpleUniverse
の背景色の初期値は黒です。
SimpleUniverse
には便利なメソッドがあります。
Canvas3D
の生成のとき、コンストラクターの引数のjava.awt.GraphicsConfiguration
はnull
にしました。
SimpleUniverse
にはシステムが持つ適切なGraphicsConfiguration
を取得するメソッドがあります。
public static java.awt.GraphicsConfiguration getPreferredConfiguration()
static
が指定されていることで分かるように、getPreferredConfiguration()
はクラスメソッドです。
このメソッドを使ってGraphicsConfiguration
オブジェクトを取得し、それを引数にCanvas3D
を生成するように書き換えて見ましょう。
FirstApplet.java1 // Java 3Dテスト用アプレット 2 // FirstApplet.java 3 4 import java.applet.*; 5 import java.awt.*; 6 import javax.media.j3d.*; 7 import com.sun.j3d.utils.applet.MainFrame; 8 import com.sun.j3d.utils.universe.SimpleUniverse; 9 10 public class FirstApplet extends Applet { 11 public FirstApplet() { 12 GraphicsConfiguration config = 13 SimpleUniverse.getPreferredConfiguration();...(1) 14 Canvas3D canvas = new Canvas3D(config);.........(2) 15 this.setLayout(new BorderLayout()); 16 this.add(canvas, BorderLayout.CENTER); 17 18 SimpleUniverse universe = new SimpleUniverse(canvas); 19 } 20 21 public static void main(String[] args) { 22 FirstApplet applet = new FirstApplet(); 23 MainFrame frame = new MainFrame(applet, 500, 500); 24 } 25 }
(1)でGraphicsConfiguration
オブジェクトを取得しています。
取得したGraphicsConfiguration
オブジェクトを引数にして、(2)でCanvas3D
オブジェクトを生成しています。
実行結果は同じなので省略します。
SimpleUniverse
を追加することでView側のツリーは構築できました。
ビジュアル・オブジェクトのツリーを構築するためにまず必要となるものは何でしょうか。
それがjavax.media.j3d.BranchGroup
オブジェクトです。
BranchGroup
オブジェクトはjavax.media.j3d.Group
のサブクラスです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Group | +--javax.media.j3d.BranchGroup クラス宣言 public class BranchGroup extends Group
シーン・グラフを構成するオブジェクトは大きく2つに分かれます。
一つはGroup (javax.media.j3d.Group)
オブジェクトです。
Group
オブジェクトはaddChild(javax.media.j3d.Node child)
メソッドを持ち、javax.media.j3d.Node
(とそのサブクラス)を“子供”として保持することができます。
Group
オブジェクトにはBranchGroup
のほかにjavax.media.j3d.TransformGroup, javax.media.j3d.Switch, javax.media.j3d.OrderedGroup
などがあります。
もう一つはLeaf (javax.media.j3d.Leaf)
オブジェクトです。
Leaf
オブジェクトは他のjavax.media.j3d.Node
オブジェクトを“子供”として保持することはできません。
Leaf
オブジェクトにはjavax.media.j3d.Shape3D
などがあります。
BranchGroup
をSimpleUniverse
に追加するために、SimpleUniverse
にはaddBcanchGraph(javax.media.j3d.BranchGroup)
メソッドがあります。
public void addBranchGraph(BranchGroup bg)
ではFirstApplet
にBranchGroup
を加えてみましょう。
FirstApplet.java1 // Java 3Dテスト用アプレット 2 // FirstApplet.java 3 4 import java.applet.*; 5 import java.awt.*; 6 import javax.media.j3d.*; 7 import com.sun.j3d.utils.applet.MainFrame; 8 import com.sun.j3d.utils.universe.SimpleUniverse; 9 10 public class FirstApplet extends Applet { 11 public FirstApplet() { 12 GraphicsConfiguration config = 13 SimpleUniverse.getPreferredConfiguration(); 14 Canvas3D canvas = new Canvas3D(config); 15 this.setLayout(new BorderLayout()); 16 this.add(canvas, BorderLayout.CENTER) 17 18 SimpleUniverse universe = new SimpleUniverse(canvas); 19 20 BranchGroup scene = new BranchGroup();...(1) 21 22 universe.addBranchGraph(scene);..........(2) 23 } 24 25 public static void main(String[] args) { 26 FirstApplet applet = new FirstApplet(); 27 MainFrame frame = new MainFrame(applet, 500, 500); 28 } 29 }
(1)でBranchGroup
のインスタンスを生成しています。
生成したBranchGroup
のインスタンスを、(2)でSimpleUniverse
にaddBcanchGraph()
しています。
これから追加する描画処理は、すべてこのBranchGroup
にaddChild()
していくことになります。
今後描画処理が増えていくことを考慮して、BranchGroup
の生成とシーン・グラフ構築の部分をコンストラクターとは別のメソッドとして独立させることにします。
これをcreateSceneGraph()
メソッドとしてまとめてみます。
FirstApplet.java1 // Java 3Dテスト用アプレット 2 // FirstApplet.java 3 4 import java.applet.*; 5 import java.awt.*; 6 import javax.media.j3d.*; 7 import com.sun.j3d.utils.applet.MainFrame; 8 import com.sun.j3d.utils.universe.SimpleUniverse; 9 10 public class FirstApplet extends Applet { 11 public FirstApplet() { 12 GraphicsConfiguration config = 13 SimpleUniverse.getPreferredConfiguration(); 14 Canvas3D canvas = new Canvas3D(config); 15 this.setLayout(new BorderLayout()); 16 this.add(canvas, BorderLayout.CENTER); 17 18 SimpleUniverse universe = new SimpleUniverse(canvas); 19 20 BranchGroup scene = createSceneGraph(); 21 22 universe.addBranchGraph(scene); 23 } 24 25 private BranchGroup createSceneGraph() {...(1) 26 BranchGroup root = new BranchGroup();....(2) 27 28 return root;.............................(3) 29 } 30 31 public static void main(String[] args) { 32 FirstApplet applet = new FirstApplet(); 33 MainFrame frame = new MainFrame(applet, 500, 500); 34 } 35 }
(1)からcreateSceneGraph()
メソッドの定義が始まります。
引数は無し、戻り値はBranchGroup
のインスタンスです。
(2)でBranchGroup
のインスタンスを生成し、(3)でそのインスタンスを戻り値としてreturn
しているだけです。
今後、描画処理を追加する場合、この(2)と(3)の間に追加していくことになります。
BranchGroup
をaddBranchGraph()
したあとのシーン・グラフは次のようになります。
ではFirstApplet
を実行してみましょう。
>java FirstApplet
描画処理を何も追加していないので特に変化はありません。
このアプレットに目に見える物体を追加してみましょう。
Java 3Dにはいくつかのオブジェクトがテストのために用意されています。
そうしたオブジェクトのうち、ここではcom.sun.j3d.utils.geometry.ColorCube
を使ってみます。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Leaf | +--javax.media.j3d.Shape3D | +--com.sun.j3d.utils.geometry.ColorCube クラス宣言 public class ColorCube extends Shape3D
ColorCube
は各面の色が違う立方体です。
ColorCube
はテスト用に作られたサンプルです。
実用的価値(?)は特にありません。
FirstApplet.java1 // Java 3Dテスト用アプレット 2 // FirstApplet.java 3 4 import java.applet.*; 5 import java.awt.*; 6 import javax.media.j3d.*; 7 import com.sun.j3d.utils.applet.MainFrame; 8 import com.sun.j3d.utils.universe.SimpleUniverse; 9 import com.sun.j3d.utils.geometry.ColorCube; 10 11 public class FirstApplet extends Applet { 12 public FirstApplet() { 13 GraphicsConfiguration config = 14 SimpleUniverse.getPreferredConfiguration(); 15 Canvas3D canvas = new Canvas3D(config); 16 this.setLayout(new BorderLayout()); 17 this.add(canvas, BorderLayout.CENTER); 18 19 SimpleUniverse universe = new SimpleUniverse(canvas); 20 21 BranchGroup scene = createSceneGraph(); 22 23 universe.addBranchGraph(scene); 24 } 25 26 private BranchGroup createSceneGraph() { 27 BranchGroup root = new BranchGroup(); 28 29 root.addChild(new ColorCube(0.4));...(1) 30 31 return root; 32 } 33 34 public static void main(String[] args) { 35 FirstApplet applet = new FirstApplet(); 36 MainFrame frame = new MainFrame(applet, 500, 500); 37 } 38 }
(1)でColorCube
のインスタンスを生成し、BranchGroup
にaddChild()
しています。
ColorCube
のコンストラクターの引数は、ColorCube
の大きさです。
この場合、ColorCube
は原点(0, 0, 0)を中心にX, Y, Z各軸に0.4の大きさを持つ立方体になります。
ここで使用したColorCube
のコンストラクターは以下の通りです。
public ColorCube(double scale)
ではFirstApplet
を実行してみましょう。
>java FirstApplet
相変わらず何も表示されませんね。
実はこれは視点位置が原点(0, 0, 0)にあるために、ColorCube
と重なっていて何も見えないのです。
ColorCube
が見えるように、視点を適当な位置に移動するコードを追加してみます。
FirstApplet.java1 // Java 3Dテスト用アプレット 2 // FirstApplet.java 3 4 import java.applet.*; 5 import java.awt.*; 6 import javax.media.j3d.*; 7 import com.sun.j3d.utils.applet.MainFrame; 8 import com.sun.j3d.utils.universe.SimpleUniverse; 9 import com.sun.j3d.utils.geometry.ColorCube; 10 11 public class FirstApplet extends Applet { 12 public FirstApplet() { 13 GraphicsConfiguration config = 14 SimpleUniverse.getPreferredConfiguration(); 15 Canvas3D canvas = new Canvas3D(config); 16 this.setLayout(new BorderLayout()); 17 this.add(canvas, BorderLayout.CENTER); 18 19 SimpleUniverse universe = new SimpleUniverse(canvas); 20 universe.getViewingPlatform().setNominalViewingTransform();...(1) 21 22 BranchGroup scene = createSceneGraph(); 23 24 universe.addBranchGraph(scene); 25 } 26 27 private BranchGroup createSceneGraph() { 28 BranchGroup root = new BranchGroup(); 29 30 root.addChild(new ColorCube(0.4)); 31 32 return root; 33 } 34 35 public static void main(String[] args) { 36 FirstApplet applet = new FirstApplet(); 37 MainFrame frame = new MainFrame(applet, 500, 500); 38 } 39 }
(1)でSimpleUniverse
のgetViewingPlatform()
メソッドを使って、com.sun.j3d.utils.universe.ViewingPlatform
オブジェクトを取得しています。
ViewingPlatform
オブジェクトは視点を適当な位置に移動するメソッドを持っています。
public void setNominalViewingTransform()
setNominalViewingTransform()
メソッドは視点位置をZ軸方向に約2.41移動させます。
ではFirstApplet
を実行してみましょう。
>java FirstApplet
ColorCube
の視点に近い面が見えるようになりました。
ColorCube
を追加したことで、シーングラフは次のようになりました。
ColorCube
のほかの面を見るためには、ColorCube
を移動したり回転させたりする必要があります。
移動、回転、拡大縮小などの効果については後に解説します。
com.sun.j3d.utils.geometry
パッケージにはColorCube
のほかにもいくつかのオブジェクトが定義されています。
クラス名 | 説明 | サンプル |
---|---|---|
Box | 直方体 | |
ColorCube | 各面に色のついた立方体 | |
Cone | 円錐 | |
Cylinder | 円柱 | |
Sphere | 球体 |
ColorCube
以外のオブジェクトは、照明されないとうまく表示できません。
Java 3Dでの照明の方法については後に説明します。
はじめに紹介した地球のアプレットは、com.sun.j3d.utils.geometry.Sphere
オブジェクトに地球の表面のグラフィックをテクスチャー・マッピングしたものです。
テクスチャー・マッピングとは、3次元のオブジェクトの表面に2次元のグラフィックを貼り付けたような効果が得られる技法のことです。
テクスチャー (JPEGファイル) | テクスチャー・マッピングしたサンプル |
---|---|
テクスチャー・マッピングについても後に解説します。
今までのアプレットではColorCube
の赤い面しか見えませんでした。
他の面も見えるように、ColorCude
を回転させるにはどうしたら良いでしょうか。
このような回転、移動、拡大縮小などの操作のためのオブジェクトがjavax.media.j3d.TransformGroup
オブジェクトです。
TransformGroup
はjavax.media.j3d.Group
のサブクラスです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Group | +--javax.media.j3d.TransformGroup クラス宣言 public class TransformGroup extends Group コンストラクター (一部) public TransformGroup()
Group
のサブクラスなので、BranchGroup
などと同じくaddChild()
メソッドを持ち、javax.media.j3d.Node
オブジェクトのサブクラスを“子供”として保持することができます。
回転(Rotation)、移動(Translation)、拡大縮小(Scaling)などの操作を総称して「変換」(Transform)と呼びます。
TransformGroup
に適用した変換操作は、TransformGroup
に addChild()
されたすべてのノードに対して適用されます。
FirstApplet
にTransformGroup
を加えてみましょう。
FirstApplet.java1 // Java 3Dテスト用アプレット 2 // FirstApplet.java 3 4 import java.applet.*; 5 import java.awt.*; 6 import javax.media.j3d.*; 7 import com.sun.j3d.utils.applet.MainFrame; 8 import com.sun.j3d.utils.universe.SimpleUniverse; 9 import com.sun.j3d.utils.geometry.ColorCube; 10 11 public class FirstApplet extends Applet { 12 public FirstApplet() { 13 GraphicsConfiguration config = 14 SimpleUniverse.getPreferredConfiguration(); 15 Canvas3D canvas = new Canvas3D(config); 16 this.setLayout(new BorderLayout()); 17 this.add(canvas, BorderLayout.CENTER); 18 19 SimpleUniverse universe = new SimpleUniverse(canvas); 20 universe.getViewingPlatform().setNominalViewingTransform(); 21 22 BranchGroup scene = createSceneGraph(); 23 24 universe.addBranchGraph(scene); 25 } 26 27 private BranchGroup createSceneGraph() { 28 BranchGroup root = new BranchGroup(); 29 30 TransformGroup trans = new TransformGroup();...(1) 31 trans.addChild(new ColorCube(0.4));............(2) 32 33 root.addChild(trans);..........................(3) 34 35 return root; 36 } 37 38 public static void main(String[] args) { 39 FirstApplet applet = new FirstApplet(); 40 MainFrame frame = new MainFrame(applet, 500, 500); 41 } 42 }
(1)でTransformGroup
のインスタンスを生成しています。
(2)でColorCube
のインスタンスを生成し、BranchGroup
ではなくTransformGroup
にaddChild()
しています。
(3)ではTransformGroup
をBranchGroup
にaddChild()
しています。
TransformGroup
を追加したことで、シーン・グラフは次のようになります。
まだ回転などの効果を加えていないので、実行結果は前と変わりません。
回転、移動、拡大縮小などの効果はTransformGroup
に対して直接適用することはできません。
TransformGroup
はjavax.media.j3d.Transform3D
オブジェクトのインスタンスを保持しています。
回転、移動、拡大縮小などはこのTransform3D
に対して適用することになります。
Transform3D
はjava.lang.Object
の直接のサブクラスです。
クラス継承 java.lang.Object | +--javax.media.j3d.Transform3D クラス宣言 public class Transform3D extends java.lang.Object コンストラクター (一部) public Transform3D()
Transform3D
には回転、移動、拡大縮小のために次のようなメソッドが用意されています。
public void rotX(double angle) X軸を回転軸にしてangle(単位:ラジアン)だけ回転します。 回転以外の操作(拡大縮小、移動)はリセットされます。 public void rotY(double angle) Y軸を回転軸にしてangle(単位:ラジアン)だけ回転します。 回転以外の操作(拡大縮小、移動)はリセットされます。 public void rotZ(double angle) Z軸を回転軸にしてangle(単位:ラジアン)だけ回転します。 回転以外の操作(拡大縮小、移動)はリセットされます。 public final void setRotation(javax.vecmath.AxisAngle4d a1) javax.vecmath.AxisAngle4d で指定されたベクトルを回転軸にして AxisAngle4d で指定された角度(単位:ラジアン)だけ回転します。 AxisAngle4dは次のようなコンストラクターを持つオブジェクトです。 public AxisAngle4d(double x, // 回転軸ベクトルのX成分 double y, // 回転軸ベクトルのY成分 double z, // 回転軸ベクトルのZ成分 double angle) // 回転角(ラジアン) public final void setRotation(javax.vecmath.AxisAngle4f a1) javax.vecmath.AxisAngle4f で指定された軸を回転軸にして AxisAngle4f で指定された角度(単位:ラジアン)だけ回転します。 AxisAngle4fは次のようなコンストラクターを持つオブジェクトです。 public AxisAngle4f(float x, // 回転軸ベクトルのX成分 float y, // 回転軸ベクトルのY成分 float z, // 回転軸ベクトルのZ成分 float angle) // 回転角(ラジアン) public final void setTranslation(javax.vecmath.Vector3d trans) javax.vecmath.Vertor3d で指定された座標に移動します。 Vector3dは次のようなコンストラクターを持つオブジェクトです。 public Vector3d(double x, // X座標 double y, // Y座標 double z) // Z座標 public final void setTranslation(javax.vecmath.Vector3f trans) javax.vecmath.Vertor3d で指定された座標に移動します。 Vector3fは次のようなコンストラクターを持つオブジェクトです。 public Vector3f(float x, // X座標 float y, // Y座標 float z) // Z座標 public final void setScale(double scale) scaleだけ拡大縮小します。1より大きい値は拡大、1より小さい値のときは縮小します。 public final void setScale(javax.vecmath.Vector3d scale) javax.vecmath.Vector3d で指定されたX, Y, Z各軸の倍率で拡大縮小します。 1より大きい値は拡大、1より小さい値のときは縮小します。
Transform3D
には、上記以外にも座標変換のためのメソッドが数多く定義されています。
Transform3D
を使ってColorCube
を回転させてみましょう。
FirstApplet.java (一部)27 private BranchGroup createSceneGraph() { 28 BranchGroup root = new BranchGroup(); 29 30 Transform3D t3d = new Transform3D();..............(1) 31 t3d.rotY(Math.PI / 4.0);..........................(2) 32 33 TransformGroup trans = new TransformGroup(t3d);...(3) 34 35 trans.addChild(new ColorCube(0.4)); 36 37 root.addChild(trans); 38 39 return root; 40 } 41 42 public static void main(String[] args) { 43 FirstApplet applet = new FirstApplet(); 44 MainFrame frame = new MainFrame(applet, 500, 500); 45 } 46 }
(1)でTransform3D
のインスタンスを生成しています。
(2)でTransform3D
のrotY()
メソッドを使って、Y軸を回転軸にしてπ/4ラジアンだけ回転しています。
(3)でTransformGroup
のインスタンスを生成していますが、このときTransform3D
を引数にしています。
TransformGroup
のコンストラクターにはTransform3D
を引数にするものもあります。
public TransformGroup(Transform3D t1)
このコンストラクターで生成されたTransformGroup
には、引数のTransform3D
の座標変換が適用されます。
FirstApplet
を実行してみましょう。
>java FirstApplet
Y軸を回転軸にπ/4ラジアン回転したので、黄色い面が見えています。
回転方向はどのように考えれば良いのでしょうか。
回転方向を考えるとき重要なのは、回転軸のベクトルの向きです。
回転軸ベクトルの向きに、右ねじを回転させるところを想像してください。
このときの右ねじが回転する方向がTransform3D
の回転メソッドの回転方向になります。
このサンプルではY軸を回転軸にπ/4ラジアン回転させているので、赤い面の左側にあった黄色い面が見えています。
ここで重要なのは、Y軸を中心にして X軸、Z軸も回転している、という点です。
この図は斜め上から見ています。Y軸を中心に X,Z軸も回転しています。
たとえば、この後さらにrotX()
で回転させるとします。すでに回転した座標系のX軸を中心に回転することになります。
ColorCube
をX軸でも回転させてみましょう。
27 private BranchGroup createSceneGraph() { 28 BranchGroup root = new BranchGroup(); 29 30 Transform3D t3d = new Transform3D(); 31 t3d.rotY(Math.PI / 4.0); 32 t3d.rotX(Math.PI / 4.0);...(1) 33 34 TransformGroup trans = new TransformGroup(t3d); 35 36 trans.addChild(new ColorCube(0.4)); 37 38 root.addChild(trans); 39 40 return root; 41 }
(1)でX軸を回転軸にπ/4ラジアン回転しています。
ではFirstApplet
を実行してみましょう。
>java FirstApplet
最後に適用したX軸の回転しか有効になっていません。
rotX(), rotY(), rotZ()
による回転は、
それ以前に適用された回転操作を無効にします。
もしいくつかの変換操作を重ねて適用したければ、Transform3D
のmul()
メソッドを使って効果を乗算する必要があります。
public final void mul(double scalar) mul()を適用したTransform3DのX,Y,Z各軸に対して、 scalerだけ拡大縮小の効果が乗算されます。 public final void mul(double scalar, Transform3D t1) t1のX,Y,Z各軸に対してscalerだけ拡大縮小されたものが、 mul()を適用したTransform3Dにセットされます。 t1は変化しません。 public final void mul(Transform3D t1) mul()を適用したTransform3Dとt1を乗算したものが、 mul()を適用したTransform3Dにセットされます。 t1は変化しません。 public final void mul(Transform3D t1, Transform3D t2) t1, t2を乗算したものが、 mul()を適用したTransform3Dにセットされます。 t1, t2は変化しません。
mul()
メソッドを使って書き直してみましょう。
27 private BranchGroup createSceneGraph() { 28 BranchGroup root = new BranchGroup(); 29 30 Transform3D t3d = new Transform3D(); 31 t3d.rotY(Math.PI / 4.0); 32 33 Transform3D rotateX = new Transform3D();..........(1) 34 rotateX.rotX(Math.PI / 4.0);......................(2) 35 36 t3d.mul(rotateX);.................................(3) 37 38 TransformGroup trans = new TransformGroup(t3d);...(4) 39 40 trans.addChild(new ColorCube(0.4)); 41 42 root.addChild(trans); 43 44 return root; 45 }
(1)でX軸の回転のためのTransform3D
オブジェクトのインスタンスを生成しています。
(2)でrotX()
メソッドを使って、X軸を回転軸にしてπ/4だけ回転しています。
(3)でt3d
に対して、mul()
メソッドを使ってrotateX
に加えたX軸の回転を乗算しています。
(4)でY軸, X軸の回転が乗算されたTransform3D
をTransformGroup
にsetTransform()
しています。
FirstApplet
を実行してみましょう。
>java FirstApplet
rotY()
メソッドが実行されると、Y軸を回転軸にしてπ/4ラジアン回転しています。
この時点でX軸、Z軸もπ/4ラジアン回転していることに注意してください。
次にrotX()
メソッドが実行され、X軸を回転軸にしてπ/4だけ回転しています。
rotY()
とrotX()
の順序を逆にすると、これと違った結果が得られます。
FirstApplet.java (一部)27 private BranchGroup createSceneGraph() { 28 BranchGroup root = new BranchGroup(); 29 30 Transform3D t3d = new Transform3D(); 31 t3d.rotX(Math.PI / 4.0);.................(1) 32 33 Transform3D rotateY = new Transform3D(); 34 rotateY.rotY(Math.PI / 4.0); 35 36 t3d.mul(rotateY);........................(2) 37 38 TransformGroup trans = new TransformGroup(t3d); 39 40 trans.addChild(new ColorCube(0.4)); 41 42 root.addChild(trans); 43 44 return root; 45 }
(1)でrotX()
メソッドが実行され、X軸を回転軸にしてπ/4ラジアン回転します。
(2)でrotateY
が乗算されていますが、t3d
にはすでにrotX()
による回転が適用されています。
つまり、すでに傾いているY軸を回転軸にして、π/4だけ回転することになります。
実行結果は次のようになります。
Transform3D
にはrotX(), rotY() rotZ()
以外にも回転のためのメソッドがあります。
setRotation(AxisAngle4d)
メソッドは任意の軸を回転軸にして回転ができます。
FirstApplet.java (一部)28 private BranchGroup createSceneGraph() { 29 BranchGroup root = new BranchGroup(); 30 31 Transform3D t3d = new Transform3D(); 32 t3d.setRotation(new AxisAngle4d(0.57, 0.57, -0.57, Math.PI / 4.0));...(1) 33 34 TransformGroup trans = new TransformGroup(t3d); 35 36 trans.addChild(new ColorCube(0.4)); 37 38 root.addChild(trans); 39 40 return root; 41 }
(1)でjavax.vecmath.AxisAngle4d
のインスタンスを生成しています。
AxisAngle4d
のコンストラクターでは、X = 0.57, Y = 0.57, Z = -0.57のベクトルを回転軸に、π/4ラジアン回転するように指定しています。
このAxisAngle4d
のインスタンスを引数にして、Transform3D
のsetRotation()
を使って回転させています。
この実行結果は次のようになります。
移動はTransform3D
のsetTranslation()
メソッドを使用します。
FirstApplet.java (一部)28 private BranchGroup createSceneGraph() { 29 BranchGroup root = new BranchGroup(); 30 31 Transform3D t3d = new Transform3D(); 32 t3d.setTranslation(new Vector3d(0.0, 0.4, 0.0));........(1) 33 34 Transform3D rotation = new Transform3D(); 35 36 rotation.setRotation( 37 new AxisAngle4d(0.57, 0.57, -0.57, Math.PI / 4.0));...(2) 38 39 t3d.mul(rotation);......................................(3) 40 41 TransformGroup trans = new TransformGroup(t3d); 42 43 trans.addChild(new ColorCube(0.4)); 44 45 root.addChild(trans); 46 47 return root; 48 } 49 50 public static void main(String[] args) { 51 FirstApplet applet = new FirstApplet(); 52 MainFrame frame = new MainFrame(applet, 500, 500); 53 } 54 }
(1)でjavax.vecmath.Vector3d
オブジェクトのインスタンスを生成しています。
コンストラクターの引数はX = 0.0, Y = 0.4, Z = 0.0
で、Y方向に0.4移動させています。
生成したVector3d
のインスタンスを引数にしてTransform3D
のsetTranslation()
を呼んでいます。
(2)で回転を加えています。
(3)で移動に回転を乗算しています。
この実行結果は次のようになります。
ここでは示しませんが、移動と回転の順序を逆にすると、回転した軸に沿って移動します。
X, Y, Zすべての軸に対して同じ倍率で拡大縮小するには、Transform3D
のsetScale(double scale)
を使用します。
X, Y, Z各軸に異なった倍率を適用したい場合はsetScale(Vector3d scale)
メソッドを使用します。
FirstApplet.java (一部)28 private BranchGroup createSceneGraph() { 29 BranchGroup root = new BranchGroup(); 30 31 Transform3D t3d = new Transform3D(); 32 t3d.setRotation( 33 new AxisAngle4d(0.57, 0.57, -0.57, Math.PI / 4.0)); 34 35 Transform3D scaling = new Transform3D();.........(1) 36 scaling.setScale(new Vector3d(0.2, 0.8, 1.8));...(2) 37 38 t3d.mul(scaling);................................(3) 39 40 TransformGroup trans = new TransformGroup(t3d); 41 42 trans.addChild(new ColorCube(0.4)); 43 44 root.addChild(trans); 45 46 return root; 47 }
(1)でjavax.vecmath.Vector3d
のインスタンスを生成しています。
コンストラクターの引数はX = 0.2, Y = 0.8, Z = 1.8
です。それぞれの軸に対してこの倍率が適用されます。
(2)でVector3d
のインスタンスを引数にしてsetScale()
メソッドを呼んでいます。
(3)で回転したTransform3D
に対して拡大縮小の効果を乗算しています。
この実行結果は次のようになります。
回転と拡大縮小の順序を逆にすると、違った結果が得られます。
FirstApplet.java (一部)28 private BranchGroup createSceneGraph() { 29 BranchGroup root = new BranchGroup(); 30 31 Transform3D t3d = new Transform3D(); 32 t3d.setScale(new Vector3d(0.2, 0.8, 1.8));..............(1) 33 34 Transform3D rotation = new Transform3D(); 35 rotation.setRotation( 36 new AxisAngle4d(0.57, 0.57, -0.57, Math.PI / 4.0));...(2) 37 38 t3d.mul(rotation);......................................(3) 39 40 TransformGroup trans = new TransformGroup(t3d); 41 42 trans.addChild(new ColorCube(0.4)); 43 44 root.addChild(trans); 45 46 return root; 47 }
(1)で拡大縮小を行い、(2)で回転を行っています。
(3)ではすでに拡大縮小された軸に対して回転が乗算されます。
このとき各軸のスケールは1:1ではなくなっているために、回転は歪んだかたちで行われます。
この実行結果は次のようになります。
TransformGroup
とTransform3D
を使えば、物体を回転/移動/拡大縮小できることがわかりました。では、マウスをつかってこれらの操作を実現するにはどうしたら良いでしょうか。
Java 3Dには、イベント処理のためのクラスとして javax.media.j3d.Behavior
が用意されています。マウス、キーボードなどによるイベント処理は、Behavior
を継承したクラスを書いて実現します。Behavior
については別項で詳しく説明します。
com.sun.j3d.utils.behaviors.mouse
パッケージでは、マウスによる回転、移動、ズームなどのクラスが提供されています。
回転、移動、ズームなどのクラスは MouseBehavior
クラスを継承しています。MouseBehavior
クラスを継承したクラスを書いて、独自のマウス処理を実現することもできると思います。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Leaf | +--javax.media.j3d.Behavior | +--com.sun.j3d.utils.behaviors.mouse.MouseBehavior | |--com.sun.j3d.utils.behaviors.mouse.MouseRotate // 回転 | |--com.sun.j3d.utils.behaviors.mouse.MouseTranslate // 移動 | +--com.sun.j3d.utils.behaviors.mouse.MouseZoom // ズーム クラス宣言 public abstract class MouseBehavior extends Behavior コンストラクター (一部) public MouseBehavior(TransformGroup transformGroup) // 操作対象の TransformGroup public MouseBehavior(int format) // 起動時の動作オプション 定数フィールド (一部) public static final int MANUAL_WAKEUP // 起動をマニュアルで行う public static final int INVERT_INPUT // Transform を逆転する
TransformGroup
型の引数をとるコンストラクターでは、操作対象となる TransformGroup
を指定して MouseBehavior
を生成します。
int
型の引数をとるコンストラクターでは、動作オプションを指定して MouseBehavior
を生成します。動作オプションには MANUAL_WAKEUP, INVERT_INPUT
があります。
MANUAL_WAKEUP
を指定すると、マウス操作ではなく wakeup()
メソッドを実行して MouseBehavior
を起動します。
INVERT_INPUT
を指定すると、マウスによる操作を逆転することができます。例えば、物体でなく視点を回転/移動させたいときに便利です。
MANUAL_WAKEUP, INVERT_INPUT
の両方を指定したいときは |
演算子 (OR演算子) で OR をとった値を指定します。
MouseBehavior
の使用方法は次のようになります。
TransformGroup
をコンストラクターで指定して MouseBehavior
を生成する。MouseRotate, MouseTranslate, MouseZoom
)setSchedulingBounds()
メソッドで、スケジューリングが有効となる領域 (javax.media.j3d.Bounds
オブジェクト) を設定するaddChild()
するKeyNavigator
の使用方法と良く似ています。ここで重要なのは、MouseBehavior
の適用対象となる TransformGroup
は常に一つである という点です。
MouseBehavior
では複数の物体をそれぞれ別個に操作することはできません。複数の物体を別々に操作したい場合には、後に説明する com.sun.j3d.utils.behaviors.picking
パッケージを使用してください。
では実行結果を見てください。
マウスでのドラッグで地球を回転させたり、移動したり、ズームしたり出来ます。マウス・ドラッグによる操作は、画面内のどの部分をクリックしても開始できます。地球以外の部分をクリックしてドラッグを開始してみてください。
MouseRotate, MouseTranlate, MouseZoom
での操作は次の通りです。
マウスボタン | 操作 |
---|---|
左ドラッグ | 回転 |
中央ドラッグ | ズーム (Z軸方向への移動) |
右ドラッグ | 移動 (X軸、Y軸方向) |
3ボタンマウスでない場合、
マウスボタンのエミュレーションは環境によって異なります。
UNIX 環境では X-Window System でのマウス・エミュレーションに依存します。
Windows
環境ではマウスの左ボタンと同時にキーボードの
[Alt]
キーを押すことで中ボタンをエミュレートできます。
このサンプルのソースは次の通りです。
MouseBehaviorTest.java (一部)34 private BranchGroup createSceneGraph() { 35 BranchGroup root = new BranchGroup(); 36 37 TransformGroup trans = new TransformGroup(); 38 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);--┬(1) 39 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);-┘ 40 41 BoundingSphere bounds = new BoundingSphere(new Point3d(), 100.0);...(2) 42 43 MouseRotate rotator = new MouseRotate(trans);...(3) 44 rotator.setSchedulingBounds(bounds);............(4) 45 root.addChild(rotator);.........................(5) 46 47 MouseTranslate translator = new MouseTranslate(trans);┐ 48 translator.setSchedulingBounds(bounds); ├(6) 49 root.addChild(translator);----------------------------┘ 50 51 MouseZoom zoomer = new MouseZoom(trans);┐ 52 zoomer.setSchedulingBounds(bounds); ├(7) 53 root.addChild(zoomer);------------------┘ 54 55 trans.addChild( new ColorCube(0.4) ); 56 57 root.addChild(trans); 58 59 return root; 60 } 61 62 public static void main(String[] args) { 63 MouseBehaviorTest applet = new MouseBehaviorTest(); 64 Frame frame = new MainFrame(applet, 500, 500); 65 } 66 }
(1)では実行時の Transform3D
の読み取り/書き込みのための capability bit
を設定しています。capability bit
については次の項目で説明します。
(2)ではMouseRotate, MouseTranslate, MouseZoom
に対してスケジューリングが有効になる領域 BoundingSphere
を生成しています。この領域は原点を中心とした半径 100.0
の球の内部になります。領域を定義するためのクラスである BoundingSphere
などについても後で詳しく説明します。
(3)でMouseRotate
を生成しています。適用対象は BranchGroup
直下の TransformGroup
です。(4)でスケジューリング領域を設定し、(5)で addChild()
しています。
MouseRotate
と同様に、(6)で MouseTranslate
、(7)で MouseZoom
に対して生成、適用、BranchGroup
への addChild()
を行っています。
■■capability bit
マウス操作のサンプルでは、setCapability()
メソッドを使って TransformGroup
に ALLOW_TRANSFORM_READ, ALLOW_TRANSFORM_WRITE
という定数値を設定しています。
37 TransformGroup trans = new TransformGroup(); 38 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 39 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
setCapability()
しないとどうなるでしょうか。setCapability()
の行をコメントにして再コンパイルし、サンプルを実行してみます。
$ java MouseBehaviorTest Exception occurred during Behavior execution: javax.media.j3d.CapabilityNotSetException: Group: no capability to get transform at javax.media.j3d.TransformGroup.getTransform(TransformGroup.java:98) at com.sun.j3d.utils.behaviors.mouse.MouseRotate.processStimulus(Compiled Code) at javax.media.j3d.BehaviorScheduler.processBehaviors(Compiled Code) at javax.media.j3d.BehaviorScheduler.run(BehaviorScheduler.java:949)
javax.media.j3d.CapabilityNotSetException
が発生しました。回転/移動/ズームなどの操作は行われませんでした。
Java 3D では、実行時に設定値を変更する場合、事前に読み取り/書き込みを"許可"しなければならない場合があります。このためのメソッドが setCapability()
メソッドです。
setCapability()
メソッドで"許可"される必要のある値が読み取り/書き込みされるとき、capability bit
と呼ばれるビット値が検査されます。
capability bit
を設定しない属性値を実行時に変更することはできません。capability bit
で許可されていない値が読み取り/書き込みされると、javax.media.j3d.CapabilityNotSetException
が発生します。
setCapability()
メソッド)これまで説明したように、Java 3D で設定値を変更する場合、あらかじめ"許可"を与えておかなければならない場合があります。
このためのメソッドが setCapability()
です。
set
は javax.media.SceneGraphObject
のメソッドです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject クラス宣言 public abstract class SceneGraphObject extends java.lang.Object メソッド (一部) public final void setCapability(int bit)
SceneGraphObject
から派生したサブクラスはすべて setCapability()
メソッドを持っています。
実行時に値を読み取り/書き込みする場合、使用するクラスの ALLOW_xxxx
定数フィールドを調べて、適切な capability bit
を設定する必要があります。
javax.media.j3d.Bounds
MouseBehavior
のサンプルでは、MouseBehavior
が作用する領域として BoundingSphere
を指定しました。
Java 3Dには、適用の対象となる領域を設定しないと有効にならないオブジェクトがあります。イベント処理(javax.media.j3d.Behavior
)、照明(javax.media.j3d.Light
)、霧(javax.media.j3d.Fog
)、背景(javax.media.j3d.Background
)などです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Leaf | |--javax.media.j3d.Behavior // イベント処理 | | | +--javax.media.j3d.Interpolator // アニメーションの処理 | |--javax.media.j3d.Light // 照明 | |--javax.media.j3d.Fog // 霧 | +--javax.media.j3d.Background // 背景
これらのオブジェクトに適用対象となる領域を設定するのは、不必要な処理を省いて実行時のパフォーマンスを上げるためです。範囲外のものを描画対象から外し、実行時の処理を軽減します。
また、Java 3Dの物体はそれぞれ領域を持っています。物体どうしが重なっているかどうか、物体が特定の領域に入っているか、マウス位置にある物体は何か、などを物体が占める領域で判定します。
領域クラスは抽象クラス javax.media.j3d.Bounds
を基底クラスとして、箱状の領域(javax.media.j3d.BoundingBox
)、球状の領域(javax.media.j3d.BoundingSphere
)、面で囲まれた閉領域(javax.media.j3d.BoundingPolytope
)などのクラスがあります。
クラス継承 java.lang.Object | +--javax.media.j3d.Bounds // 領域の抽象クラス | +--javax.media.j3d.BoundingBox // 矩形領域 | +--javax.media.j3d.BoundingSphere // 球状の領域 | +--javax.media.j3d.BoundingPolytope // 面で囲まれた閉領域 クラス宣言 public abstract class Bounds extends java.lang.Object implements java.lang.Cloneable
Bounds
はjavax.media.j3d.Node
のサブクラスではありません。したがって、シーングラフに addChild()
されることはありません。
コンストラクター public Bounds()
Bounds
のコンストラクターはデフォルトコンストラクター(引数なしのコンストラクター)だけです。
Bounds
には、他の領域や点、(半)直線との交差を判定するための intersect()
メソッドが用意されています。
メソッド public abstract boolean intersect(Point3d origin, // 通過座標とベクトルで指定した半直線 Vector3d direction) // との交差判定 public abstract boolean intersect(Point3d point) // 点との交差判定 public abstract boolean intersect(Bounds boundsObject) // 他の領域との交差判定 public abstract boolean intersect(Bounds[] boundsObjects) // 他の複数領域との交差判定
例えば「マウスでクリックした座標から画面奥方向に延びる(半)直線」と「物体の領域」との交差を判定できれば、マウスクリックした物体を選択することもできるでしょう。
Bounds
オブジェクトでの領域はローカル座標に従います。たとえば、TransformGroup
にaddChild()
された物体が回転/移動/拡大縮小したとき、Bounds
もその TransformGroup
の回転/移動/拡大縮小に従います。
■■javax.media.j3d.BoundingBox
javax.media.j3d.BoundisgBox
は箱状の領域を定義します。
クラス継承 java.lang.Object | +--javax.media.j3d.Bounds | +--javax.media.j3d.BoundingBox クラス宣言 public class BoundingBox extends Bounds コンストラクター public BoundingBox() public BoundingBox(Point3d lower, // 最も小さい位置座標 Point3d upper) // 最も大きい位置座標 public BoundingBox(Bounds boundsObject) // Bounds オブジェクト public BoundingBox(Bounds[] bounds) // Bounds オブジェクト配列
コンストラクター引数として、最も小さい位置座標と、最も大きい位置座標の2つのPoint3d
を与える場合はどのように考えたら良いでしょうか。
これまでのサンプルの ColorCube
のように、原点を中心に x, y, z
方向それぞれ 0.4
の大きさを持った領域を考えてみます。
x, y, z
それぞれが最も小さい値である座標は (-0.4, -0.4, -0.4)
です。それぞれが最も大きい値である座標は (0.4, 0.4, 0.4)
です。BoundingBox
は、この2点間の箱状の領域になります。
引数なしのコンストラクターで生成した BoundingBox
のデフォルト領域は、最小が (-1.0, -1.0, -1.0)
、最大が (1.0, 1.0, 1.0)
の座標間の箱状の領域です。
他のBounds
オブジェクトや、Bounds
オブジェクト配列を引数に与えるコンストラクターでは、引き数に指定したBounds
オブジェクトを囲むような新たな領域が設定されます。
■■javax.media.j3d.BoundingSphere
javax.media.j3d.BoundingSphere
は中心点と半径を指定して球状の領域を定義します。
クラス継承 java.lang.Object | +--javax.media.j3d.Bounds | +--javax.media.j3d.BoundingSphere クラス宣言 public class BoundingSphere extends Bounds コンストラクター public BoundingSphere() public BoundingSphere(Point3d center, // 球の中心座標 double radius) // 球の半径 public BoundingSphere(Bounds boundsObject) // Bounds オブジェクト public BoundingSphere(Bounds[] boundsObjects) // Bounds オブジェクト配列
引数を2つとるコンストラクターでは、Point3d
で中心座標を、double
で半径を指定して BoundingSphere
を生成します。
引数なしのコンストラクターで生成した BoundingSphere
の領域は、中心が(0.0, 0.0, 0.0)
、半径が 1.0
の球状の領域になります。
BoundingBox
と同様に、他のBounds
オブジェクトや、Bounds
オブジェクト配列を引数に与えるコンストラクターでは、引き数に指定したBounds
オブジェクトを囲むような新たな領域が設定されます。
■■javax.media.j3d.BoundingPolytope
javax.media.j3d.BoundingPolytope
は複数の平面で空間を分割し、その内部の閉じた空間によって領域を定義します。
クラス継承 java.lang.Object | +--javax.media.j3d.Bounds | +--javax.media.j3d.BoundingPolytope クラス宣言 public class BoundingPolytope extends Bounds コンストラクター public BoundingPolytope() public BoundingPolytope(Vector4d[] planes) // 平面方程式の配列 public BoundingPolytope(Bounds boundsObject) // Bounds オブジェクト public BoundingPolytope(Bounds[] boundsObjects) // Bounds オブジェクト配列
平面は Vector4d
を使った平面方程式で定義します。平面方程式は次の通りです。
Ax + By + Cz + D = 0
平面方程式はどのように考えれば良いでしょうか。
平面は、面に垂直なベクトルを使って定義できます。
平面方程式の A, B, C
各係数が、ベクトルの x, y, z
各成分になる、と考えても良いでしょう。
残る項D
はどのように考えたら良いでしょうか。
D
は面から原点(0, 0, 0)
までの距離と考えることができます。ベクトルの正方向がD
の符号の正方向です。
平面方程式の A, B, C, D
をVector4d
の x, y, z, w
各成分に設定します。
クラス継承 java.lang.Object | +--javax.vecmath.Tuple4d | +--javax.vecmath.Vector4d クラス宣言 public class Vector4d extends Tuple4d implements java.io.Serializable コンストラクター (一部) public Vector4d(double x, // x 成分 double y, // y 成分 double z, // z 成分 double w) // w 成分
BoundingPolytope
では、次の式で半空間を定義します。
Ax + By + Cz + D <= 0
無限に広がる空間は図に描けないので、羊羹や豆腐のように切り取った部分空間で図解してみます。
羊羹のような箱型の部分空間を、平面 Ax + By + Cz + D = 0
で切ったらどうなるでしょうか。
式 Ax + By + Cz + D <= 0
で定義された半空間は、切り取った平面を含んで、ベクトルと反対方向に広がる半空間です。図では羊羹の下半分がある半空間です。
残りの半空間 Ax + By + Cz + D > 0
は、平面を含まず、ベクトルと同じ方向に広がる半空間です。図では羊羹の上半分がある半空間です。
引数無しのコンストラクターで生成された BoundingPolytope
には、要素数6のVector4d
配列による平面方程式が設定されます。
Vector4d[] | 平面方程式 | 半空間 Ax+By+Cz+D<=0 |
---|---|---|
planes[0] | (1,0,0,-1) | |
planes[1] | (-1,0,0,-1) | |
planes[2] | (0,1,0,-1) | |
planes[3] | (0,-1,0,-1) | |
planes[4] | (0,0,1,-1) | |
planes[5] | (0,0,-1,-1) |
これは、引数無しのコンストラクターで生成された BoundingBox
と同じ領域です。
BoundingPolytope
では3つ以上の平面で領域を指定します。Vector4d
配列の要素数が3よりも小さいときは java.lang.IllegalArgumentException
が発生します。
BoundingBox, BoundingSphere
と同様に、他のBounds
オブジェクトや、Bounds
オブジェクト配列を引数に与えるコンストラクターでは、引き数に指定したBounds
オブジェクトを囲むような新たな領域が設定されます。
■SmallUniverse
を書いてみるこれまで、View側のツリーを構築するために SimpleUniverse
を使って来ました。では SimpleUniverse
で構築されたView側のツリーとはどのようなものなのでしょうか。
SimpleUniverse
をはじめとする com.sun.j3d.utils.universe
パッケージのソースは公開されていますので、読んでみると参考になると思います。
ここでは SimpleUniverse
の代わりとなる、最も単純なクラスを書いてみます。
SimpleUniverse
の代わりになるようなクラス、SmallUniverse
を書いてみましょう。ソースは次のようになりました。
SmallUniverse.java1 // Java 3D Test Program 2 // SmallUniverse.java 3 // Copyright(c) 1999 ENDO Yasuyuki <yasuyuki@javaopen.org> 4 5 import javax.media.j3d.*; 6 7 public class SmallUniverse { 8 protected VirtualUniverse universe = null; 9 protected Locale locale = null; 10 protected BranchGroup root = null; 11 protected TransformGroup trans = null; 12 protected ViewPlatform vp = null; 13 protected View view = null; 14 protected PhysicalBody body = null; 15 protected PhysicalEnvironment env = null; 16 protected Canvas3D canvas = null; 17 18 public SmallUniverse() { 19 this( new Locale( new VirtualUniverse() ) ); 20 } 21 22 public SmallUniverse(Locale locale) { 23 universe = locale.getVirtualUniverse(); 24 25 this.locale = locale; 26 27 root = new BranchGroup(); 28 root.setCapability(BranchGroup.ALLOW_DETACH); 29 root.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND); 30 31 trans = new TransformGroup(); 32 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 33 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 34 root.addChild(trans); 35 36 vp = new ViewPlatform(); 37 float r = vp.getActivationRadius();//DEBUG 38 System.out.println("r=" + r);//DEBUG 39 trans.addChild(vp); 40 41 view = new View(); 42 view.attachViewPlatform(vp); 43 44 body = new PhysicalBody(); 45 view.setPhysicalBody(body); 46 47 env = new PhysicalEnvironment(); 48 view.setPhysicalEnvironment(env); 49 50 canvas = new Canvas3D(null); 51 view.addCanvas3D(canvas); 52 53 this.locale.addBranchGraph(root); 54 } 55 56 public VirtualUniverse getUniverse() { return universe; } 57 58 public Locale getLocale() { return locale; } 59 //public void setLocale(Locale locale) { this.locale = locale; } 60 61 public BranchGroup getBranchGroup() { return root; } 62 63 public TransformGroup getTransformGroup() { return trans; } 64 65 public void getTransform(Transform3D t3d) { trans.getTransform(t3d); } 66 public void setTransform(Transform3D t3d) { trans.setTransform(t3d); } 67 68 public ViewPlatform getViewPlatform() { return vp; } 69 70 public View getView() { return view; } 71 72 public PhysicalBody getPhysicalBody() { return body; } 73 74 public PhysicalEnvironment getPhysicalEnvironment() { return env; } 75 76 public Canvas3D getCanvas() { return canvas; } 77 //public void setCanvas3D(Canvas3D canvas) { this.canvas = canvas; } 78 79 public void detachBranchGraph() { 80 java.util.Enumeration e = locale.getAllBranchGraphs(); 81 while (e.hasMoreElements()) { 82 BranchGroup g = (BranchGroup)e.nextElement(); 83 if (g == root) locale.removeBranchGraph(root); 84 } 85 } 86 87 public void atachBranchGraph() { 88 java.util.Enumeration e = locale.getAllBranchGraphs(); 89 while (e.hasMoreElements()) { 90 BranchGroup g = (BranchGroup)e.nextElement(); 91 if (g == root) return; 92 } 93 locale.addBranchGraph(root); 94 } 95 96 }
SmallUniverse
では VirtulalUniverse
を生成して Locale
を一つ追加し、この Locale
の配下に View 側のツリーを構築していくことにします。
■■javax.media.j3d.VirtualUniverse
VirtualUniverse
のコンストラクターは引数無しのものだけです。
コンストラクター public VirtualUniverse()
VirtualUniverse
には
Locale
を追加するためのメソッドはありません。
追加はLocale
のコンストラクターで行います。
VirtualUniverse
は複数の Locale
を持つこともできます。
■■javax.media.j3d.Locale
javax.media.j3d.Locale
はかならず一つの VirtualUniverse
を"親"に持ちます。
コンストラクター (一部) public Locale(VirtualUniverse universe) // 親となる VirtualUniverse
コンストラクター引数に VirtualUniverse
を指定することで、VirtualUniverse
が Locale
の"親"になります。
同じ VirtualUniverse
をコンストラクター引数に指定して複数の Locale
を生成したときには、VirtualUniverse
が複数の Locale
を保持することになります。
SmallUniverse
では、VirtualUniverse
型、Locale
型の変数を持たせてコンストラクター引数で初期化するようにしました。
SmallUniverse.java (一部)1 // Java 3D Test Program 2 // SmallUniverse.java 3 // Copyright(c) 1999 ENDO Yasuyuki <yasuyuki@javaopen.org> 4 5 import javax.media.j3d.*; 6 7 public class SmallUniverse { 8 protected VirtualUniverse universe = null; 9 protected Locale locale = null; : : 18 public SmallUniverse() { 19 this( new Locale( new VirtualUniverse() ) ); 20 } 21 22 public SmallUniverse(Locale locale) { 23 universe = locale.getVirtualUniverse(); 24 25 this.locale = locale; : : 50 }
引数なしのコンストラクターでは、新たに生成した VirtualUniverse
を引数にして Locale
を生成し、Locale
を引数にとるコンストラクターを実行しています。
Locale
を引数にとるコンストラクターでは、Locale#getVirtualUniverse()
で取得した VirtualUniverse
を変数 universe
に代入し、引数として渡された Locale
を変数 locale
に代入しています。
引数無しのコンストラクターで SmallUnivrese
を構築した場合には、新たな VirtualUniverse, Locale
が生成されます。
Locale
を引数にとるコンストラクターで生成された場合には、すでに生成された VirtualUniverse, Locale
を保持します。
追加した Locale
に View側の BranchGraph を構築して行きます。
Locale
に追加できるのは javax.media.j3d.BranchGroup
だけです。Locale
には複数の BranchGroup
を追加することができます。
Locale のメソッド (一部) public void addBranchGraph(BranchGroup branchGroup) // 追加したい BranchGroup public void removeBranchGraph(BranchGroup branchGroup) // 削除したい BranchGroup public void replaceBranchGraph(BranchGroup oldGroup, // 置き換たい古い BranchGrop BranchGroup newGroup) // 新たな BranchGroup public int numBranchGraphs() // BranchGroup の数を返す public java.util.Enumeration getAllBranchGraphs() // すべての BranchGroup を取得
SmallUniverse
に BranchGroup
型、TransformGroup
型の変数を持たせ、コンストラクターで初期化することにしました。
SmallUniverse.java (一部)7 public class SmallUniverse { 8 protected VirtualUniverse universe = null; 9 protected Locale locale = null; 10 protected BranchGroup root = null; 11 protected TransformGroup trans = null; : : 22 public SmallUniverse(Locale locale) { 23 universe = locale.getVirtualUniverse(); 24 25 this.locale = locale; 26 27 root = new BranchGroup(); 28 29 trans = new TransformGroup(); 30 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 31 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 32 root.addChild(trans); : : 50 }
この TransformGroup
に設定されている Transform3D
をgetTransform()
メソッドで取得できるようにしておきます。
59 public void getTransform(Transform3D t3d) { trans.getTransform(t3d); }
この TransformGroup
には、次に説明する ViewPlatform
を addChild()
します。
ViewPlatform
の"親"である TransformGroup
から取得した Transform3D
に移動や回転を与えると、視点の移動や回転が実現できます。
■■javax.media.j3d.ViewPlatform
javax.media.j3d.ViewPlatform
は View側のツリーの唯一の Leaf
ノードです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Leaf | +--javax.media.j3d.ViewPlatform クラス宣言 public class ViewingPlatform extends BranchGroup コンストラクター public ViewPlatform()
ViewPlatform
が addChild()
されている TransformGroup
に移動、回転などの操作を与えると、視点を移動したり回転させたりすることができます。
SmallUniverse
では ViewPlatform
型の変数を宣言し、コンストラクターで生成して TransformGroup
にaddChild()
しています。
11 protected TransformGroup trans = null; : : 34 vp = new ViewPlatform(); 35 trans.addChild(vp);
SmallUniverse
では設定しませんでしたが、ViewPlatform
には照明やアニメーションなどを活性化(Activation)させる領域を設定することができます。
メソッド (一部) public final void setActivationRadius(float activationRadius) // 活性化領域の半径
setActivationRadius()
メソッドで視野(ViewPlatform)の周囲の半径を指定します。デフォルト値は 62.0f
です。
照明やアニメーションなどの Bounds
(領域)が視野の周囲の領域と交差すると、<照明やアニメーションなどが有効になります。
(正確には有効化(活性化)の対象になります。実際に有効になるかどうかはこれだけでは決定できません)
■■javax.media.j3d.View
javax.media.j3d.View
は描画に関する様々な情報を保持するためのクラスです。
クラス継承 java.lang.Object | +--javax.media.j3d.View クラス宣言 public class View extends java.lang.Object コンストラクター public View()
クラス継承で分かるように、View
はシーングラフに追加されません。attachViewPlatform()
メソッドで設定された ViewPlatform
を参照します。
メソッド (一部) public final void attachViewPlatform(ViewPlatform vp) // 参照するViewPlatform
SmallUniverse
では次のように View
を生成して attachViewPlatform()
で ViewPlatform
を設定しました。
13 protected View view = null; : : 41 view = new View(); 42 view.attachViewPlatform(vp);
View
は様々なオブジェクト、設定を保持します。
ビューポリシー | SCREEN_VIEW |
投影ポリシー | PERSPECTIVE_PROJECTION |
スクリーンスケールポリシー | SCALE_SCREEN_SIZE |
ウインドウリサイズポリシー | PHYSICAL_WORLD |
ウインドウ移動ポリシー | PHYSICAL_WORLD |
ウインドウ視点ポリシー | RELATIVE_TO_FIELD_OF_VIEW |
単一視的ビューポリシー | CYCLOPEAN_EYE_VIEW |
フロントクリップポリシー | PHYSICAL_EYE |
バッククリップポリシー | PHYSICAL_EYE |
視覚ポリシー | VISIBILITY_DRAW_VISIBLE |
互換モード | false |
左の投影行列 | identity |
右の投影行列 | identity |
ViewPlatform 座標から視野座標への変換行列 | identity |
PhysicalBody オブジェクト | null |
PhysicalEnvironment オブジェクト | null |
スクリーンスケール | 1.0 |
視野角 | PI/4 |
フロントクリップ距離 | 0.1 |
バッククリップ距離 | 10.0 |
トラッキング可能 | false |
ユーザー頭部から仮想世界への変換を可能にする | false |
Canvas3D オブジェクトのリスト | empty |
透明度描画のときに深度バッファーを無視するかどうか | true |
スクリーンアンチエリアス | false |
照明を左右の目の位置で計算する | false |
ViewPlatformオブジェクト | null |
behaviorスケジューラーが実行中かどうか | true |
描画を実行する | true |
SmallUniverse
では最低限必要なものだけを設定し、あとはデフォルト値のまま使用しました。ここで行った設定は次のものです。
attachViewPlatform(ViewPlatform)
setPhysicalBody(PhysicalBody)
setPhysicalEnvironment(PhysicalEnvironment)
addCanvas3D(Canvas3D)
attachViewPlatform()
についてはすでに説明しました。
setPhysicalBody()
はヘッドマウントディスプレイなどを装着した人間の目や耳の位置などを定義するためのオブジェクト PhysicalBody
を設定します。
setPhysicalEnvironment()
はセンサーや入力機器についての情報を定義するためのオブジェクト PhysicalEnvironment
を設定します。
addCanvas3D()
は Canvas3D
を追加します。複数の Canvas3D
を追加できます。
■■javax.media.j3d.PhysicalBody
javax.media.j3d.PhysicalBody
は、人間の目や耳の位置などを定義します。
クラス継承 java.lang.Object | +--javax.media.j3d.PhysicalBody クラス宣言 public class PhysicalBody extends java.lang.Object コンストラクター public PhysicalBody() public PhysicalBody(Point3d leftEyePosition, // 左目の位置 Point3d rightEyePosition) // 右目の位置 public PhysicalBody(Point3d leftEyePosition, // 左目の位置 Point3d rightEyePosition, // 右目の位置 Point3d leftEarPosition, // 左耳の位置 Point3d rightEarPosition) // 右耳の位置
コンストラクターでは人間の目の位置、耳の位置などを設定することができます。この位置は頭部座標系での位置です。頭部座標系の原点は両目の中間です。
目と耳の位置以外にも、目と地表の距離や、目とスクリーンの距離などを設定することができます。引数無しのコンストラクターで生成されたときのデフォルト値は次のようになります。
左目の位置 | (-0.033, 0.0, 0.0) |
右目の位置 | (0.033, 0.0, 0.0) |
左耳の位置 | (-0.080, -0.030, 0.095) |
右耳の位置 | (0.080, -0.030, 0.095) |
目と地表の距離 | 1.68 |
目とスクリーンの距離 | 0.4572 |
頭部座標系からヘッドトラッカー座標系への変換Transform3D | 単位行列 |
ヘッドマウントディスプレイを使った場合に、頭部の動きを捕捉して視点位置を変更する必要があります。頭部座標系から、ヘッドトラッカー座標系への変換のための Transform3D
を設定することもできます。
メソッド (一部) public void setHeadToHeadTracker(Transform3D t) // 頭部座標→ヘッドトラッカー座標変換のための Transform3D
SmallUniverse
では引数無しのコンストラクターで生成したデフォルト値のまま使用しました。
14 protected PhysicalBody body = null; : : 44 body = new PhysicalBody(); 45 view.setPhysicalBody(body);
■■javax.media.j3d.PhysicalEnvironment
javax.media.j3d.PhysicalEnvironment
は頭部や腕などに付けたセンサーや、サウンドに関する設定値を定義します。
クラス継承 java.lang.Object | +--javax.media.j3d.PhysicalEnvironment クラス宣言 public class PhysicalEnvironment extends java.lang.Object コンストラクター (一部) public PhysicalEnvironment()
SmallUniverse
では引数無しのコンストラクターで生成した PhysicalEnvironment
をそのまま使用しました。
15 protected PhysicalEnvironment env = null; : : 47 env = new PhysicalEnvironment(); 48 view.setPhysicalEnvironment(env);
PhysicalEnvironment
には、頭部や腕などのセンサーや、サウンドのための様々な値を設定できます。
引数無しのコンストラクターで生成された PhysicalEnvironment
には次のようなデフォルト値が設定されています。
センサーの数 | 3 |
配列変数sensors | null (for all array elements) |
頭部のindex | 0 |
右手のindex | 1 |
左手のindex | 2 |
利き腕のindex | 1 |
利き腕でない腕のindex | 2 |
トラッキング可能 | false |
オーディオディバイス | null |
オーディオディバイスのリスト | empty |
物理共存座標系からトラッカーベース座標系への変換 | identity |
物理空間における物理共存座標系ポリシー | View.NOMINAL_SCREEN |
■■javax.media.j3d.Canvas3D
javax.media.j3d.Canvas3D
は3次元空間を2次元のウインドウ(スクリーン)に描画する機能を持ちます。また、描画のための様々な値を設定することができます。
クラス継承 java.lang.Object | +--java.awt.Component | +--java.awt.Canvas | +--javax.media.j3d.Canvas3D クラス宣言 public class Canvas3D extends java.awt.Canvas コンストラクター public Canvas3D(java.awt.GraphicsConfiguration graphicsConfiguration) // グラフィックス状況 public Canvas3D(java.awt.GraphicsConfiguration graphicsConfiguration, // グラフィックス状況 boolean offScreen) // オフスクリーン描画をする/しない
Canvas3D
のコンストラクターでは、現在のグラフィックス状況を表す java.awt.GraphicsConfiguration
オブジェクトを引数にとります。
二つの引数をとるコンストラクターでは、オフスクリーン描画の有無を設定します。デフォルト値は false
です。
通常は目に見える描画画面(スクリーン)に描画されます。オフスクリーンを有効にすると、スクリーンではなくメモリーバッファー(オフスクリーンバッファー)に描画します。バッファーに描画された画像をスクリーンに転送することもできますし、ファイル保存したり、印刷したり、加工して利用することもできます。
SmallUniverse
では、java.awt.GraphicsConfiguration
だけを引数にとるコンストラクターで生成した Canvas3D
をデフォルト値のまま使用しました。
16 protected Canvas3D canvas = null; : : 50 canvas = new Canvas3D(null); 51 view.addCanvas3D(canvas);
引数無しのコンストラクターでCanvas3D
を生成したときのデフォルト値は次のようになります。
イメージプレート上の左目位置 | (0.142, 0.135, 0.4572) |
イメージプレート上の右目位置 | (0.208, 0.135, 0.4572) |
立体視の有効/無効 | true |
ダブルバッファーの有効/無効 | true |
単一視ビューポリシー | View.CYCLOPEAN_EYE_VIEW |
オフスクリーンモード | false |
オフスクリーンバッファー | null |
オフスクリーン位置 | (0,0) |
イメージプレートとは何でしょうか。
Canvas3D
は、3次元空間上のものを2次元の"板"に投影して描画します。この仮想的な"板"のことをイメージプレートと呼んでいます。
View
のデフォルト値では、目からスクリーンまでの距離は 0.4572
でした。イメージプレートはこのスクリーン位置にある"板"です。
3次元空間上の物体はイメージプレートに投影されます。
イメージプレートに投影された画像がスクリーンに描画されます。
■SimpleUniverse
あれこれ■■SimpleUniverse
で表示できる範囲com.sun.j3d.utils.universe.SimpleUniverse
を使ったサンプルでは setNominalViewingTransform()
メソッドで、視点をZ軸方向に約2.41
移動させました。また、描画される物体は ±1.0
の範囲に収まるような大きさにしていました。
SimpleUniverse
で描画できる範囲はどこからどこまでなのでしょうか? setNominalViewingTransform()
メソッドは何を行っているのでしょうか?
View
オブジェクトのデフォルト値では、視野の角度(field of view)は π/4
ラジアン(45°
)です。
視野の前後についても限界があります。視点からの距離が 0.1
よりも近くにある物体は描画されません。また、視点からの距離が 10.0
を超える物体も描画されません。
視野の手前側の描画の限界距離はフロントクリップ距離(flont clip distance)、視野の奥の描画の限界距離はバッククリップ距離(back clip distance)と呼ばれています。
視野の角度と前方、後方のクリップ距離から、図のような角錐台の領域以外は表示されないことがわかるでしょう。
(実際には、視点から0.4572
の距離にイメージプレートがあるので、イメージプレートより近くにある物体は描画されません)
大きい物体を表示させるときには表示領域を広げる必要があります。表示領域を広げるにはどうしたら良いでしょうか?
最も手軽なのはバッククリップ距離を大きくすることです。View
にはこのためのメソッドとして setBackClipDistance()
があります。
public final void setBackClipDistance(double distance) // バッククリップ距離
com.sun.j3d.utils.universe.SimpleUniverse
を使う場合には次のようにします。
com.sun.j3d.utils.universe.Viewer
オブジェクトを取得するViewer#getWiew()
メソッドで javax.media.j3d.View
オブジェクトを取得するView#setBackClipDistance()
メソッドでバッククリップ距離を設定するこの操作は次のように書くこともできます。
simpleUniverse.getViewer().getView().setBackClipDistance(100.0); // 100.0までを表示
■■setNominalViewingTransform()
では何を行っているのか?com.sun.j3d.utils.universe.SimpleUniverse
には getViewingPlatform()
というメソッドがあります。
public ViewingPlatform getViewingPlatform()
getViewingPlatform()
で取得できるオブジェクトは com.sun.j3d.utils.universe.ViewingPlatform
です。名前が似ていますが、javax.media.j3d.ViewPlatform
とは別のオブジェクトです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Group | +--javax.media.j3d.BranchGroup | +--com.sun.j3d.utils.universe.ViewingPlatform クラス宣言 public class ViewingPlatform extends BranchGroup
com.sun.j3d.utils.universe.ViewingPlatform
には、Z軸方向に視点を移動するためのsetNaminalViewingTransform()
メソッドがあります。
public void setNominalViewingTransform()
setNominalViewingTransform()
メソッドでは何を行っているのでしょうか?
setNominalViewingTransform()
メソッドでは、次のような計算式でZ軸方向への移動距離を計算しています。
Z軸移動距離 = 1.0 / Math.tan(視野角/2.0);
視野の角度の1/2のtan
の逆数を求めています。原点位置±1.0
の範囲のものがちょうど視野に入る距離です。
視野の角度が π/4
ラジアンのとき、Z軸移動距離は約 2.41
になります。
■■SimpleUniverse
から Locale
を取り出すcom.sun.j3d.utils.universe.SimpleUniverse
には Locale
を取得するための getLoale()
があります。
public Locale getLocale() // Locale を取得
BranchGroup
を追加するには SimpleUniverse#addBranchGraph()
メソッドを使えば良いのですが、SimpleUniverse
には追加したBranchGroup
を削除するメソッドはありません。
SimpleUniverse
から BranchGroup
を削除するにはつぎのような処理が必要になります。
getLocale()
で Locale
を取得するLocale#removeBranchGraph()
メソッドで BranchGroup
を削除するSimpleUniverse universe = new SimpleUniverse(canvas); BranchGroup scene = new BranchGroup(); scene.setCapability(BranchGroup.ALLOW_DETACH); // 実行時の remove を許可する universe.addBranchGraph(scene); : : universe.getLocale().removeBranchGraph(scene);
実行時に Locale
から BranchGroup
を削除するには BranchGroup.ALLOW_DETACH
という capability bit
を設定する必要があります。
■■SimpleUniverse
の視点側の TransformGroup
を取り出す視点を移動させたいときなど、SimpleUniverse
から視点側の TransformGroup
を取り出したい場合があります。
視点側の TransformGroup
は com.sun.j3d.utils.universe.ViewingPlatform
が保持しています。
ViewingPlatform のメソッド (一部) public TransformGroup getViewPlatformTransform() // 視点側の TransformGroup を取得する
SimpleUniverse
には ViewingPlatform
を取得するためのメソッド getViewingPlatform()
があります。視点側の TransformGroup
を取得するには次のような処理が必要になります。
SimpleUniverse#getVieiwingPlatform
メソッドで ViewingPlatform
を取得するViewingPlatform#getViewPlatformTransform()
メソッドで視点側の TransformGroup
を取得するSimpleUniverse universe = new SimpleUniverse(canvas); : : TransformGroup vtrans = universe.getViewingPlatform().getViewPlatformTransform();
取得した TransformGroup
に対して移動、回転などの変換操作を行うと視点が移動、回転します。
いままでシーングラフを図に描いてきましたが、このへんでシーングラフの表記法についてまとめてみましょう。
Java 3Dのオブジェクトの多くは javax.media.j3d.SceneGraphObject
を継承しています。
java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | | | +--javax.media.j3d.Group | | | +--javax.media.j3d.Leaf | +--javax.media.j3d.NodeComponent | +--javax.media.j3d.Geometry | +--javax.media.j3d.Appearance
SceneGraphObject
のサブクラス javax.media.j3d.Node
には Group, Leaf
というサブクラスがあります。
Group
には addChild(Node)
メソッドがあり、他の Group, Leaf
を"子供"として保持することができます。ツリー状のシーングラフはこの"親子関係"によって構築されます。
親子関係は実線矢印で表します。向きは親→子です。
"親"ノードに加えられた操作は、その"親"の配下の"子供"ノードに影響します。たとえば TransformGroup
に加えられた変換操作はその配下のすべての"子供"ノードに影響します。
NodeComponent
も SceneGraphObject
のサブクラスですが、こちらはノードとしてツリーを構築することはありません。他のオブジェクトから参照されるだけです。
シーングラフの図ではオブジェクト参照は点線矢印で表します。
VirtuelUniverse
VirtualUniverse
は斜めに線が入った偏平な楕円で表します。
この図は次のようなコードに対応しています。
VirtualUniverse universe = new VirtualUniverse();
Locale
Locale
は菱形で表します。
この図は次のようなコードに対応しています。
Locale locale = new Locale(universe);
Group
Group
ノードは円で表します。
円の中に Group
クラスの頭文字を書きます。例えば BranchGroup
なら BG
、TransformGroup
ならT
です。
Leaf
Leaf
ノードは三角形で表します。
三角形の中に Leaf
クラスの頭文字を書きます。例えば ViewPlatform
なら VP
です。
NodeComponent
NodeComponent
は楕円で表します。
楕円の中に NodeComponent
クラスのクラス名や頭文字を書きます。
Behavior
Behavior
は Leaf
のサブクラスなので、三角形の中に頭文字 B
を書いて表します。
SceneGraphObject
のサブクラスでないその他のクラスは四角形で表します。
四角形の中や、四角形の下などにクラス名を書きます。
■javax.media.j3d.SceneGraphObject
javax.media.j3d.SceneGraphObject
はシーングラフを構成するオブジェクトの基底クラスです。capability bit
を設定したり、任意のユーザーデータを設定するメソッドがあります。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject クラス宣言 public abstract class SceneGraphObject extends java.lang.Object コンストラクター public SceneGraphObject()
ScereGraphObject
は抽象クラスです。サブクラスには Node
と NodeComponent
があります。このうち Node
はツリー状のシーングラフを構成します。NodeComponent
はツリーの構成要素にはなりませんが、様々な値が設定され Node
から参照されます。
capability bits | 全 bit クリア |
live 状態かどうか | false |
compiled 状態かどうか | false |
ユーザー定義オブジェクト | null |
SceneGraphObject
には capability bit
を設定/取得するためのメソッドがあります。
public final void setCapability(int bit) // capability bit 整数定数 public final boolean getCapability(int bit) // capability bit 整数定数
capability bit
の設定は、その ScereGraphObject
を含むツリーがシーングラフに追加される前に行う必要があります。
capability bit
で設定する定数値は、クラスごとに定義されています。
public final void clearCapability(int bit) // capability bit 整数定数
clearCapability()
は定数で指定された capability bit
をクリアします。
public final boolean isCompiled() // compile() されているかどうか
isCompiled()
は、そのSceneGraphObject
が "compile"
状態かどうかを返します。
BranchGroup
には compile()
というメソッドがあります。BranchGroup
をcompile()
するとそのBranchGroup
配下のツリーは最適化されますが、ノードを動的に追加/削除することなどができなくなります。
public final boolean isLive() // "live"状態かどうか
isLive()
は、その SceneGraphObject
が "live"
状態かどうかを返します。
BranchGroup
が Locale
に addBranchGraph()
されると、その BranchGroup
配下のツリーは Java 3D の描画スケジューリングの対象になります。ツリーが描画スケジューリングの対象になっていることを "live"
状態と呼びます。
public void setUserData(java.lang.Object userData) // 任意のユーザー定義オブジェクト public java.lang.Object getUserData() // 任意のユーザー定義オブジェクトを取得
setUserData(), getUserData()
は任意のユーザー定義オブジェクトを設定/取得します。
設定したユーザー定義オブジェクトは描画には直接関係ありませんが、SceneGraphObject
に任意の情報を設定することができます。
■javax.media.j3d.Node
javax.media.j3d.Node
はシーングラフの"節"(ノード)としてツリー状のシーングラフを構築します。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node クラス宣言 public abstract class Node extends SceneGraphObject コンストラクター public Node()
シーングラフは、addChild()
メソッドで追加された Node
の親子関係によって構築されます。
ピッキング可能 | true |
衝突検知対象になる | true |
bounds を自動計算 | true |
bounds | なし (自動計算) |
public final Node getParent()
getParanet()
メソッドはその Node
の"親" Node
を取得します。
public final void setBounds(Bounds bounds) public final Bounds getBounds()
setBounds(), getBounds()
メソッドは、その Node
の境界領域を設定/取得します。設定した領域 (javax.media.j3d.Bounds
オブジェクト)は、他の Node
との衝突判定(交差判定)、照明、スケジューリングの有効範囲などに使われます。
public void setCollidable(boolean collidable) public boolean getCollidable()
setCollidable(), getCollidable()
は、衝突判定の対象にするかどうかを設定/取得します。setCollidable(false)
と設定した場合、この物体は衝突判定の対象でなくなります。つまり、この物体に衝突しても衝突は検知されなくなります。
public final void setBoundsAutoCompute(boolean autoCompute) public final boolean getBoundsAutoCompute()
setBoundsAutoCompute(), getBoundsAutoCompute()
は、この Node
のBounds
を自動計算するかどうかを設定します。デフォルト値は true
です。この Node
が "live"
にならないと自動計算は行われません。
public final void getLocalToVworld(Transform3D t) // 座標変換 public final void getLocalToVworld(SceneGraphPath path, // この Node を含むパス Transform3D t) // 変換座標
getLocalToVWorld()
メソッドは、この Node
のローカル座標系から、バーチャルワールド座標系への変換行列を Transform3D
に取得します。
SceneGraphPath
を引数に取るものは、この Node
が含まれる SceneGraphPath
を引数に指定します。
public Node cloneTree() public Node cloneTree(boolean forceDuplicate) // 複製を強制するかどうか public Node cloneTree(boolean forceDuplicate, // 複製を強制するかどうか boolean allowDanglingReference) // ダングリング参照の許可するかどうか public Node cloneTree(NodeReferenceTable referenceTable) // ノード参照テーブル public Node cloneTree(NodeReferenceTable referenceTable, // ノード参照テーブル boolean forceDuplicate) // 複製を強制するかどうか public Node cloneTree(NodeReferenceTable referenceTable, // ノード参照テーブル boolean forceDuplicate, // 複製を強制するかどうか boolean allowDanglingReferences) // ダングリング参照を許可するかどうか
cloneTree()
メソッドは、この Node
以下のすべてのツリーを複製します。
forceDuplicate
にtrue
を指定すると、Node
が参照している NodeComponent
も常に複製されます。これが false
のときは各 NodeComponent
の duplicateOnCloneTree
フラグが検査され、duplicateOnCloneTree
が false
のときは NodeComponent
は複製されません。
public Node cloneNode(boolean forceDuplicate) // 複製を強制するかどうか
cloneNode()
メソッドは、この Node
の新たな複製を作成します。
forceDuplicate
にtrue
を指定すると、Node
が参照している NodeComponent
も常に複製されます。これが false
のときは各 NodeComponent
の duplicateOnCloneTree
フラグが検査され、duplicateOnCloneTree
が false
のときは NodeComponent
は複製されません。
public void duplicateNode(Node originalNode, // 複製元の Node boolean forceDuplicate) // 複製を強制するかどうか
duplicateNode()
メソッドは、引数に指定された Node
をこの Node
に複製します。
forceDuplicate
にtrue
を指定すると、Node
が参照している NodeComponent
も常に複製されます。これが false
のときは各 NodeComponent
の duplicateOnCloneTree
フラグが検査され、duplicateOnCloneTree
が false
のときは NodeComponent
は複製されません。
public void setPickable(boolean pickable) public boolean getPickable()
setPickable()
メソッドは、この Node
へのピッキングを可能にしたり不可能にしたりします。getPickable()
メソッドはピッキングが可能かどうかを取得します。マウスなどで物体を選択することをピッキングと呼びます。デフォルト値では true
です。
■javax.media.j3d.NodeComponent
javax.media.j3d.NodeComponent
は Node
から参照され、様々な属性を設定するために使用されます。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.NodeComponent クラス宣言 public abstract class NodeComponent extends SceneGraphObject コンストラクター public NodeComponent()
public final void setDuplicateOnCloneTree(boolean duplicate) // 複製するかどうか public final boolean getDuplicateOnCloneTree()
setDuplicateOnCloneTree(),getDuplicateOnCloneTree()
メソッドは、cloneTree()
メソッドが実行されたとき、この NodeComponent
を複製するかどうかを設定/取得します。true
のときは複製されます。false
のときは複製されませんが、cloneTree()
の引数の forceDuplicate
を true
にしたときはこのフラグは無視され常に複製されます。
public NodeComponent cloneNodeComponent(boolean forceDuplicate)
cloneNodeComponent()
メソッドはこの NodeComponent
から新たな複製を作成します。
引数の forceDupcicate
が true
のとき、この NodeComponent
の duplicateOnCloneTree
フラグは無視され、常に複製されます。forceDuplicate
がfalse
のときは duplicateOnCloneTree
フラグが検査され、duplicateOnCloneTree
が true
のときだけ複製されます。
public void duplicateNodeComponent(NodeComponent originalNodeComponent, // 複製元の NodeComponent boolean forceDuplicate) // 複製を強制するかどうか
duplicateNodeComponent()
メソッドは、引数で指定された NodeComponent
をこの NodeComponent
に複製します。
引数の forceDupcicate
が true
のとき、引数に指定された NodeComponent
の duplicateOnCloneTree
フラグは無視され、常に複製されます。forceDuplicate
がfalse
のときは duplicateOnCloneTree
フラグが検査され、duplicateOnCloneTree
が true
のときだけ複製されます。
■Group
ノードのいろいろGroupのサブクラス java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Group | +--javax.media.j3d.BranchGroup | +--javax.media.j3d.OrderedGroup | +--com.sun.j3d.utils.geometry.Primitive | +--javax.media.j3d.SharedGroup | +--javax.media.j3d.Switch | +--javax.media.j3d.TransformGroup
BranchGroup, TransofrmGroup
以外の Group
ノードについて簡単に説明します。
■javax.media.j3d.Group
Group
はaddChild()
メソッドを持ち、他の Node
をその"子供"として保持します。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Group クラス宣言 public class Group extends Node コンストラクター public Group()
public final void setCollisionBounds(Bounds bounds) // 衝突境界領域を取得 public final Bounds getCollisionBounds()
setCollisionBounds(),getCollisionBounds()
メソッドは、この Group
の衝突境界領域を設定/取得します。
public final void setChild(Node child, // セットしたい Node int index) // Node の index
setChild()
メソッドは、指定された index
に Node
をセットします。index
は 0
以上、numChildren()
より小です。
Java 3D 1.2 以降では引数 child
に null
を指定できます。
public final void insertChild(Node child, // 挿入したい Node int index) // Node の index
insertChild()
メソッドは、指定された index
の"位置"に Node
を挿入します。index
は 0
以上、numChildren()
より小です。
Java 3D 1.2 以降では引数 child
に null
を指定できます。
public final void removeChild(int index) // Node の index
removeChild()
メソッドは、指定された index
の Node
を削除します。index
は 0
以上、numChildren()
より小です。
public final Node getChild(int index) // Node の index
getChild()
メソッドは、指定された index
の Node
を取得します。
public final java.util.Enumeration getAllChildren() // すべての"子"を取得
getAllChildren()
メソッドは、すべての Node
を取得します。
public final void addChild(Node child) // 追加したい Node
addChild()
メソッドは、引数に指定された Node
を Group
に"子"として追加します。
Java 3D 1.2 以降では引数 child
に null
を指定できます。
public final void moveTo(BranchGroup branchGroup) // この Group の移動先の BranchGroup
moveTo()
メソッドは、引数に指定された BranchGroup
を、それまで接続されていた Group
から 切り離し、この Group
に addChild()
します。
public final int numChildren() // "子"の数を取得
numChildren()
メソッドは、"子"Node
の数を取得します。
public final void setAlternateCollisionTarget(boolean target) public final boolean getAlternateCollisionTarget()
setAlternateCollisionTarget()
は、このGroup
が衝突相手になったときに、衝突を報告させるかどうかを設定します。デフォルトでは false
です。
public Node cloneNode(boolean forceDuplicate)
cloneNode()
はこの Group
ノードを複製します。
引数の forceDupcicate
が true
のとき、この NodeComponent
の duplicateOnCloneTree
フラグは無視され、常に複製されます。forceDuplicate
がfalse
のときは duplicateOnCloneTree
フラグが検査され、duplicateOnCloneTree
が true
のときだけ複製されます。
■javax.media.j3d.Switch
javax.media.j3d.Switch
は、追加した"子"ノードのそれぞれについて、描画の対象にするか、描画対象から外すかを設定できる Group
ノードです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Group | +--javax.media.j3d.Switch クラス宣言 public class Switch extends Group コンストラクター public Switch() public Switch(int whichChild) // 表示させる"子"の index public Switch(int whichChild, // 表示させる"子"の index java.util.BitSet childMask) // マスク値 定数フィールド (一部) public static final int CHILD_NONE // 全てを表示する public static final int CHILD_ALL // 全て表示しない public static final int CHILD_MASK // indexまたはマスク値で指定した"子"だけを表示
Switch
は、特定の"子"を描画対象にしたり、描画の対象から外したりできます。描画対象から外されたノードは、シーンに存在しなくなる、と言っても良いかも知れません。
int
型の引数をとるコンストラクターでは、whitchChild
に指定した index の"子"ノードだけが描画の対象になります。witchChild
には CDILD_NONE, CHILD_ALL, CHILD_MASK
を指定することもできます。witchChild
のデフォルト値は CHILD_NONE
です。
CHLID_NONE
を指定するとすべての"子"ノードは描画されません。
CHILD_ALL
を指定するとすべての"子"ノードが描画されます。
CHILD_MASK
を指定したときは、java.util.BitSet
によるマスク値で指定した"子"ノードだけが描画されます。
public final void setWhichChild(int child) // 表示させる"子"の index
setWhitchClild()
メソッドは、引数 child
で指定された index の"子"ノードを描画の対象に設定します。指定された"子"以外は描画の対象から外されます。
public final void setChildMask(java.util.BitSet childMask) // マスク値
setChildMask()
メソッドは、java.util.BitSet
によるマスク値で指定された"子"ノードだけを描画対象に設定します。このメソッドを有効にするには、setWhitchChild()
メソッドで CHILD_MASK
を指定しておく必要があります。
■javax.media.j3d.SharedGroup
javax.media.j3d.SharedGroup
は javax.media.j3d.Link
から参照され、複数のシーングラフで共有することができる特殊な Group
ノードです。
SharedGroup
それ自体を他の Group
に追加することはできません。Link
から参照されるだけです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Group | +--javax.media.j3d.SharedGroup クラス宣言 public class SharedGroup extends Group コンストラクター public SharedGroup()
SharedGroup
は他のGroup
と同様に、他のノードを"子"として保持できます。ただし SharedGroup
を別の Group
に addChild()
することはできません。
SharedGroup
は、次で説明する Link
から参照され、複数のシーングラフから共有されます。
javax.media.j3d.Link
javax.media.j3d.Link
は SharedGroup
を参照する Leaf
ノードです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Leaf | +--javax.media.j3d.Link クラス宣言 public class Link extends Leaf コンストラクター public Link() public Link(SharedGroup sharedGroup) // 参照する SharedGroup
引数を持つコンストラクターでは、この Link
が参照する SharedGroup
を指定します。
SharedGroup
をその配下に addChild()
したいシーングラフでは、Link
を生成して SharedGroup
を参照させ、その Link
をシーングラフに追加します。
SharedGroup
はどの Group
にも addChild()
しない
public void setSharedGroup(SharedGroup sharedGroup) // 参照する SharedGroup public SharedGroup getSharedGroup() // 参照する SharedGroup を取得
setSharedGroup()
メソッドは、この Link
が参照する SharedGroup
を設定します。
getSharedGroup()
メソッドは、この Link
が参照している SharedGroup
を取得します。
■javax.media.j3d.OrderedGroup
javax.media.j3d.OrderedGroup
は、追加されたノードが追加された順番で描画されることを保証する Group
ノードです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Group | +--javax.media.j3d.OrderedGroup クラス宣言 public class OrderedGroup extends Group コンストラクター public OrderedGroup()
OrderedGroup
に追加されたノードは、追加された順番に描画されます。
通常 Java 3Dの描画スケジューリングでは、何がいつ描画されるかはプログラマーには分かりません。透明度の描画のときなどには奥の物体から順番に描画して行かなければならない場合があります。このような描画の順序によって結果が異なる場合に OrderedGroup
を使用します。
■javax.media.j3d.Leaf
javax.media.j3d.Leaf
は配下に"子"を持たないノードのための抽象クラスです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Leaf クラス宣言 public abstract class Leaf extends Node コンストラクター public Leaf()
Leaf
は独自のメソッドを持ちません。
Leaf
には次のような直接のサブクラスがあります。
java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Leaf | +--javax.media.j3d.AlternateAppearance | +--javax.media.j3d.Background // 背景 | +--javax.media.j3d.Behavior | +--javax.media.j3d.BoundingLeaf | +--javax.media.j3d.Clip | +--javax.media.j3d.Fog // 霧 | +--javax.media.j3d.Light // 光源 | +--javax.media.j3d.Link | +--javax.media.j3d.ModelClip | +--javax.media.j3d.Morph | +--javax.media.j3d.Shape3D | +--javax.media.j3d.Sound | +--javax.media.j3d.Soundscape | +--javax.media.j3d.ViewPlatform