Sun, 19 Feb 2006
IndexedGeometryArray で TEXTURE_COORDINATE_2を指定する場合
テクスチャーに使う画像は Appearance の setTexture で与える。
IndexedGeometryArray の中で行うことは
- setTextureCoordinate() でテクスチャーに使う画像上の点に番号をつける。
- setTextureCoordinateIndex() で上で付けた点と setCoordinateIndex() で番号づけした点との対応を与える。
が全てである。
テクスチャーに使う画像上の点を与える方法
テクスチャーに使う画像の座標系は (s,t) で表され、画像の大きさにかかわらず、
0 から 1 までの値をとる。
例
下の例では、立方体の各面に画像を張り付けている。TexCoord2f[] t でテクスチャー画像上の点を
8個取り出して、setTextureCoordinateIndices() でそれを立方体の各頂点に対応させている。
立方体に張り付けるときに、大きさを自動的に変換していることに注意する。
import javax.media.j3d.*;
import javax.vecmath.*;
class DiceGeometry extends IndexedQuadArray{
double[] coord;
DiceGeometry(){
super(8,
IndexedLineArray.COORDINATES|
IndexedLineArray.TEXTURE_COORDINATE_2,
24);
coord = new double[3*8];
createGeometry();
setCoordinates(0,coord);
createTexture();
}
public void createGeometry(){
// 0
coord[0] = 0.5;
coord[1] = 0.5;
coord[2] = 0.5;
// 1
coord[3] = -0.5;
coord[4] = 0.5;
coord[5] = 0.5;
// 2
coord[6] = -0.5;
coord[7] = -0.5;
coord[8] = 0.5;
// 3
coord[9] = 0.5;
coord[10] = -0.5;
coord[11] = 0.5;
// 4
coord[12] = 0.5;
coord[13] = 0.5;
coord[14] = -0.5;
// 5
coord[15] = -0.5;
coord[16] = 0.5;
coord[17] = -0.5;
// 6
coord[18] = -0.5;
coord[19] = -0.5;
coord[20] = -0.5;
// 7
coord[21] = 0.5;
coord[22] = -0.5;
coord[23] = -0.5;
// index の設定
setCoordinateIndex(0,0);
setCoordinateIndex(1,1);
setCoordinateIndex(2,2);
setCoordinateIndex(3,3);
setCoordinateIndex(4,0);
setCoordinateIndex(5,4);
setCoordinateIndex(6,5);
setCoordinateIndex(7,1);
setCoordinateIndex(8,0);
setCoordinateIndex(9,3);
setCoordinateIndex(10,7);
setCoordinateIndex(11,4);
setCoordinateIndex(12,1);
setCoordinateIndex(13,5);
setCoordinateIndex(14,6);
setCoordinateIndex(15,2);
setCoordinateIndex(16,5);
setCoordinateIndex(17,4);
setCoordinateIndex(18,7);
setCoordinateIndex(19,6);
setCoordinateIndex(20,2);
setCoordinateIndex(21,6);
setCoordinateIndex(22,7);
setCoordinateIndex(23,3);
}
public void createTexture(){
TexCoord2f[] t = new TexCoord2f[8];
t[0] = new TexCoord2f(0.5f, 0.5f);
t[1] = new TexCoord2f(0f, 0.5f);
t[2] = new TexCoord2f(0f, 0f);
t[3] = new TexCoord2f(0.5f, 0f);
t[4] = new TexCoord2f(1.0f, 0.5f);
t[5] = new TexCoord2f(0.5f, 0.5f);
t[6] = new TexCoord2f(0.5f, 0f);
t[7] = new TexCoord2f(1.0f, 0f);
setTextureCoordinates(0, 0, t);
int ind[] = new int[]{0,3,2,1,
7,6,5,4,
1,2,3,0,
5,4,7,6,
2,3,0,1,
2,7,4,1};
setTextureCoordinateIndices(0, 0, ind);
}
}
posted at 16:55 |
category: /Java/Java3DTips |
固定リンク(テクスチャーの貼り付け方)
Picking した物体の座標を得るには
com.sun.j3d.utils.picking.behaviors.PickingCallback
インターフェースを使うと良い。
PickRotateBehavior や PickTranslateBehavior には
setupCallback() メソッドがあるので、それを使って、
結びつける。すると、Picking した TransformGroup の値が変化したときには
setupCallback(PickingCallback callback) によって結びつけられた callback
の transformChanged() メソッドが実行される。
ActionListner と使い方は似ているので、比較してみると分かりやすいかもしれない。
| インターフェース名 |
ActionListener |
PickingCallback |
| 点火元と結びつけるメソッド |
addActionLisnter() |
setupCallback() |
| 動作を定義するメソッド |
actionPerformed() |
transformChanged() |
PickCallback を継承したクラスを作成し、その中の transformChanged()
メソッドの中に実際の処理を書く。そして、PickTranslateBehavior などの
インスタンスに setupCallback() メソッドでこのクラスのインスタンスを
結びつければ良い。
例えば Picking された TransformGroup の座標を調べるには
PickTranslateBehavior pickTrans
= new PickTranslateBehavior(scene,this,bounds);
pickTrans.setupCallback(new PickingCallback(){
Vector3d vect = new Vector3d(); // 座標を格納する
Transform3D t3d = new Transform3D();
public void transformChanged(int type,TransformGroup tg){
if(type == PickingCallback.TRANSLATE){
tg.getTransform(t3d);
t3d.get(vect);
// ここで座標の処理をする。
}
}
});
のようになる。単に座標を表示するだけのプログラムをサンプルとして下に挙げる。
posted at 16:54 |
category: /Java/Java3DTips |
固定リンク(Picking した物体の座標を得るには)
天球のシミュレーション (Java Web Start)
恒星の位置を取得して、プラネタリウムのようなものを Java3D
で作ってみました。6等星まで表示するようになっています。
恒星のデータは外部のXMLファイルで記述してあります。
履歴
- 2003/6/22
- 恒星の位置情報をXMLファイルで記述して、直径20の球面上に
星を配置してプラネタリウムのようなものを作る。
参考リンク
posted at 16:44 |
category: /Program |
固定リンク(プラネタリウム)
花火のシミュレーション (Java Web Start)
夏の風物詩といえば花火ですが、それを Java3D でシミュレーションしようと思う。
できれば玉にどのように火薬を詰めるか、
どの方向に爆発させるかなどについえもシミュレーションできるようにしたい。
種類
よく言われる打ち上げ花火(正確には「打ち上げ玉」)の中にも、
割物、ポカ物、昇り曲、仕掛け花火などがあり、
代表的な割物の中にも、菊、牡丹、冠、千輪、などがある。
詳しくは参考文献を見てほしい。
色
色は金属の炎色反応で決まる。
紅色は炭酸ストロンチウム、緑色は硝酸バリウム、
黄色はシュウ酸ソーダ、青色は酸化銅、
白色はアルミニウムなどを使うらしい。
シミュレーション
花火を飛ばすための「割薬」と、光を出すための「星」を
「玉皮」の中に詰めることによって、玉ができる。
Java3D によるシミュレーションではこの玉を BranchGroup とし、
そのなかにいろいろな星を Shape3D として
addChild することにする。
適当なキーを押すと開始し、スペースキーを押すと止まります。
マウスによって、視点を動かせるので、花火が上がっている中を小型セスナで
アクロバット飛行をする気分が味わえます。
参考文献
posted at 16:34 |
category: /Program |
固定リンク(花火のシミュレーション)
物体を選択してマウスで動かしたりするには、PickMouseBehavior のサブクラス
を使う。
- 回転させる PickRotateBehavior
- 動かす PickTranslateBehavior
- ズームする PickZoomBehavior
これらは Java3D 1.2 以前では com.sun.j3d.utils.behaviors.picking パッケー
ジに入っていたが、1.2 からは com.sun.j3d.utils.picking.behaviors パッ
ケージに入っている。ここでは新しい方
(com.sun.j3d.utils.picking.behaviors)を使おう。
以下では物体を選んで回転させる方法について解説する。
PickRotateBehavior の部分を他のクラスに変えれば、他も同様にできる。
やるべきことは簡単で、PickRotateBehavior のインスタンスを作成し、
BranchGroup に addChild すればよい。Picking を有効にしたい Node を
あらかじめ setCapability(TransformGroup.ENABLE_PICK_REPORTING) によって
属性を変えておくことを忘れずに。
// ..... 途中から
Canvas3D canvas = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
BranchGroup scene = new BranchGroup();
TransformGroup[] trBox = new TransformGroup[2];
for(int i=0;i<trBox.length;i++){
trBox[i] = new TransformGroup();
trBox[i].setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
trBox[i].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
trBox[i].setCapability(TransformGroup.ENABLE_PICK_REPORTING);
trBox[i].addChild(new ColorCube(0.1f));
}
BoundingSphere bounds = new BoundingSphere(new Point3d(), 100.0);
// 立方体を別々に動かすためのピッキング
pickRot = new PickRotateBehavior(scene,canvas,bounds);
scene.addChild(pickRot);
// ..... 以下略
上の例では、trBox[0]、trBox[1] が Picking 可能になっている。
そこに立方体が addChild されているので、最後の2行によって、
立方体を Picking によって個別に回転することができる。
posted at 16:19 |
category: /Java/Java3DTips |
固定リンク(Picking するには)
物体を選択したときの動作を自分で定義するには、
com.sun.j3d.utils.picking.behaviors.PickMouseBehavior を自分で拡張する。
PickMouseBehavior は抽象クラスで、updateScene(int xpos,int ypos) メソッ
ドが抽象メソッドであるから、これを拡張する。ここでは Picking した物体
の座標を表示するプログラムを取り上げてみる。
PickMouseBehavior には pickCanvas と言うフィールドがある。
このクラスの setShapeLocation(xpos,ypos) と
pickClosest() メソッドを使ってマウスをクリックした点に一番近い物は何かを
を調べることができる。pickClosest() は調査の結果を PickResult クラスで返
すので、実際に Node を取り出すには、PickResult クラスの getNode() メソッ
ドを用いる。雛型は次の通り。
public void updateScene(int xpos,int ypos){
TransformGroup tg = null;
// マウスの座標を与える
pickCanvas.setShapeLocation(xpos,ypos);
// マウスの位置に一番近いノード
PickResult res = pickCanvas.pickClosest();
if(res != null){
// 何かが Picking されているときには
// その TransformGroup を取り出す
if(((tg = (TransformGroup)res.getNode(PickResult.TRANSFORM_GROUP)) != null) &&
(tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
(tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
// ここで tg についての処理を行う
}
}
}
今の場合は、tg についての処理のところで、getTransform() で座標を取り出し、
それを TextField に書き込んでいる。
posted at 16:16 |
category: /Java/Java3DTips |
固定リンク(Picking をカスタマイズするには)
Java3D 付属の Picking ではマウスで物体を選択することはできるが、
それを動かすときに、マウスカーソルに追従させることはできない。
それを可能にするための Behavior を書き直してみた。
もちろんx座標とy座標方向にしか動かすことはできない。
z座標方向は画面と垂直なので、マウスカーソルの位置で奥行を
変化させることはできないため。
また、Picking した物体がぶら下がっている TransformGroup を
動かしたときに標準の Picking では違った方向に動く仕様になっているが、
それも大域座標で計算しなおすような仕様に変更してある。
以下にソースを挙げる。使いかたは、PickingTranslateBehavior とほぼ同じ。
ただ、コンストラクタの引数の順番が異なる。
/**
* @author TOKUNAGA Ken-ichi
* @version Time-stamp: <03/02/28 03:17:20 tkenichi>
*
* 物体をピッキングして、それをマウスカーソルに追従させる。
*/
import com.sun.j3d.utils.picking.*;
import com.sun.j3d.utils.picking.behaviors.*;
import com.sun.j3d.utils.behaviors.mouse.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;
public class MouseDragBehavior extends Behavior
implements MouseBehaviorCallback{
Vector3d currV3d = new Vector3d(),diffV3d = new Vector3d();
Point3d cursorP3d = new Point3d(),viewP3d = new Point3d();
Vector4d currV4d = new Vector4d();
private PickingCallback callback = null;
private PickCanvas pickCanvas;
private WakeupOr wakeupCondition;
private boolean picked = false;
// ピッキングした座標を格納する
private TransformGroup currGrp;
private Transform3D
currT3d = new Transform3D(), // ピッキングした座標
localT3d = new Transform3D(), // 局所座標
inverse = new Transform3D(), // 逆変換
plate2world = new Transform3D(); // imageplate から仮想空間への変換
public MouseDragBehavior(Canvas3D canvas,
BranchGroup root,
Bounds bounds){
currGrp = new TransformGroup();
currGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
currGrp.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
currGrp.setCapability(TransformGroup.ALLOW_LOCAL_TO_VWORLD_READ);
// Behavior は Leaf だからその上の BranchGroup につける
root.addChild(currGrp);
pickCanvas = new PickCanvas(canvas, root);
pickCanvas.setMode(PickCanvas.BOUNDS);
setSchedulingBounds(bounds);
}
public void setMode(int pickMode) {
pickCanvas.setMode(pickMode);
}
public int getMode() {
return pickCanvas.getMode();
}
public void setTolerance(float tolerance) {
pickCanvas.setTolerance(tolerance);
}
public float getTolerance() {
return pickCanvas.getTolerance();
}
public void initialize() {
// マウスを押したとき、離したとき、ドラッグしたときに
// 起動する
WakeupCriterion[] conditions = new WakeupCriterion[3];
conditions[0] = new WakeupOnAWTEvent(MouseEvent.MOUSE_DRAGGED);
conditions[1] = new WakeupOnAWTEvent(MouseEvent.MOUSE_PRESSED);
conditions[2] = new WakeupOnAWTEvent(MouseEvent.MOUSE_RELEASED);
wakeupCondition = new WakeupOr(conditions);
wakeupOn(wakeupCondition);
}
public void processStimulus (Enumeration criteria) {
WakeupCriterion wakeup;
AWTEvent[] evt = null;
int xpos = 0, ypos = 0;
MouseEvent mevent;
// AWTEvent を取り出す
while(criteria.hasMoreElements()) {
wakeup = (WakeupCriterion)criteria.nextElement();
if (wakeup instanceof WakeupOnAWTEvent)
evt = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
}
// MouseEvent の場合
if (evt[0] instanceof MouseEvent){
mevent = (MouseEvent) evt[0];
// マウスカーソルの2次元ピクセル座標
xpos = mevent.getPoint().x;
ypos = mevent.getPoint().y;
switch(mevent.getID()){
case MouseEvent.MOUSE_PRESSED:
// 押されたとき
System.out.println("mouse pressed");
// ピッキングする
if (!mevent.isAltDown() && mevent.isMetaDown()){
pickingTransformGroup(xpos,ypos);
}
break;
case MouseEvent.MOUSE_RELEASED:
// 離したとき
// ピッキングをやめる
picked = false;
break;
case MouseEvent.MOUSE_DRAGGED:
// ドラッグしたとき
// ピッキングされた TransformGroup を動かす
if (picked && !mevent.isAltDown() && mevent.isMetaDown()){
translate(xpos,ypos);
}
break;
default:
System.out.println("other event");
}
}
wakeupOn (wakeupCondition);
}
// ピッキングして TransformGroup を currGrp に格納する
private void pickingTransformGroup(int xpos,int ypos){
TransformGroup tg = null;
// PickCanvas をつかってピッキングしているノードを探す
pickCanvas.setShapeLocation(xpos, ypos);
// LineArray と Vertex の両方が重なっている場合も
// Vertex を取り出すために、pickAll() で全て取り出す
PickResult pr[] = pickCanvas.pickAll();
if(pr != null){
for(int i=0;i<pr.length;i++){
System.out.println(i + " = " + pr[i].getNode(PickResult.GROUP));
// ピッキングした結果が読み書き可能な TransformGroup を取り出す
if ((pr[i] != null) &&
((tg = (TransformGroup)pr[i].getNode(PickResult.TRANSFORM_GROUP))
!= null) &&
(tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
(tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
System.out.println("success to pick " + tg);
picked = true;
// ピッキングした結果の参照を currGrp にセットする
currGrp = tg;
// 物体が乗っている座標系とその逆変換を得る
currGrp.getLocalToVworld(localT3d);
System.out.println(localT3d);
inverse.invert(localT3d);
System.out.println(inverse);
// ImagePlate から仮想空間への変換行列を得る
pickCanvas.getCanvas().
getImagePlateToVworld(plate2world);
// 視点の位置を得る
pickCanvas.getCanvas().getCenterEyeInImagePlate(viewP3d);
plate2world.transform(viewP3d);
// マウスカーソルの位置に物体を合わせる
translate(xpos,ypos);
// freePickResult(pr);
}
}
}
}
private void translate(int xpos,int ypos){
// マウスカーソルのimageplate上の位置を得る
pickCanvas.getCanvas().
getPixelLocationInImagePlate(xpos,ypos,cursorP3d);
plate2world.transform(cursorP3d);
// ピッキングした物体の座標を通る
currGrp.getTransform(currT3d);
currT3d.get(currV3d);
currV4d.set(currV3d.x,
currV3d.y,
currV3d.z,
1);
localT3d.transform(currV4d);
currV3d.set(currV4d.x,
currV4d.y,
currV4d.z);
//System.out.println("cursor = " + cursorP3d);
//System.out.println("current = " + currV3d);
// 物体の座標をマウスカーソルの位置にあわせる
// view と垂直方向な平面上を移動する
currV3d.sub(viewP3d);
cursorP3d.sub(viewP3d);
double alpha =
(currV3d.x * viewP3d.x +
currV3d.y * viewP3d.y +
currV3d.z * viewP3d.z) /
(cursorP3d.x * viewP3d.x +
cursorP3d.y * viewP3d.y +
cursorP3d.z * viewP3d.z);
currV3d.scaleAdd(alpha,cursorP3d,viewP3d);
// 大域座標を局所座標に直す
currV4d.set(currV3d.x,
currV3d.y,
currV3d.z,
1);
inverse.transform(currV4d);
currV3d.set(currV4d.x,
currV4d.y,
currV4d.z);
currT3d.setTranslation(currV3d);
currGrp.setTransform(currT3d);
transformChanged(MouseBehaviorCallback.TRANSLATE,
currT3d);
}
public void setupCallback(PickingCallback callback){
this.callback = callback;
}
public void transformChanged(int type,Transform3D transform){
if(callback != null){
callback.transformChanged(type,currGrp);
}
}
}
posted at 16:14 |
category: /Java/Java3DTips |
固定リンク(Picking した物体を Drag するには)
絡み数の簡易計算 (Java Web Start)
絡み数を計算するプログラム。多角形を三角形に分割して
それぞれの三角形で絡み目を計算してそれらを足しています。
三角形同士が干渉しあうことの判定はもっと速いものもあるでしょうが、
ここでは正確さを重視しています。
履歴
- 2004/11/07
- とりあえずバージョン。四角形に対して三角形を動かした場合に
絡み数を随時計算するようにする。
使い方
マウスでグリグリしてください。
白い三角形が動きます。赤い四角形との絡み目を計算して表示します。
視点は変えられません。表示された辺で上下関係は見てください。
posted at 16:02 |
category: /Program/Knot |
固定リンク(絡み目の計算
)
輸送問題をステップ実行するプログラム(Java Web Start)
m個のの供給地からn個の需要地へ物資を輸送する場合、
各供給地から需要地への輸送費と各供給地の供給量、
各需要地の需要量が与えられているとき、
どの供給地から需要地にどれだけ物資を輸送するのがコストが最も少なくなるか。
この問題を考えるのが輸送問題である。
このプログラムではそれを飛び石法を用いて解くことにする。
まず供給地の個数と需要地の個数を入力する。
するとコスト表と輸送量の表が現れる。
その表に必要な係数を入力して、「次のステップ」ボタンを押すと、
標準的な手順にしたがって、飛び石法で解を求めていく。
飛び石法で基底変数を変換する場合、そのループの場所の色を変えています。
輸送量の表の右下のセルに全輸送コストを表示しています。
解が退化する場合はメッセージを出して終了します。
その場合は供給量、需要量を摂動させて
もう一度始めから解いて下さい。
posted at 15:31 |
category: /Program/OR |
固定リンク(輸送問題
)
PERT Simulator(Java Web Start)
いくつかの作業をまとまりとして見るときそれをプロジェクトと言い、
作業リストからプロジェクトの日程計画をたてることを考える。
作業リストにはその作業を始めるのに既に終了しておかなくてはならない
作業(先行作業)と、所要時間から構成される。このときそれぞれの作業が
いつから始めることが可能か、余裕があるかどうかを調べる。
ここでは作業リストを与えて、次のものを求める。
- 最早開始時刻(ES)
- 最早終了時刻(EF)
- 最遅開始時刻(LS)
- 最遅終了時刻(LF)
- 全余裕(TF)
- 自由余裕(FF)
まず最初の画面では作業の個数を選択する。次に作業リストを与える表が現れるので、
所要時間を記入し、先行作業のところにチェックをいれる。その後、『PERT実行』
と言うボタンを押せば上の値を求めて表として表示する。
まだ日程計画としてつじつまがあっていないとき
(先行作業をたどって行くとループになるときなど)
の例外処理はしていない。最悪無限ループに陥る可能性がある。
また、ダミー作業を挿入する方法が一意でないときの処理も
いい加減である。その辺は注意して利用してほしい。
ひょっとしたらバグが残っているかもしれない。
見つけた人は教えてほしい。
posted at 15:20 |
category: /Program/OR |
固定リンク(PERT
)
シンプレックス法をステップ実行するプログラム(Java Web Start)
初めの画面では変数の個数と条件式の個数を入力する。
変数はスラック変数も含める。条件式は目的関数は含めない。
[ENTER] ボタンを押すと、シンプレックス表の画面に切り替わる。
ここで、シンプレックス表を入力する。左端の行は目的関数 (z)
の係数、右端は定数を入力する。[STEP] を押すと1段階ごとに
シンプレックス法を実行する。[RESET] を押すと、はじめの画面に戻る。
実行するときに実行可能基底解を表す表からはじめなければ、正しい答えは保証
されません。2段階シンプレックス法や罰金法などを用いて調整して下さい。
一般的な流儀では定数項を一番左に書いたり、目的関数を一番上に書いたりする
かも知れませんが、その場合は適宜読みかえて下さい。
posted at 15:15 |
category: /Program/OR |
固定リンク(シンプレックス法
)
ベータ分布乱数生成プログラム(Java Web Start)
ベルヌイ分布に関するベイズ推測を行うと、
事後分布としてベータ分布が現れる。そこでベータ分布の
勉強をかねて、乱数生成プログラムを作成。
履歴
- 2003/11/03
- 乱数生成アルゴリズムおよび簡単なインタフェイス作成
実行形式
a,b の値を入力し、[SET PARAMETER] ボタンを押すと、
確率分布が更新される。START ボタンを押せば乱数が生成されます。結果はヒストグラム表示され
ます。試行回数によってヒストグラムの幅は自動的に調整されます。
これだけで終わっては仕方ないので、KL距離を計算したり、AIC を計算したりする
プログラムに発展させていきたいな。
posted at 15:04 |
category: /Program/Math |
固定リンク(ベータ分布
)
正規分布の数値計算(Java Web Start)
正規分布表が手元にないときに代わりに数値計算するプログラムです。
posted at 14:53 |
category: /Program/Math |
固定リンク(正規分布
)
平方剰余を計算するプログラム(Java Web Start)
いわゆる Legendre 記号を計算する。
posted at 14:42 |
category: /Program/Math |
固定リンク(平方剰余を求める
)