Java 3D には、アニメーションを実現するためのクラスとして Interpolator
が用意されています。
Interpolater
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Leaf | +--javax.media.j3d.Behavior | +--javax.media.j3d.Interpolator クラス宣言 public abstract class Interpolator extends Behavior コンストラクター public Interpolator() public Interpolator(Alpha alpha) // この Interpolator で使用する Alpha
Interpolator
は Behavior
のサブクラスです。
Behavior
と同様、initialize(), processStimulus()
で wakeupOn()
を使って起動条件を設定することもできますが、Interpolator
ではアニメーションが簡単にできるように機能が拡張されています。
Interpolator
でのアニメーションには javax.media.j3d.Alpha
クラスを使用します。
javax.media.j3d.Alpha
は、RGBA カラーモデルで不透明の度合を表す「アルファ」とは関係ありません。Alpha
は、0.0〜1.0
の範囲の値 (アルファ値) を持っています。アルファ値は、時間の変化に応じて 0.0〜1.0
の範囲で変化して行きます。
Interpolator
では、変化するアルファ値に応じて、色、距離、座標、大きさ、回転などを補間して行きます。
0.0
が状態の開始、1.0
が状態の終了 (の値) と言っても良いでしょう。
Interpolator
の使用方法は次のようになります。
Alpha
を生成する。Alpha
に、時間の変化に応じた状態の変化を設定するInterpolator
を生成する。コンストラクターの引数に Alpha
を指定するsetSchedulingBounds()
メソッドで、スケジューリングが有効になる領域 (Bounds
) を設定する。Interpolator
を BranchGroup
に addChild()
するBehavior
のような起動条件の設定は不要です。Alpha
を設定し、setSchedulingBounds()
でスケジューリングが有効になる領域を設定し、BranchGroup
に addChild()
するだけで Interpolator
の動作が開始します。
Alphah2
javax.media.j3d.Alpha
は、時間の変化に応じて 0.0〜1.0
の範囲の値 (アルファ値) を変化させます。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.NodeComponent | +--javax.media.j3d.Alpha クラス宣言 public class Alpha extends NodeComponent コンストラクター (一部) public Alpha() public Alpha(int loopCount, // 繰り返しの回数 int mode, // 変化モード(増加、減少、または両方) long triggerTime, // 最初の起動開始までのミリ秒 long phaseDelayDuration, // 最初の起動開始後に本当に変化を開始するまでのミリ秒 long increasingAlphaDuration, // 増加に要するミリ秒 long increasingAlphaRampDuration, // 増加が加速するミリ秒 long alphaAtOneDuration, // 1.0 を保持するミリ秒 long decreasingAlphaDuration, // 減少に要するミリ秒 long decreasingAlphaRampDuration, // 減少が加速するミリ秒 long alphaAtZeroDuration) // 0.0 を保持するミリ秒 定数フィールド public static final int INCREASING_ENABLE // 増加を有効にする public static final int DECREASING_ENABLE // 減少を有効にする メソッド (一部) public void setStartTime(long startTime) // 開始基準時刻
loopCount
に繰り返し回数を指定します。-1
を指定すると無限に繰り返します。デフォルト値は -1
です。
loopCount
を変更しても、Alpha
の開始時刻を変更しないと繰り返し回数の変更が反映されません。開始時刻は、すべての実行の基準になります。開始時刻は setStartTime()
で変更します。たとえば、即座に変更を反映したいときは現在時刻を開始時刻にします。
alpha.setStartTime(System.currentTimeMillis()); // 現在時刻から開始 alhpa.setLoopCount(1); // 1回だけ
mode
には、定数 INCREASING_ENABLE, DECREASING_ENABLE
を指定します。それぞれ増加、減少を有効にします。デフォルト値は INCLEASING_ENABLE
です。
INCLEASING_ENABLE |
DECLEASING_ENABLE |
---|
両方を OR
した値を指定すると増加も減少も有効になります。
triggerTime
は、Interpolator
が最初に起動されるまでの時間 (トリガー時間) をミリ秒で指定します。デフォルト値は 0
です。
phaseDelayDuration
は、最初に起動されてから、本当に変化を開始するまでの遅延時間をミリ秒で指定します。デフォルト値は 0
です。
increasingAlphaDuration
は、0.0
から 1.0
までの増加に要する時間をミリ秒で指定します。
increasingAlphaRampDuration
は、増加が加速される時間をミリ秒で指定します。この時間が increasingAlphaDuration
の 1/2 よりも小さいとき、最初は加速し、次に一定時間同じ増加率を保ち、最後に減速します。
この時間が increasingAlphaDuration
の 1/2 以上のときは 1/2 とみなされます。1/2 以上のときは増加率が一定になる時間は無く、はじめ加速し、次に減速して行きます。
この時間が 0
のときは常に同じ増加率で増加します。デフォルト値は 0
です。
alphaAtOneDuration
は、増加終了後 1.0
の状態を保持する時間をミリ秒で指定します。デフォルト値は 0
です。
decreasingAlphaDuration
は、1.0
から 0.0
への減少に要する時間をミリ秒で指定します。デフォルト値は 0
です。
decreasingAlphaRampDuration
は、減少が加速される時間をミリ秒で指定します。この時間が decreasingAlphaDuration
の 1/2 よりも小さいとき、最初は加速し、次に一定時間同じ減少率を保ち、最後に減速します。
この時間が decreasingAlphaDuration
の 1/2 以上のときは 1/2 とみなされます。1/2 以上のときは増加率が一定になる時間は無く、はじめ減少が加速し、次に減少が減速して行きます。
この時間が 0
のときは常に同じ減少率で減少します。デフォルト値は 0
です。
alphaAtZeroDuration
は、減少が終了してから 0.0
の状態を保持する時間をミリ秒で指定します。デフォルト値は 0
です。
すべての値の関係は次の図のようになります。
AlphaPanel
Aplpha
の状態を変更するための GUI クラス AlphaPanel
を書きました。
AlphaPanel
の使用方法は次のようになります。
AlphaPanel
を生成するAlphaPanel#getAlpha()
で Alpha
を取得するInterpolator
を生成する。コンストラクター引数に AlphaPanel#getAlpha()
で取得した Alpha
を指定するAlphaPanel
のソースコードはCD-ROMを参照してください。GUI 構築が大半なので詳しい説明は省略します。
AlphaPatel.java
javax.media.j3d.ColorInterpolator
javax.media.j3d.ColorInterpolator
は javax.media.j3d.Material
の diffuseColor
を変化させます。
クラス宣言 public class ColorInterpolator extends Interpolator コンストラクター public ColorInterpolator(Alpha alpha, // 変化の元になる Alpha Material target) // 変更対象の Material public ColorInterpolator(Alpha alpha, // 変化の元になる Alpha Material target, // 変更対象の Material Color3f startColor, // 初期の DiffuseColor Color3f endColor) // 終了時の DiffuseColor
ColorInterpolator
のコンストラクターでは、変更対象となる Material
を指定します。変更の対象となる色は diffuseColor
のみです。変化開始時の diffuseColor
と、変化終了時の diffuseColor
を設定し、Alpha
が 0.0〜1.0
の範囲で変化すると diffuseColor
が変化開始色〜変化終了色 の間で変化します。
diffuseColor
以外の色を変化させたい場合には自分で独自の Interpolator
を書くことになると思います。
このサンプルの実行結果は次のようになります。
Alpha
や色を変化させてみてください。値の変更は即座に反映されます。loopCount
を変更した場合は [Stop]
ボタンを押して ColorInterpolator
を停止 (setEnabled(false)
) させ、再度 [Start]
ボタンを押してください。
ハート型のオブジェクトは別クラスとして書きました。ソースコードは次の通りです。頂点座標の配列と頂点 index の配列を用意し、com.sun.j3d.utils.geometry.GeometryInfo
で IndexedTriangleArray
を構築しています。
Heart.java1 // Java 3D Test Program 2 // Heart.java 3 // Copyright (c) 1999 ENDO Yasuyuki 4 // mailto:yasuyuki@javaopen.org 5 // http://www.javaopen.org/j3dbook/index.html 6 7 8 import javax.media.j3d.*; 9 import javax.vecmath.*; 10 import com.sun.j3d.utils.geometry.*; 11 12 public class Heart { 13 protected GeometryInfo ginfo = null; 14 public GeometryArray getGeometry() { return ginfo.getGeometryArray(); } 15 public Vector3f[] getNormals() { return ginfo.getNormals(); } 16 17 public Heart() { 18 float[] vertices = { 19 -0.35553592f, 0.23813197f, 0.2910625f, 20 -0.07661505f, 0.31729084f, 0.12777443f, : : 350 0.028356554f, 0.24565041f, -0.18884426f, 351 0.11708972f, 0.18016575f, -0.259885f, 352 }; 353 354 int[] indices = { 355 3, 9, 1, 356 9, 8, 1, : : 1015 331, 325, 137, 1016 137, 325, 136, 1017 }; 1018 ginfo = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY); 1019 ginfo.setCoordinates(vertices); 1020 ginfo.setCoordinateIndices(indices); 1021 NormalGenerator ngen = new NormalGenerator(); 1022 ngen.generateNormals(ginfo); 1023 } 1024 }
ColorInterpolatorTest
のソースコードは次のようになります。GUI 構築のため AlphaPanel, TuplePanel
を使用しました。
ColorInrepolatorTest.java1 // Java 3D Test Applet 2 // ColorInterpolatorTest.java 3 // Copyright (c) 1999 ENDO Yasuyuki 4 // mailto:yasuyuki@javaopen.org 5 // http://www.javaopen.org/j3dbook/index.html 6 7 import java.applet.*; 8 import java.awt.*; 9 import java.awt.event.*; 10 import javax.media.j3d.*; 11 import javax.vecmath.*; 12 import com.sun.j3d.utils.applet.MainFrame; 13 import com.sun.j3d.utils.universe.SimpleUniverse; 14 import com.sun.j3d.utils.behaviors.mouse.MouseRotate; 15 16 public class ColorInterpolatorTest extends Applet { 17 private AlphaPanel apanel = null; 18 19 private Appearance app = null; 20 private Color3f scolor = new Color3f(1.0f, 0.0f, 0.0f); 21 private Color3f ecolor = new Color3f(0.0f, 0.0f, 1.0f); 22 private ColorInterpolator cinterp = null;.................(1) 23 24 public ColorInterpolatorTest() { 25 this.setLayout(new BorderLayout()); 26 27 apanel = new AlphaPanel(); 28 this.add(apanel, BorderLayout.NORTH); 29 30 Panel cpanel = new Panel(); 31 cpanel.setLayout( new GridLayout(2, 1) ); 32 this.add(cpanel, BorderLayout.SOUTH); 33 34 Panel[] cpanels = new Panel[2]; 35 for (int i=0; i<2; i++) { 36 cpanels[i] = new Panel(); 37 cpanel.add(cpanels[i]); 38 } 39 40 final Button sbutton = new Button("Stop"); ┐ 41 sbutton.addActionListener( new ActionListener() { │ 42 public void actionPerformed(ActionEvent e) { │ 43 String blabel = sbutton.getLabel(); │ 44 if (blabel.equals("Start")) { │ 45 cinterp.setEnable(true);.....................(3) │ 46 apanel.reset();..............................(4) │ 47 │ 48 sbutton.setLabel("Stop"); ├(2) 49 } else if (blabel.equals("Stop")) { │ 50 cinterp.setEnable(false); │ 51 │ 52 sbutton.setLabel("Start"); │ 53 } │ 54 } │ 55 }); │ 56 cpanels[0].add(sbutton); ┘ 57 58 cpanels[0].add( new Label("Start -") ); ┐ 59 TuplePanel stp = new TuplePanel(scolor); │ 60 stp.addTupleEventListener( new TupleEventListener() { │ 61 public void tupleStateChanged(TupleEvent e) { │ 62 Color3f color = e.getColor3f(); ├(5) 63 cinterp.setStartColor(color);.................(6) │ 64 } │ 65 }); │ 66 cpanels[0].add(stp); ┘ 67 68 cpanels[1].add( new Label("End -") ); ┐ 69 TuplePanel etp = new TuplePanel(ecolor); │ 70 etp.addTupleEventListener( new TupleEventListener() { │ 71 public void tupleStateChanged(TupleEvent e) { ├(7) 72 Color3f color = e.getColor3f(); │ 73 cinterp.setEndColor(color); │ 74 } │ 75 }); ┘ 76 cpanels[1].add(etp); 77 78 GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); 79 Canvas3D canvas = new Canvas3D(config); 80 this.add(canvas, BorderLayout.CENTER); 81 82 SimpleUniverse universe = new SimpleUniverse(canvas); 83 universe.getViewingPlatform().setNominalViewingTransform(); 84 85 BranchGroup scene = createSceneGraph(); 86 universe.addBranchGraph(scene); 87 } 88 89 private BranchGroup createSceneGraph() { 90 BranchGroup root = new BranchGroup(); 91 root.setCapability(BranchGroup.ALLOW_DETACH); 92 93 DirectionalLight light = 94 new DirectionalLight( new Color3f(1.0f, 1.0f, 1.0f), 95 new Vector3f(-0.57f, -0.57f, -0.57f) ); 96 BoundingSphere bounds = new BoundingSphere(new Point3d(), 100.0); 97 light.setInfluencingBounds(bounds); 98 root.addChild(light); 99 100 AmbientLight alight = new AmbientLight(); 101 alight.setInfluencingBounds(bounds); 102 root.addChild(alight); 103 104 TransformGroup trans = new TransformGroup(); 105 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 106 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 107 trans.setCapability(TransformGroup.ENABLE_PICK_REPORTING); 108 root.addChild(trans); 109 110 MouseRotate rotator = new MouseRotate(); 111 rotator.setSchedulingBounds(bounds); 112 rotator.setTransformGroup(trans); 113 root.addChild(rotator); 114 115 Heart heart = new Heart(); 116 app = createAppearance(); 117 Shape3D shape = new Shape3D( heart.getGeometry(), app ); 118 trans.addChild(shape); 119 120 cinterp = createInterpolator( apanel.getAlpha(), app.getMaterial() );...(8) 121 root.addChild(cinterp); 122 123 return root; 124 } 125 126 private ColorInterpolator createInterpolator(Alpha alpha, Material mat) { ┐ 127 ColorInterpolator cinterp = │ 128 new ColorInterpolator(alpha, mat, scolor, ecolor);.....................(10) ├(9) 129 cinterp.setSchedulingBounds(new BoundingSphere(new Point3d(), 100.0));...(11) │ 130 return cinterp; │ 131 } ┘
(1)で ColorInterpolator
のインスタンスを保持するための変数を確保しています。
(2)で [Stop]/[Start]
ボタンを構築しています。最初は "Stop"
が表示され、ボタンがクリックされると "Start"
に変化します。ボタンクリックの処理では、Button#getLabel()
で得たラベル文字列を判断して、"Start"
なら開始処理、"Stop"
なら停止処理を行っています。
(3)の開始処理ではsetEnable(true)
で ColorInterpolator
を有効 (動作できる状態) にしています。
(4)でAlphaPanel#reset()
を使って、Alpha
の開始時刻を現在時刻に再設定しています。この処理をしないと loopCount
の値を変更してもうまく反映されません。ここでは AlphaPanel#reset()
を使用しましたが、Alpha
を直接使う場合は Alpha#setStartTime(System.currentTimeMillis())
を実行してください。
(5)でTuplePanel
を使って startColor
を変更するための 3つの TextField
を構築しています。(6)では、TuplePanel
への入力によって変更された色を ColorInterpolator#setStartColor()
メソッドで設定しています。
(7)では、(5)の startColor
のための処理と同様に
endoColor
のための GUIを TuplePanel
で構築しています。
(8)で ColorInterpolator
を生成しています。引数は、AlphaPanel#getAlpha()
で取得した Alpha
と、変更対象の Material
です。実際の処理は (9)の createColorInterpolator()
メソッドで行っています。
(10)で ColorInterpolator
を生成しています。(11)でスケジューリングが有効になる範囲を設定しています。
javax.media.j3d.TransparencyInterpolator
javax.media.j3d.TransparencyInterpolator
は javax.media.j3d.TransparencyAttributes
の透明度 (transparency
) を変化させます。
クラス宣言 public class TransparencyInterpolator extends Interpolator コンストラクター public TransparencyInterpolator(Alpha alpha, // 変化の元になる Alpha TransparencyAttributes target) // 変更対象の TransparencyAttributes public TransparencyInterpolator(Alpha alpha, // 変化の元になる Alpha TransparencyAttributes target, // 変更対象の TransparencyAttributes float minimumTransparency, // 初期の透明度 float maximumTransparency) // 終了時の透明度
TransparencyInterpolator
のコンストラクターでは、変更対象の TransparencyAttributes
、変化開始時の透明度 ( minimumTransparency
)、変化終了時の透明度 (maximumTransparency
)を指定します。minimumTransparency
のデフォルト値は 0.0f
、maximumTransparency
のデフォルト値は 1.0f
です。
サンプルの実行結果を見てください。
サンプルでは、Background
に空のグラフィックを適用しています。
TextField
に透明度を入力して、変化開始時と終了時の透明度を変更できます。
このサンプルのソースコードはCD-ROMを参照してください。
TransparencyInterpolatorTest.java
javax.media.j3d.ScaleInterpolator
javax.media.j3d.ScaleInterpolator
は TransformGroup
の scale
を変化させます。
クラス宣言 public class ScaleInterpolator extends Interpolator コンストラクター public ScaleInterpolator(Alpha alpha, // 変化の元になる Alpha TransformGroup target) // 変更対象の TransformGroup public ScaleInterpolator(Alpha alpha, // 変化の元になる Alpha TransformGroup target, // 変更対象の TransformGroup Transform3D axisOfScale, // 拡大縮小の対象軸 float minimumScale, // 初期の拡大縮小率 float maximumScale) // 終了時の拡大縮小率
ScaleInterpolator
のコンストラクターでは、変更対象の TransformGroup
、変化開始時の拡大縮小率、変化終了時の拡大縮小率を指定します。
変化開始時の拡大縮小率のデフォルト値は 0.1
、変化終了時の拡大縮小率のデフォルト値は 1.0
です。
サンプルの実行結果は次のようになります。
このサンプルのソースはCD-ROMを参照してください。
ScaleInterporatorTest.java
javax.media.j3d.PositionInterpolator
javax.media.j3d.PositionInterpolator
は、TransformGroup
の X軸方向への移動距離を変化させます。
クラス宣言 public class PositionInterpolator extends Interpolator コンストラクター public PositionInterpolator(Alpha alpha, // 変化の元になる Alpha TransformGroup target) // 変更対象の TransformGroup public PositionInterpolator(Alpha alpha, // 変化の元になる Alpha TransformGroup target, // 変更対象の TransformGroup Transform3D axisOfTranslation, // 移動方向軸 float startPosition, // 開始位置(開始距離) float endPosition) // 終了位置(終了距離)
PositionInterpolator
は、TransformGroup
の X軸方向への移動距離を変化させます。コンストラクター引数には変更対象の TransformGroup
、移動方向の軸となる Transfom3D
、開始距離、終了距離を指定します。開始距離のデフォルト値は 0.0
、終了距離のデフォルト値は 1.0
です。
axisOfTranslation
に指定した Transform3D
に回転を与て、任意の方向に移動させることができます。
サンプルプログラムの実行結果を見てください。
中央にある X, Y, Z軸は、回転対象の TransformGroup
に addChild()
されています。X, Y, Z軸を、マウスの左ボタンによるドラッグで回転させることができます。軸の中央の ColorCube
が PositionInterpolator
によって移動します。グリッド線と、奥にあるハート型は移動しません。
このサンプルのソースコードはCD-ROMを参照してください。
PositionInterpolatorTest.java
javax.media.j3d.RotationInterpolator
javax.media.j3d.RotationInterpolator
は、変更対象の TransformGroup
を Y軸を中心に回転させます。
クラス宣言 public class RotationInterpolator extends Interpolator コンストラクター public RotationInterpolator(Alpha alpha, // 変化の元になる Alpha TransformGroup target) // 変更対象の TransformGroup public RotationInterpolator(Alpha alpha, // 変化の元になる Alpha TransformGroup target, // 変更対象の TransformGroup Transform3D axisOfRotation, // 回転軸 float minimumAngle, // 初期の回転角 (ラジアン) float maximumAngle) // 終了時の回転角 (ラジアン)
RotanionInterpolator
は、変更対象の TransformGroup
を、Y軸を中心に回転させます。コンストラクター引数には変更対象の TransformGroup
、回転の軸となる Transform3D
、回転開始時の回転角、回転終了時の回転角を指定します。回転開始時の回転角のデフォルト値は 0.0
ラジアン、回転終了時の回転角のデフォルト値は 2π
ラジアン (360°) です。
サンプルプログラムの実行結果を見てください。
青い太線が回転しています。初期値では 1000ミリ秒 (1秒) で 1回転します。マウスの左ボタンドラッグで全体を回転させることができます。
このサンプルのソースコードは次の通りです。
RotataionInterpolatorTest.java (一部)81 private BranchGroup createSceneGraph() { : : 150 Transform3D rt3d = new Transform3D(); 151 rt3d.rotX( -(Math.PI / 2.0) );.................................(1) 152 rinterp = 153 new RotationInterpolator( apanel.getAlpha(), rtrans, rt3d, 154 0.0f, (float)Math.PI * 2.0f );.....(2) 155 rinterp.setSchedulingBounds(bounds);...........................(3) 156 root.addChild(rinterp);.................................................(4) 157 158 return root; 159 }
(1)で回転軸となる Transform3D
に対して X軸を中心とした 1/2π
(90°) の回転を与えています。
(2)で RotationInterpolator
を生成しています。引数には、(1)で回転させた Transform3D
を指定して、Y軸を中心とした回転を 90°傾けています。青い太線は変更対象の TransformGroup
の Z軸を中心に回転することになります。(3)でスケジューリングが有効になる領域を生成し、(4)で BranchGroup
に addChild()
しています。
javax.media.j3d.SwitchValueInterpolator
javax.media.j3d.SwitchValueInterpolator
は Switch
が有効にする子 Node
を変化させます。
クラス宣言 public class SwitchValueInterpolator extends Interpolator コンストラクター public SwitchValueInterpolator(Alpha alpha, // 変化の元になる Alpha Switch target) // 変更対象の Switch public SwitchValueInterpolator(Alpha alpha, // 変化の元になる Alpha Switch target, // 変更対象の Switch int firstChildIndex, // 最初に表示する子ノードの index int lastChildIndex) // 最終的に表示する子ノードの index
SwitchValueInterpolator
は、変更対象の Switch
に対して、最初に表示させる Node
の index と、最終的に表示させる Node
の index を指定して、その間を順番に表示させます。表示される Node
は常にどれか一つになります。
サンプルの実行結果を見てください。
5つの Box
が Switch
に addChild()
されています。左から順番に一つづつ表示されます。それぞれの Box
をマウスの左ボタンのドラッグで回転させることができますが、[Stop]
ボタンで停止させてからでないと回転させるのは難しいかもしれません。
このサンプルのソースはCD-ROMを参照してください。
SwitchValueInterpolatorTest.java
javax.media.j3d.PathInterpolator
Alpha 値は時間の経過とともに 0.0〜1.0
の範囲で変化します。javax.media.j3d.PathInterpolator
は、0.0〜1.0
の範囲のどこかに変化点を設定し、その時点での状態をあらかじめ設定しておきます。たとえば、0.0
のときの位置座標と、1.0
のときの位置座標を設定しておけば、0.0
のときの位置から 1.0
のときの位置まで物体を移動させることができます。
0.0〜1.0
の範囲で変化点を複数用意すれば、そのそれぞれ間で状態を変化させることができます。たとえば、0.0
、0.5
、1.0
のときの位置座標を設定しておけば、はじめ 0.0
のときの位置から 0.5
のときの位置まで移動し、つぎに 0.5
のときの位置から 1.0
のときの位置まで移動します。
クラス継承 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.PathInterpolator | +--javax.media.j3d.PositionPathInterpolator | +--javax.media.j3d.RotationPathInterpolator | +--javax.media.j3d.RotPosPathInterpolator | +--javax.media.j3d.RotPosScalePathInterpolator クラス宣言 public abstract class PathInterpolator extends Interpolator コンストラクター public PathInterpolator(Alpha alpha, // 変化の元になる Alpha float[] knots) // 変化点ごとの変化量 (Alpha値)
knots
は変化点の Alpha値の配列です。最初の要素は 0.0f
、最後の要素は 1.0f
である必要があります。最も変化点が少ない場合、配列は 0.0f
と 1.0f
の 2つの要素数になります。配列の各要素は 0.0〜1.0
の範囲の値を持ち、一つ前の要素よりも大きい値である必要があります。
PathInterpolator
は抽象クラス (abstract class) です。実際にはそのサブクラスである PositionInterpolator, RotationPathInterpolator, RotPosPathInterpolator, RotPosScalePathInterpolator
などを使用します。
javax.media.j3d.PositionPathInterpolator
javax.media.j3d.PositionPathInterpolator
は、変化点ごとに位置座標を設定し、その間を移動させる Interpolator です。
クラス宣言 public class PositionPathInterpolator extends PathInterpolator コンストラクター public PositionPathInterpolator(Alpha alpha, // 変化の元になる Alpha TransformGroup target, // 変更対象の TransformGroup Transform3D axisOfTranslation, // 移動時の軸となる座標系 float[] knots, // 変化点ごとの変化量 (Alpha値) Point3f[] positions) // 変化点ごとの移動座標
コンストラクターの引数には、移動対象の TransformGroup
である target
を指定します。axisOfTranslation
に指定した Transform3D
に回転を与えれば、移動させる際の座標系を回転させることができます。
knots
に変化点の Alpha値の配列を指定し、positions
に変化点の位置座標を指定します。
サンプルの実行結果を見てください。
変化点ごとの位置座標に色の付いた点を描画しています。ColorCube
が設定した座標の間を移動して行きます。TextField
に X, Y, Z座標を指定すると位置座標が変更できます。変化点ごとの Alpha値を変更すると、変化のタイミングが変化点ごとに変更できます。
マウスの左ボタンのドラッグで全体を回転させることができます。
このサンプルのソースコードは次の通りです。
PositionPathTest.java (一部)212 private BranchGroup createSceneGraph() { : : 254 pverts = new Point3f[4]; ┐ 255 pverts[0] = (Point3f)tp0.getTuple3f(); │ 256 pverts[1] = (Point3f)tp1.getTuple3f(); ├(1) 257 pverts[2] = (Point3f)tp2.getTuple3f(); │ 258 pverts[3] = (Point3f)tp3.getTuple3f(); ┘ 259 pshape = createPoints(pverts); 260 mtrans.addChild(pshape); 261 262 TransformGroup rtrans = createCube(0.05, new Vector3d(0.0, 0.0, 0.0)); 263 mtrans.addChild(rtrans); 264 265 Transform3D rt3d = new Transform3D(); 266 267 pinterp = 268 new PositionPathInterpolator( apanel.getAlpha(), rtrans, rt3d, 269 knots, pverts );..................(2) 270 pinterp.setSchedulingBounds(bounds);..............................(3) 271 pinterp.setEnable(false);.........................................(4) 272 root.addChild(pinterp);...........................................(5) 273 274 return root; 275 } 276 277 private Shape3D createPoints(Point3f[] pverts) { 278 TransformGroup trans = new TransformGroup(); 279 float[] colors = { 1.0f, 0.0f, 0.0f, // red 280 1.0f, 0.5f, 0.0f, // orange 281 1.0f, 1.0f, 0.0f, // yellow 282 0.5f, 1.0f, 0.0f }; // green 283 PointArray pgeom = 284 new PointArray( pverts.length, 285 GeometryArray.COORDINATES | GeometryArray.COLOR_3); 286 pgeom.setCoordinates(0, pverts); 287 pgeom.setColors(0, colors); 288 Appearance papp = new Appearance(); 289 papp.setPointAttributes( new PointAttributes(6.0f, false) ); 290 return new Shape3D(pgeom, papp); 291 } 292 293 private TransformGroup createCube(double size, Vector3d position) { 294 Transform3D t3d = new Transform3D(); 295 t3d.set(position); 296 TransformGroup trans = new TransformGroup(t3d); 297 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 298 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 299 trans.setCapability(TransformGroup.ENABLE_PICK_REPORTING); 300 trans.addChild( new ColorCube(size) ); 301 return trans; 302 }
(1)で変化点ごとの位置座標の配列 pverts_
を初期化しています。TuplePanel
の getTuple3f()
メソッドを使って Tuple3f
を取り出し、Point3f
にキャストして配列要素にそれぞれ代入しています。
TuplePanel
ですが、PositionPathTest
クラスの最初で宣言しています。
25 private TuplePanel tp0 = new TuplePanel( new Point3f( 0.0f, -0.6f, 0.1f) ); 26 private TuplePanel tp1 = new TuplePanel( new Point3f(-0.4f, -0.2f, 0.1f) ); 27 private TuplePanel tp2 = new TuplePanel( new Point3f( 0.4f, 0.2f, 0.1f) ); 28 private TuplePanel tp3 = new TuplePanel( new Point3f( 0.0f, 0.6f, 0.1f) );
各点の X, Y, Z座標を入力するための TuplePanel
を 4つ宣言し、それぞれに座標の初期値を与えています。
(2)で PositionPathInterpolator
を生成しています。
(3)でスケジューリングが有効になる領域を設定し、(4)で setEnable(false)
で変化を停止させています。[Start]
ボタンを押すと変化を開始するようにしました。(5)で BranchGroup
に addChild()
しています。
javax.media.j3d.RotationPathInterpolator
javax.media.j3d.RotationPathInterpolator
は、変化点ごとに回転値を設定し、その間で回転させる Interpolator
です。
クラス宣言public class RotationPathInterpolator extends PathInterpolator コンストラクター public RotationPathInterpolator(Alpha alpha, // 変化の元になる Alpha TransformGroup target, // 変更対象の TransformGroup Transform3D axisOfRotation, // 回転時の軸となる座標系 float[] knots, // 変化点ごとの変化量 (Alpha値) Quat4f[] quats) // 変化点ごとの回転値 (四元数)
コンストラクターの引数には変更対象の TransformGroup
、軸となる座標系の Transform3D
を与えます。Transform3D
に回転を与えておけば、回転の基準となる座標系をあらかじめ傾けておくことができます。
変化点ごとの回転値は四元数 Quat4f
で与えます。AxisAngle4f
なをど使用したい場合には、まず AxisAngle4f
を生成し、Quat4f
の set(AxisAngle4f)
メソッドで Quat4f
に設定してください。
このサンプルの実行結果を見てください。
変化点は 3点設定しました。手前にある小さい ColorCube
それぞれをマウスの左ボタンのドラッグで回転させることができます。小さい ColorCube
の回転を Quat4f
に取得して、変化点ごとの回転値として設定しています。
[Start]
ボタンを押すと中央の大きい ColorCube
が回転します。手前の小さい ColorCube
をマウスで回転させると、変化点ごとの回転値が即座に変更されます。
グリッドの四隅の立方体をマウスの左ボタンでドラッグすると、全体を回転させることができます。
このサンプルのソースはCD-ROMを参照してください。
RotationPathTest.java
javax.media.j3d.RotPosPathInterpolator
javax.media.j3d.RotPosPathInterpolator
は、変化点ごとに位置座標と回転値を設定して、位置と回転を変化させることができる Interpolator です。
クラス宣言 public class RotPosPathInterpolator extends PathInterpolator コンストラクター public RotPosPathInterpolator(Alpha alpha, // 変化の元になる Alpha TransformGroup target, // 変更対象の TransformGroup Transform3D axisOfRotPos, // 移動、回転の軸になる座標系 float[] knots, // 変化点ごとの変化量 (Alpha値) Quat4f[] quats, // 変化点ごとの回転値 (四元数) Point3f[] positions) // 変化点ごとの移動座標
コンストラクターの引数では、変更対象の TransformGroup
と、移動、回転の軸になる座標系の Transform3D
を指定します。Transform3D
に回転を与えると、移動、回転の軸になる座標系を傾けることができます。
knots
には変化点ごとの Alpha値の配列を設定します。quats
に変化点ごとの回転値を、positions
に変化点ごとの位置座標を指定します。knots, quats, positions
の要素数は同じである必要があります。
サンプルプログラムの実行結果を見てください。
下にある k0〜k3
の TextField
に Alhpa値を入力すると、変化点ごとの Alpha値を変更することができます。
変化点ごとの位置座標に小さい ColorCube
が置いてあり、マウスの左ボタンドラッグで回転させることができます。下にある TextField
に X, Y, Z座標を入力すると変化点ごとの位置座標を変えることができます。小さい ColorCube
の位置も移動します。
グリッドの四隅の立方体をマウスの左ボタンでドラッグすると、全体を回転させることができます。
このサンプルのソースはCD-ROMを参照してください。
RotPosPathTest.java
javax.media.j3d.RotPosScalePathInterpolator
javax.media.j3d.RotPosScalePathInterpolator
は、変化点ごとに回転値、位置座標、拡大縮小倍率を設定し、その間を変化させる Interpolator
です。
クラス宣言 public class RotPosScalePathInterpolator extends PathInterpolator コンストラクター public RotPosScalePathInterpolator(Alpha alpha, // 変化の元になる Alpha TransformGroup target, // 変更対象の TransformGroup Transform3D axisOfRotPosScale, // 回転、移動、拡大縮小の軸になる座標系 float[] knots, // 変化点ごとの変化量 (Alpha値) Quat4f[] quats, // 変化点ごとの回転値 (四元数) Point3f[] positions, // 変化点ごとの移動座標 float[] scales) // 変化点ごとの拡大縮小率
コンストラクターでは、変更対象となる TransformGroup
と回転、移動、拡大縮小の軸になる Transform3D
、変化点ごとの変化量になる Alpha値、変化点ごとの回転値、変化点ごとの位置座標、そして変化点ごとの拡大縮小率を指定します。拡大縮小率は 1.0f
が等倍で、1.0f
より小さければ縮小、1.0f
より大きければ拡大です。
サンプルの実行結果を見てください。
Alpha値を k0〜k3
の TextField
に入力すると変化点ごとの Alpha値を変更することができます。
変化点ごとの位置座標に小さい ColorCube
が置いてあります。マウスの左ボタンのドラッグで ColorCube
を回転させることができます。ColorCube
の回転は、変化点ごとの回転値として即座に反映されます。
X, Y, Z座標を TextField
に入力して、変化点ごとの位置座標を変更することができます。位置座標を変更すると、小さい ColorCube
も移動します。
s0〜s3
の TextField
に拡大縮小率を入力して、変化点ごとの拡大縮小率を変更することができます。拡大縮小率を変更すると、小さい ColorCube
も拡大縮小されます。
このサンプルのソースはCD-ROMを参照してください。
RotPosScalePathTest.java
com.sun.j3d.utils.behaviors.interpolators.TCBSplinePatheInterpolator
com.sun.j3d.utils.behaviors.interpolators.TCBSplinePatheInterpolator
は、変化点ごとに TCBKeyFrame
オブジェクトを設定してその間をスプライン補間して変化させる Interpolator
です。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Leaf | +--javax.media.j3d.Behavior | +--javax.media.j3d.Interpolator | +--com.sun.j3d.utils.behaviors.interpolators.TCBSplinePathInterpolator クラス宣言 public abstract class TCBSplinePathInterpolator extends Interpolator コンストラクター public TCBSplinePathInterpolator(Alpha alpha, // 変化の元になる Alpha TCBKeyFrame[] keys) // 変化点ごとの TCBKeyFrame
コンストラクターでは TCBKeyFrame
の配列を指定します。
クラス継承 java.lang.Object | +--com.sun.j3d.utils.behaviors.interpolators.TCBKeyFrame クラス宣言 public class TCBKeyFrame extends java.lang.Object コンストラクター public TCBKeyFrame(TCBKeyFrame kf) // 初期値となる TCBKeyFrame public TCBKeyFrame(float k, // 変化点ごとの変化量 (Alpha値) int l, // 一次補間かスプライン補間かのフラグ Point3f pos, // 変化点ごとの移動座標 Quat4f q, // 変化点ごとの回転値 (四元数) Point3f s, // 変化点ごとの拡大縮小率(x, y, z各軸) float t, // 張力 (tention) float c, // 連続性 (continuity) float b) // 傾斜 (bias)
コンストラクター引数は、変化点ごとの変化量 k
、位置座標 pos
、回転値 q
、拡大縮小率 s
などを指定します。拡大縮小率は X, Y, Z軸各軸ごとに指定できます。
フラグ l
に 0
を指定するとスプライン補間が使用されます。1
を指定すると、スプライン補間ではなく一次補間が使用されます。デフォルト値は 0
です。
TCBスプラインを使ったスプライン補間では、t, c, b
のそれぞれの値を
t
(tention:張力) は曲線のゆるやかさを変化させます。張力 (tention) が負の値のとき、曲線はゆるやかになります。
正の値のとき曲線はきつくなります。
c
(continuity:連続性) は、変化点を通過する際の角度変化を急激にするか、ゆるやかにするかを左右します。連続性 (continuity) が 0
のとき角度はゆるやかになります。
0
以外のとき角度は急になります。
b
(bias) は、変化点を通過する曲線の接線方向の傾斜を変化させます。傾斜 (bias) が負のとき変化点の開始側のカーブが大きくなり、終了側の傾斜が急になります。
正のときは変化の開始側の傾斜が急になり、終了側のカーブが大きくなります。
TCBSplinePathInterpolator
は抽象クラスです。実際にはそのサブクラスの RotPosScaleTCBSplinePathInterpolator
を使用します。
com.sun.j3d.utils.behaviors.interpolators.RotPosScaleTCBSplinePathInterpolator
com.sun.j3d.utils.behaviors.interpolators.RotPosScaleTCBSplinePathInterpolator
は、変化点ごとに TCBKeyFrame
を設定し、その間をスプライン補間して変化させる Interpolator
です。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.Node | +--javax.media.j3d.Leaf | +--javax.media.j3d.Behavior | +--javax.media.j3d.Interpolator | +--com.sun.j3d.utils.behaviors.interpolators.TCBSplinePathInterpolator | +--com.sun.j3d.utils.behaviors.interpolators.RotPosScaleTCBSplinePathInterpolator クラス宣言 public class RotPosScaleTCBSplinePathInterpolator extends TCBSplinePathInterpolator コンストラクター public RotPosScaleTCBSplinePathInterpolator(Alpha alpha, // 変化の元になる Alpha TransformGroup target, // 変更対象の TransformGroup Transform3D axisOfRotPosScale, // 変更時のローカル座標系 TCBKeyFrame[] keys) // 変化点ごとの TCBKeyFrame
コンストラクターでは変更対象の TransformGroup
、変化の軸になる Transform3D
、変化点ごとの TCBKeyFrame
の配列を指定します。
サンプルの実行結果を見てください。
変化点ごとに小さい ColorCube
が置いてあり、マウスの左ボタンドラッグで回転、中央ボタンドラッグで Z軸方向への移動、右ボタンドラッグで X、Y方向への移動ができます。
k0〜k3
の TextField
に Alpha値を入力すると、変化点ごとの Alpha値を変更することができます。
t, c, b
のそれぞれの TextField
に -1.0〜+1.0
の値を入力すると変化点ごとの張力、連続性、傾斜を変更することができます。
s0〜s3
の TextField
に拡大縮小率を入力すると、変化点ごとの拡大縮小率を変更できます。拡大縮小率は X, Y, Z軸それぞれに設定することも可能ですが、ここではすべての軸に同じ拡大縮小率を適用しています。
[Gen]
ボタンを押すと RotPosScaleTCBSplinePathInterpolator
を生成し、変化を開始します。TCBSplinePathInterpolator
には、動作の途中で TCBKeyFrame
の値を変更するためのメソッドが無いのでこのようにしました。
このサンプルのソースは次の通りです。
TCBSplinePathTest.java (一部)1 // Java 3D Test Applet 2 // TCBSplinePathTest.java 3 // Copyright (c) 1999 ENDO Yasuyuki 4 // mailto:yasuyuki@javaopen.org 5 // http://www.javaopen.org/j3dbook/index.html 6 7 import java.applet.*; 8 import java.awt.*; 9 import java.awt.event.*; 10 import javax.media.j3d.*; 11 import javax.vecmath.*; 12 import com.sun.j3d.utils.applet.MainFrame; 13 import com.sun.j3d.utils.universe.SimpleUniverse; 14 import com.sun.j3d.utils.behaviors.picking.PickRotateBehavior; 15 import com.sun.j3d.utils.behaviors.picking.PickTranslateBehavior; 16 import com.sun.j3d.utils.behaviors.picking.PickZoomBehavior; 17 import com.sun.j3d.utils.behaviors.picking.PickObject; 18 import com.sun.j3d.utils.behaviors.picking.PickingCallback; 19 import com.sun.j3d.utils.geometry.ColorCube; 20 import com.sun.j3d.utils.geometry.Primitive; 21 import com.sun.j3d.utils.geometry.Box; 22 import com.sun.j3d.utils.behaviors.interpolators.RotPosScaleTCBSplinePathInterpolator; 23 import com.sun.j3d.utils.behaviors.interpolators.TCBKeyFrame; 24 25 public class TCBSplinePathTest extends Applet { 26 private Canvas3D canvas = null; 27 private SimpleUniverse universe = null; 28 private BranchGroup scene = null; 29 private Point3f[] points = null; 30 private TCBKeyFrame[] keys = null; 31 private TransformGroup[] strans = null; 32 private AlphaPanel apanel = null; 33 private TransformGroup ctrans = null; 34 private BoundingSphere bounds = null; 35 private RotPosScaleTCBSplinePathInterpolator rinterp = null; : 435 private BranchGroup createSceneGraph() { 436 BranchGroup root = new BranchGroup(); 437 root.setCapability(BranchGroup.ALLOW_DETACH); 438 439 bounds = new BoundingSphere(new Point3d(), 100.0); 440 441 TransformGroup mtrans = new TransformGroup(); 442 mtrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 443 mtrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 444 mtrans.setCapability(TransformGroup.ENABLE_PICK_REPORTING); 445 mtrans.setUserData("mtrans"); 446 root.addChild(mtrans); 447 448 final TransformGroup rtrans = new TransformGroup(); 449 rtrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 450 rtrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 451 root.addChild(rtrans); 452 453 points = new Point3f[4]; 454 points[0] = new Point3f( 0.0f, -0.6f, 0.1f); 455 points[1] = new Point3f(-0.4f, -0.2f, 0.1f); 456 points[2] = new Point3f( 0.4f, 0.2f, 0.1f); 457 points[3] = new Point3f( 0.0f, 0.6f, 0.1f); 458 459 keys = new TCBKeyFrame[4]; 460 461 keys[0] = 462 new TCBKeyFrame(0.0f, 0, new Point3f(points[0]), 463 new Quat4f(0.0f, 0.0f, 0.0f, 0.0f), 464 new Point3f(1.0f, 1.0f, 1.0f), 0.0f, 0.0f, 0.0f); 465 keys[1] = 466 new TCBKeyFrame(0.4f, 0, new Point3f(points[1]), 467 new Quat4f(0.0f, 0.0f, 0.0f, 0.0f), 468 new Point3f(1.0f, 1.0f, 1.0f), 0.0f, 0.0f, 0.0f); 469 keys[2] = 470 new TCBKeyFrame(0.6f, 0, new Point3f(points[2]), 471 new Quat4f(0.0f, 0.0f, 0.0f, 0.0f), 472 new Point3f(1.0f, 1.0f, 1.0f), 0.0f, 0.0f, 0.0f); 473 keys[3] = 474 new TCBKeyFrame(1.0f, 0, new Point3f(points[3]), 475 new Quat4f(0.0f, 0.0f, 0.0f, 0.0f), 476 new Point3f(1.0f, 1.0f, 1.0f), 0.0f, 0.0f, 0.0f); 477 478 TransformGroup[] ptrans = new TransformGroup[4]; 479 for (int i=0; i<4; i++) { 480 Transform3D pt3d = new Transform3D(); 481 pt3d.set( new Vector3f( (Tuple3f)keys[i].position ) ); 482 ptrans[i] = new TransformGroup(pt3d); 483 ptrans[i].setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 484 ptrans[i].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 485 rtrans.addChild(ptrans[i]); 486 } 487 488 strans = new TransformGroup[4]; 489 for (int i=0; i<4; i++) { 490 strans[i] = createCube(0.05, new Vector3d(), true); 491 strans[i].setUserData("p" + Integer.toString(i)); 492 ptrans[i].addChild(strans[i]); 493 } 494 495 PickRotateBehavior mrotator = 496 new PickRotateBehavior(root, canvas, bounds, PickObject.USE_GEOMETRY); 497 mrotator.setupCallback( new PickingCallback() { 498 public void transformChanged(int type, TransformGroup trans) { 499 if (trans != null) { 500 String udata = (String)trans.getUserData(); 501 if (udata != null) { 502 //System.out.println(udata);//DEBUG 503 Transform3D t3d = new Transform3D(); 504 trans.getTransform(t3d); 505 if (udata.equals("mtrans")) { 506 rtrans.setTransform(t3d); 507 } else if (udata.equals("p0")) { 508 Quat4f quat = new Quat4f(); 509 t3d.get(quat); 510 keys[0].quat = quat; // TEST 511 } else if (udata.equals("p1")) { 512 Quat4f quat = new Quat4f(); 513 t3d.get(quat); 514 keys[1].quat = quat; 515 } else if (udata.equals("p2")) { 516 Quat4f quat = new Quat4f(); 517 t3d.get(quat); 518 keys[2].quat = quat; 519 } else if (udata.equals("p3")) { 520 Quat4f quat = new Quat4f(); 521 t3d.get(quat); 522 keys[3].quat = quat; 523 } 524 } 525 } 526 } 527 }); 528 root.addChild(mrotator); 529 530 PickTranslateBehavior translator = 531 new PickTranslateBehavior(root, canvas, bounds, PickObject.USE_GEOMETRY); 532 translator.setupCallback( new PickingCallback() { 533 public void transformChanged(int type, TransformGroup trans) { 534 if (trans != null) { 535 String udata = (String)trans.getUserData(); 536 if (udata != null) { 537 //System.out.println(udata);//DEBUG 538 Transform3D t3d = new Transform3D(); 539 trans.getTransform(t3d); 540 if (udata.equals("mtrans")) { 541 rtrans.setTransform(t3d); 542 } else if (udata.equals("p0")) { 543 Vector3f pos = new Vector3f(); 544 t3d.get(pos); 545 keys[0].position.x = points[0].x + pos.x; 546 keys[0].position.y = points[0].y + pos.y; 547 } else if (udata.equals("p1")) { 548 Vector3f pos = new Vector3f(); 549 t3d.get(pos); 550 keys[1].position.x = points[1].x + pos.x; 551 keys[1].position.y = points[1].y + pos.y; 552 } else if (udata.equals("p2")) { 553 Vector3f pos = new Vector3f(); 554 t3d.get(pos); 555 keys[2].position.x = points[2].x + pos.x; 556 keys[2].position.y = points[2].y + pos.y; 557 } else if (udata.equals("p3")) { 558 Vector3f pos = new Vector3f(); 559 t3d.get(pos); 560 keys[3].position.x = points[3].x + pos.x; 561 keys[3].position.y = points[3].y + pos.y; 562 } 563 } 564 } 565 } 566 }); 567 root.addChild(translator); 568 569 PickZoomBehavior zoomer = 570 new PickZoomBehavior(root, canvas, bounds, PickObject.USE_GEOMETRY); 571 zoomer.setupCallback( new PickingCallback() { 572 public void transformChanged(int type, TransformGroup trans) { 573 if (trans != null) { 574 String udata = (String)trans.getUserData(); 575 if (udata != null) { 576 //System.out.println(udata);//DEBUG 577 Transform3D t3d = new Transform3D(); 578 trans.getTransform(t3d); 579 if (udata.equals("mtrans")) { 580 rtrans.setTransform(t3d); 581 } else if (udata.equals("p0")) { 582 Vector3f pos = new Vector3f(); 583 t3d.get(pos); 584 keys[0].position.z = points[0].z + pos.z; 585 } else if (udata.equals("p1")) { 586 Vector3f pos = new Vector3f(); 587 t3d.get(pos); 588 keys[1].position.z = points[1].z + pos.z; 589 } else if (udata.equals("p2")) { 590 Vector3f pos = new Vector3f(); 591 t3d.get(pos); 592 keys[2].position.z = points[2].z + pos.z; 593 } else if (udata.equals("p3")) { 594 Vector3f pos = new Vector3f(); 595 t3d.get(pos); 596 keys[3].position.z = points[3].z + pos.z; 597 } 598 } 599 } 600 } 601 }); 602 root.addChild(zoomer); 603 604 double[] vertices = { -0.8, -0.8, 0.0, 605 -0.8, 0.8, 0.0, 606 -0.4, -0.8, 0.0, 607 -0.4, 0.8, 0.0, 608 0.0, -0.8, 0.0, 609 0.0, 0.8, 0.0, 610 0.4, -0.8, 0.0, 611 0.4, 0.8, 0.0, 612 0.8, -0.8, 0.0, 613 0.8, 0.8, 0.0, 614 -0.8, -0.8, 0.0, 615 0.8, -0.8, 0.0, 616 -0.8, -0.4, 0.0, 617 0.8, -0.4, 0.0, 618 -0.8, 0.0, 0.0, 619 0.8, 0.0, 0.0, 620 -0.8, 0.4, 0.0, 621 0.8, 0.4, 0.0, 622 -0.8, 0.8, 0.0, 623 0.8, 0.8, 0.0 }; 624 625 LineArray geom = new LineArray( vertices.length / 3, GeometryArray.COORDINATES); 626 geom.setCapability(GeometryArray.ALLOW_INTERSECT); 627 geom.setCoordinates(0, vertices); 628 Shape3D grid = new Shape3D(geom); 629 grid.setCapability(Shape3D.ALLOW_GEOMETRY_READ); 630 mtrans.addChild(grid); 631 632 mtrans.addChild( createCorner(0.05f, new Vector3d(-0.8, -0.8, 0.0)) ); 633 mtrans.addChild( createCorner(0.05f, new Vector3d( 0.8, -0.8, 0.0)) ); 634 mtrans.addChild( createCorner(0.05f, new Vector3d(-0.8, 0.8, 0.0)) ); 635 mtrans.addChild( createCorner(0.05f, new Vector3d( 0.8, 0.8, 0.0)) ); 636 637 ctrans = createCube(0.05, new Vector3d(0.0, 0.0, 0.1), false); 638 rtrans.addChild(ctrans); 639 640 rinterp = createInterpolator(apanel.getAlpha(), ctrans, keys, bounds);...(1) 641 rinterp.setEnable(false);................................................(2) 642 root.addChild(rinterp);..................................................(3) 643 644 return root; 645 } 646 647 private RotPosScaleTCBSplinePathInterpolator 648 createInterpolator( Alpha alpha, TransformGroup trans, 649 TCBKeyFrame[] keys, Bounds bounds ) 650 { 651 Transform3D t3d = new Transform3D(); 652 RotPosScaleTCBSplinePathInterpolator rinterp = 653 new RotPosScaleTCBSplinePathInterpolator(alpha, trans, t3d, keys);...(4) 654 rinterp.setSchedulingBounds(bounds);...................................(5) 655 return rinterp; 656 }
private メソッド createInterpolator
を実行して RotPosScaleTCBSplinePathInterpolator
を生成しています(1)。(2)で setEnable(false)
を使って変化を停止させています。(3)で BranchGroup
に addChild()
しています。
createInterpolator
メソッドでは、(4)で RotPosScaleTCBSplinePathInterpolator
を生成し、(5)でスケジューリングが有効になる領域を設定しています。このメソッドは [Gen]
ボタンが押されるたびに実行され 、変更された TCBKeyFrame
の配列をもとに新たな RotPosScaleTCBSplinePathInterpolator
が生成されます。
[Gen]
ボタンの構築は次のようにしました。
ENDO Yasuyuki53 final Button sbutton = new Button("Gen"); 54 sbutton.addActionListener( new ActionListener() { 55 public void actionPerformed(ActionEvent e) { 56 String blabel = sbutton.getLabel(); 57 if (blabel.equals("Gen")) { 58 universe.getLocale().removeBranchGraph(scene); 59 removeChild(scene, rinterp); 60 rinterp = createInterpolator(apanel.getAlpha(), ctrans, keys, bounds); 61 addChild(scene, rinterp); 62 apanel.reset(); 63 universe.addBranchGraph(scene); 64 sbutton.setLabel("Stop"); 65 } else if (blabel.equals("Stop")) { 66 rinterp.setEnable(false); 67 sbutton.setLabel("Gen"); 68 } 69 } 70 }); 71 ppanels[0].add(sbutton);