Web 上で操作可能な仮想柔物体の変形操作システムの - Consorts.org

Web 上で操作可能な仮想柔物体の変形操作システムの試作
2004 年 7 月 31 日
幸島 明男
1.はじめに
バーチャルリアリティの有望なアプリケーションの一つとして,家具や不動産,自動車な
どの商品紹介のインターネット上の Web ページが挙げられる.現在,多くの自動車メーカ
が,車の 3 次元 CG モデルを,さまざまな角度から眺められるインタラクティブな Web ペ
ージを提供している.しかしながら,このようなインタラクティブな商品提示は雰囲気を
楽しむには優れているが,実際の商品に“触れて”いるというような強い印象は残らない
ものである.このような Web ページを,バーチャルリアリティの技術を用いて高度化する
ことで,より訴求力のある商品紹介が可能にはならないだろうか.視覚情報だけではなく,
触覚情報などの感覚情報を補うことで,ユーザにより強い印象を残せることが期待される.
そこで,本リポートでは,このような仮想現実感の技術を用いた商品紹介の Web ページ
の実現に向けた最初の一歩として,Web 上で操作可能な柔物体の変形操作システムを提案
する.従来の Web 上の商品紹介ページの 3 次元 CG モデルの多くが剛体であり,柔物体を
操作するようなものは見当たらない.加えられる力に応じて,その形状をさまざまに変化
させる柔物体を提示する技術を用いることで,従来の剛体モデルでは困難であったやわら
かい商品の紹介や,触覚情報を伴う商品紹介が実現できる.
以下では,作成した仮想柔物体の変形操作システムの内容について述べる.まず,作成
したシステムにおける柔物体のモデルについて述べる.本研究では,柔物体のモデルとし
ては,もっとも良く知られているバネモデル(Mass-Spring-Damper Model) を用いてモデ
ル化を行っている.次に,システムの実装について述べる.本システムでは,Web 上で仮
想物体を操作する機能を実現するために,Java3D を用いて実装を行った.最後に,システ
ムの実際の動作例と操作方法について述べる.本システムは,
http://www.carc.aist.go.jp/~sashima/vr/
にアクセスすることで,実際に動作させてみることが可能である1.作成したシステムの
ソースリストは末尾に添付した.
1
Web ブラウザに加えて Java と Java3D のインストールが必要です(3 章参照).
2.
柔物体と操作のモデル化
柔物体のモデル化の手法としては,有限要素法とバネモデル(Mass-Spring-Damper Model)
の 2 つが知られている.バネモデルは,有限要素法に比較して少ない計算量で変形の計算
が可能なため,実時間性の要求されるアプリケーションで,頻繁に用いられる手法である.
そこで,本研究においてもバネモデルを用いてモデル化を行う.
バネモデルでは,複数の質点がバネとダンパーによって相互に接続されたものとして,
柔物体をモデル化する.バネとダンパーは並列に接続されており,各質点 i にかかる力 Fi
は,以下の運動方程式により表現できる.
⎧ ⎛ L ⎞
⎫⎪
⎪
ij ⎟
Fi = −∑ ⎨k ⎜1 −
rij + Dvij ⎬ + mg
⎜
rij ⎟⎠
j ⎪
⎪⎭
⎩ ⎝
ここで k, Lij, rij, D, vij, m, g は,それぞれバネ定数,バネの自然長,質点 j に対する質
点 i の相対位置,ダンパー定数,質点 j に対する質点 i の相対速度,質点の質量,重力加速
度である.
本研究では,ユーザの柔物体の操作は,物体を押す行動に限定した.物体を押す行動は,
接触面に存在する複数の質点に対して外力 Fexternal を加える過程としてモデル化することが
できる2.具体的には,以下のような運動方程式で表現できる.
⎧ ⎛ L ⎞
⎫⎪
⎪ ⎜
ij ⎟
Fi = −∑ ⎨k 1 −
r + Dvij ⎬ + mg + Fexternal
⎜
⎟ ij
r
j ⎪
ij
⎪⎭
⎠
⎩ ⎝
なお,外力 Fexternal はユーザが,徐々に力を加えていくことを想定して,⊿t 秒ごとに⊿F
ずつ線形に増加するものとした.
上記の運動方程式を数値的に解くことで,質点の位置の時間変化が計算でき,物体の変
形が計算できる.運動方程式の数値計算はオイラー法により行う.具体的には,以下の式
により⊿t 秒後の質点 i の位置 ri と速度 vi を計算できる.
Fi (t )
∆t
m
ri (t + ∆t ) = ri (t ) + vi (t )∆t
vi (t + ∆t ) = vi (t ) +
このような運動方程式に基づいて,立方体を二つ重ねた形状の柔物体のモデルを構築し
た(図 1 参照).
2実装上は,一度に力を加えられるのは,
一つの質点のみに限定した.
図 1 システムの動作画面(柔物体のバネモデル)
図 1 の青い箱(12 個)が質点の位置を表し,赤い円柱(50 本)が質点間を結ぶバネを表してい
る. 質点は立方体の各頂点に存在するものとした.リンクは各質点間の全結合ではなく,
全結合された立方体2つを接合し,その接合面で2つのリンクと4つの質点を共有すると
いう形にした.物理パラメータは,ばね定数:4.0 (N/m),ダンパー定数:0.15 (N/(m/s)),質
点の質量:0.05(Kg),重力加速度 9.80665(m/s2))とした.バネの自然長は質点間の初期位置
間の距離を自然長として与えた.⊿t は 25(ms)である.ユーザの加える外力は初期値を 0
(N)として,⊿t ごとに 0.01(N)ずつ増加していくものとした.
3.
実装
Web 上で操作可能な 3 次元 CG モデルを実現するには,Internet Explorer などの Web ブ
ラウザ内に,3 次元グラフィックを描画することが必要である.現在,Web ブラウザを用
いた 3 次元グラフィックの描画システムとしては,VRML のプラグインや Java (+Java3D)
のアプレットの利用が考えられる.ここでは,変形の計算プログラミングとの融合の容易
性から,Java と Java3D を用いて実装を行った.Java3D は,オブジェクト指向の 3 次元
グラフィック API を提供する Java のグラフィックライブラリであり,シーングラフと呼
ばれる木構造を用いて仮想環境内の物体を記述することができる.物体の挙動はイベント
ハンドラのクラス Behavior のサブクラスを定義することで実現される.作成したプログラ
ムのソースリストは末尾に添付した. オブジェクト指向により,質点,リンクなどがクラ
スとして自然に記述できるため,拡張性の高いプログラムが作成可能である3. 具体的には
SpringObject クラスにおいて,質点,リンクを定義することで,異なる構造の柔物体の変
形計算を行うことができる.
開発環境:
・ JDK1.4.2 SE
・ Java3D API 1.3.1(DirectX Version)
・ Browser: Internet Explorer 6.0
・ OS: Windows XP
・ CPU: Pentium4 1GHz
・ Memory: 760 M Byte,
・ Graphics: Intel 855GM
・
4.インストールと実行
本プログラムの実行には Java(JDK1.4.2 SE)および Java3D(Java3D API 1.3.1)のイ
ンストールが必要である.Java との Runtime および Java と Java3D は以下の URL から
入手できる.(2004 年 7 月 31 日現在)
・ Java:
http://java.sun.com/j2se/1.4.2/download.html
・ Java3D:
http://java.sun.com/products/java-media/3D/download.html
インストール後は下記の URL にアクセスすると図 1 に示したような Java のアプレットが
実行される4.実行されると,仮想柔物体の形状が質点の自重で変形するの様子が描画され
るはずである.
http://www.carc.aist.go.jp/~sashima/vr/
3
しかし,行列演算は,オブジェクト指向になじまないのか,あまりきれいに書けないため,
若干中途半端になるようだ.
4 本リポート提出時の添付ファイル(zip)を解凍し,フォルダ中の index.html を開いても実
行できます.
操作
操作はマウスの左ボタンのみで行う.画面中の青い箱(質点)の上にマウスのポインタを移動
し,そこで左ボタンを押すと,その質点に対して鉛直下向きの力が働きつづける.ボタン
を押している間は下向きの力が働きつづけ,ボタンを離すと力は働かなくなる.そのため,
ボタンを押している間は変形をつづけ,離すと元の状態に戻ろうとする挙動がみられる.
さらに力を加え続けると(地面との摩擦がないため)柔物体は横倒しになる(図2参照).
図2
マウス操作による質点への外力の付加
マウスで選択することで,任意の質点にいつでも力を加えることができる5.図3は,図 2
に示した操作で,横倒しになった柔物体の右端に力を加えている様子を示している.
図3
横倒しの物体へ外力を加えた様子
5.今後の課題
ここで提案したモデルでは,ヤング率など実際の物体との対応関係については検討してい
ない.また,物体の表面やテクスチャの表現に関しても考慮しなかった.研究の目的から
すると,こういった側面の検討も不可欠である.現実の物体との対応付けは今後の課題と
したい.
パラメータの設定によって形状が不安定になる場合があった.今回は,数値計算をオイ
ラー法で行ったが,ルンゲクッタ法で行うことで改善が見られるかもしれない.体積や表
面積などの制約を,ヒューリスティックな制約として用いた計算アルゴリズムも検討する
余地がある.データファイルの読み込みやパラメータの設定パネルなどを追加することで,
より一般性を持ったシステムが実現できる.
6.おわりに
Java3D を用いて柔物体の変形操作を行うシステムを作成した.バネモデルによるモデル化
を行ったため,力覚フィードバックデバイスとの接続は容易であると予想される.機会が
あれば接続を試してみたい.
7.参考文献
[1] 広内哲夫, Java3D グラフィックス, セレンディップ, 2004
[2] 河合裕文, 松宮雅俊, 竹村治雄, 横矢直和, 疎密バネモデルを用いた柔物体の仮想環境
下での視覚および力覚提示手法の提案, 信学技報, IE2000-167, Vol.100, No.607, pp.71-76,
2001
3 次元物体を射影された 2 次元画像中の点から選択するため, 質点を選択しにくい/選
択できない場合があります.少しマウスを移動したり,選択する質点を変えたりしてくだ
さい.
5
付録:プログラムリスト
package vr;
import
import
import
import
import
import
import
import
import
import
java.applet.*;
java.util.*;
javax.media.j3d.*;
javax.vecmath.*;
java.awt.*;
java.awt.event.*;
com.sun.j3d.utils.applet.*;
com.sun.j3d.utils.geometry.*;
com.sun.j3d.utils.picking.*;
com.sun.j3d.utils.universe.*;
// 質点のクラス
class Particle {
boolean selected = false;
Hashtable linkLength = new Hashtable();
Vector3f velocity = new Vector3f(0.0f, 0.0f, 0.0f);
Vector3f force = null;
double m = 0.05f;
Vector3f position = null;
boolean movable = true;
TransformGroup view = new TransformGroup();
Vector linkedParticles = new Vector();
Box box = null;
public Particle(Vector3f p, boolean movable) {
this.movable = movable;
this.view = createBoxView();
this.setLocation(p);
}
// 箱(質点)の描画
private TransformGroup createBoxView() {
TransformGroup tg = new TransformGroup();
tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
Material matY = new Material();
matY.setDiffuseColor(new Color3f(0.0f, 0.0f, 1.0f));
//
matY.setCapability(Material.ALLOW_COMPONENT_READ|Material.ALLOW_COMPON
ENT_WRITE);
Appearance ap = new Appearance();
ap.setMaterial(matY);
ap.setCapability(Appearance.ALLOW_MATERIAL_READ |
Appearance.ALLOW_MATERIAL_WRITE);
int flag = Box.ENABLE_GEOMETRY_PICKING | Box.GENERATE_NORMALS;
box = new Box(0.1f, 0.1f, 0.1f, flag, ap);
//
box.setCapability(Shape3D.ALLOW_APPEARANCE_READ|Shape3D.ALLOW_APPEARAN
CE_WRITE);
box.setUserData(this);
tg.addChild(box);
return tg;
}
public void addlinkedParticle(Particle p) {
Vector3f tmp = new Vector3f();
tmp.sub(this.position, p.position);
Float len = new Float(tmp.length());
linkLength.put(p, len);
linkedParticles.add(p);
}
public TransformGroup getView() {
return view;
}
public void setLocation(Vector3f translation) {
// Location
if (translation.y <= 0.0) {
translation.y = 0.0f;
velocity.y = 0.0f;
}
this.position = translation;
// View
Transform3D transform2 = new Transform3D();
transform2.setTranslation(translation);
view.setTransform(transform2);
}
}
// 質点間のリンクのクラス
class Link {
Particle p0, p1 = null;
double l;
TransformGroup view = null;
Vector3f yOrient = new Vector3f(0.0f, 1.0f, 0.0f);
Transform3D origin = null;
public Link(Particle p0, Particle p1) {
this.p0 = p0;
this.p1 = p1;
view = createCylinderView();
updateView();
}
// 円柱の描画
private TransformGroup createCylinderView() {
TransformGroup tg = new TransformGroup();
tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
Material matY = new Material();
matY.setDiffuseColor(new Color3f(1.0f, 0.0f, 0.0f));
Appearance ap = new Appearance();
ap.setMaterial(matY);
Cylinder cyl = new Cylinder(0.05f, 1.0f,
Cylinder.GENERATE_NORMALS,
10, 10, ap);
tg.addChild(cyl);
Transform3D transform = new Transform3D();
tg.getTransform(transform);
origin = transform;
return tg;
}
public void updateView() {
Vector3f tmp = new Vector3f();
Vector3f housen = new Vector3f();
tmp.sub(p0.position, p1.position);
float len = tmp.length();
housen.cross(yOrient, tmp);
Transform3D transform0 = new Transform3D(origin);
//view.getTransform(transform0);
Transform3D transform1 = new Transform3D();
transform1.setScale(new Vector3d(1.0d, (double) len, 1.0d));
transform1.mul(transform0);
AxisAngle4f angle = new AxisAngle4f(housen, yOrient.angle(tmp));
Transform3D transform2 = new Transform3D();
transform2.setRotation(angle);
transform2.mul(transform1);
Transform3D transform3 = new Transform3D();
transform3.setTranslation(new
Vector3f(
(p0.position.x
+
p1.position.x) /
2.0f,
(p0.position.y + p1.position.y) /
2.0f,
(p0.position.z + p1.position.z) /
2.0f));
transform3.mul(transform2);
view.setTransform(transform3);
}
public TransformGroup getView() {
return view;
}
}
// 質点とリンク,およびその構造を定義するクラス
class SpringBox {
Vector links = null;
Vector particles = null;
TransformGroup view = null;
public static Vector3f externalForce = null;
Particle selectedParticle = null;
// ばね定数とダンパー定数
double k = 4.0f;
float d = 0.15f;
// ⊿T
float deltaX = 0.025f;
// 重力
static Vector3f g = new Vector3f(0.0f, 9.80665f, 0.0f);
public SpringBox() {
view = new TransformGroup();
externalForce = new Vector3f(0.0f, 0.0f, 0.0f);
links = new Vector();
particles = new Vector();
Particle
Particle
Particle
Particle
Particle
Particle
Particle
Particle
Particle
Particle
Particle
Particle
p0 = new Particle(new Vector3f(0.0f, 0.0f, 0.0f), true);
p1 = new Particle(new Vector3f(0.0f, 0.0f, 1.0f), true);
p2 = new Particle(new Vector3f(1.0f, 0.0f, 1.0f), true);
p3 = new Particle(new Vector3f(1.0f, 0.0f, 0.0f), true);
p4 = new Particle(new Vector3f(0.0f, 1.0f, 0.0f), true);
p5 = new Particle(new Vector3f(0.0f, 1.0f, 1.0f), true);
p6 = new Particle(new Vector3f(1.0f, 1.0f, 1.0f), true);
p7 = new Particle(new Vector3f(1.0f, 1.0f, 0.0f), true);
p8 = new Particle(new Vector3f(0.0f, 2.0f, 0.0f), true);
p9 = new Particle(new Vector3f(0.0f, 2.0f, 1.0f), true);
p10 = new Particle(new Vector3f(1.0f, 2.0f, 1.0f), true);
p11 = new Particle(new Vector3f(1.0f, 2.0f, 0.0f), true);
addParticle(p0);
addParticle(p1);
addParticle(p2);
addParticle(p3);
addParticle(p4);
addParticle(p5);
addParticle(p6);
addParticle(p7);
addParticle(p8);
addParticle(p9);
addParticle(p10);
addParticle(p11);
addLink(p0,
addLink(p0,
addLink(p0,
addLink(p1,
addLink(p1,
addLink(p2,
addLink(p4,
addLink(p4,
addLink(p5,
addLink(p5,
addLink(p6,
addLink(p7,
p1);
p2);
p3);
p2);
p3);
p3);
p5);
p6);
p6);
p7);
p7);
p4);
addLink(p4,
addLink(p4,
addLink(p4,
addLink(p4,
addLink(p5,
p0);
p1);
p2);
p3);
p0);
addLink(p5,
addLink(p5,
addLink(p5,
addLink(p6,
addLink(p6,
addLink(p6,
addLink(p6,
addLink(p7,
addLink(p7,
addLink(p7,
addLink(p7,
p1);
p2);
p3);
p0);
p1);
p2);
p3);
p0);
p1);
p2);
p3);
addLink(p4,
addLink(p4,
addLink(p4,
addLink(p4,
addLink(p5,
addLink(p5,
addLink(p5,
addLink(p5,
addLink(p6,
addLink(p6,
addLink(p6,
addLink(p6,
addLink(p7,
addLink(p7,
addLink(p7,
addLink(p7,
p11);
p8);
p9);
p10);
p8);
p9);
p10);
p11);
p9);
p10);
p11);
p8);
p10);
p11);
p9);
p8);
addLink(p8, p9);
addLink(p8, p10);
addLink(p8, p11);
addLink(p9, p10);
addLink(p9, p11);
addLink(p10, p11);
}
// オイラー法
void calc() {
for (int i = 0; i < particles.size(); i++) {
Particle p = (Particle) particles.get(i);
if (p.movable) {
Vector3f f = new Vector3f(0.0f, 0.0f, 0.0f);
for (int j = 0; j < p.linkedParticles.size(); j++) {
Particle pj = (Particle) p.linkedParticles.get(j);
Vector3f vij = new Vector3f();
vij.sub(p.velocity, pj.velocity);
vij.scale(d);
f.sub(vij);
Vector3f rij = new Vector3f();
rij.sub(p.position, pj.position);
// System.out.println("rij: " + rij);
float len = rij.length();
// System.out.println(i + "rij: " + rij + " " + len);
float origLength = ( (Float) p.linkLength.get(pj)).floatValue();
rij.scale( (float) (k * (origLength / len - 1.0f)));
f.add(rij);
//
System.out.println(i + " f: " + f);
}
Vector3f mg = new Vector3f(g);
mg.scale( (float) p.m);
f.sub(mg);
if (this.selectedParticle == p) {
System.out.println(i + "," + externalForce);
f.add(externalForce);
}
p.force = f;
}
// System.out.println("pos: " + p.position);
}
for (int i = 0; i < particles.size(); i++) {
Particle p = (Particle) particles.get(i);
if (p.movable) {
Vector3f f = new Vector3f(p.force);
f.scale( (float) (deltaX / p.m));
Vector3f v = new Vector3f(p.velocity);
v.add(f);
p.velocity = new Vector3f(v);
Vector3f p1 = new Vector3f();
v.scale(deltaX);
p1.add(p.position, v);
p.setLocation(new Vector3f(p1));
}
}
for (int i = 0; i < links.size(); i++) {
Link l = (Link) links.get(i);
l.updateView();
}
}
void addParticle(Particle p0) {
particles.add(p0);
view.addChild(p0.getView());
}
void addLink(Particle p0, Particle p1) {
Link l = new Link(p0, p1);
p0.addlinkedParticle(p1);
p1.addlinkedParticle(p0);
links.add(l);
view.addChild(l.view);
}
public TransformGroup getView() {
return view;
}
// 外力の負荷とリセット
public synchronized void addForce(Vector3f v) {
externalForce.x += v.x;
externalForce.y += v.y;
externalForce.z += v.z;
}
public void resetForce() {
externalForce = new Vector3f(0.0f, 0.0f, 0.0f);
}
}
// Graphics とユーザインターフェイス
public class World
extends Applet {
static private boolean pushFlag = false;
static private double radius = 300.0d;
Canvas3D
canvas
=
Canvas3D(SimpleUniverse.getPreferredConfiguration());
private PickCanvas pickCanvas;
new
public void init() {
SimpleUniverse universe = createUniverse(canvas);
BranchGroup bg = new BranchGroup();
DirectionalLight light = new DirectionalLight(new Color3f(1.0f, 1.0f,
1.0f),
new
Vector3f(0.0f, -0.5f, -1.0f));
BoundingSphere bounds = new BoundingSphere(
new Point3d(0.0, 0.0, 0.0), radius);
light.setInfluencingBounds(bounds);
bg.addChild(light);
//座標系の設定
TransformGroup tg = new TransformGroup();
tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
SpringBox spObj = new SpringBox();
SpringBehavior spring = new SpringBehavior(this, spObj);
tg.addChild(spring.tg);
KeyCheck key = new KeyCheck(this, spObj);
tg.addChild(key.tg);
tg = setviewpoint(tg);
bg.addChild(tg);
bg.addChild(spring);
bg.addChild(key);
this.add(canvas);
pickCanvas = new PickCanvas(canvas, bg);
pickCanvas.setMode(PickCanvas.BOUNDS);
canvas.addMouseListener(new MyMouseAdapter(spObj));
universe.addBranchGraph(bg);
}
// ビューポイント
private TransformGroup setviewpoint(TransformGroup tg) {
Transform3D transform1 = new Transform3D();
tg.getTransform(transform1);
Transform3D transform2 = new Transform3D();
transform2.setTranslation(new Vector3f(0.0f, -1.5f, -3.5f));
transform2.mul(transform1);
AxisAngle4f angle = new AxisAngle4f(new Vector3f(0.0f, 1.0f, 0.0f),
0.6f);
Transform3D transform3 = new Transform3D();
transform2.setRotation(angle);
transform3.mul(transform2);
tg.setTransform(transform3);
return tg;
}
// 仮想世界の作成
private SimpleUniverse createUniverse(Canvas3D canvas) {
this.setLayout(new BorderLayout());
this.add(canvas, BorderLayout.CENTER);
SimpleUniverse universe = new SimpleUniverse(canvas);
ViewingPlatform vp = universe.getViewingPlatform();
vp.setNominalViewingTransform();
return universe;
}
// 地面の描画
private TransformGroup createGround() {
TransformGroup tg = new TransformGroup();
Material matY = new Material();
matY.setDiffuseColor(new Color3f(1.0f, 1.0f, 1.0f));
Appearance ap = new Appearance();
ap.setMaterial(matY);
Box ground = new Box(100.f, 0.02f, 100.0f, Box.GENERATE_NORMALS, ap);
tg.addChild(ground);
Transform3D transform1 = new Transform3D();
tg.getTransform(transform1);
Transform3D transform2 = new Transform3D();
transform2.setTranslation(new Vector3f(0.0f, -0.14f, 0.0f));
transform2.mul(transform1);
tg.setTransform(transform2);
return tg;
}
// 移動
public
TransformGroup
setLocation(TransformGroup
translation) {
Transform3D transform2 = new Transform3D();
transform2.setTranslation(translation);
tg.setTransform(transform2);
return tg;
}
tg,
Vector3f
// 構造の時間変化の制御(タイマー割り込み)
class SpringBehavior
extends Behavior {
//変数の宣言
public TransformGroup tg = null;
private WakeupCondition keyin = null;
WakeupOnElapsedTime wakeTimes = null;
private float angle = 0.5f;
private World world = null;
private SpringBox springObject = null;
double deltaX = 0.01;
double xStart = 0.00;
double yStart = 1.0;
double zStart = 0.0;
double yLimit = 0.25;
double x = xStart;
double y = yStart;
double z = zStart;
double[] y_z = new double[2];
public SpringBehavior(World w, SpringBox sp) {
this.world = w;
springObject = sp;
tg = new TransformGroup();
TransformGroup ground = createGround();
tg.addChild(springObject.getView());
tg.addChild(ground);
BoundingSphere bounds = new BoundingSphere(
new Point3d(0.0, 0.0, 0.0), 100.);
this.setSchedulingBounds(bounds);
}
public void initialize() {
wakeTimes = new WakeupOnElapsedTime(10);
wakeupOn(wakeTimes);
}
public void processStimulus(Enumeration enum) {
if (world.pushFlag) {
springObject.addForce(new Vector3f(0.0f, -0.01f, 0.0f));
}
springObject.calc();
wakeupOn(wakeTimes);
}
}
// Mouse の割り込み処理
class KeyCheck
extends Behavior {
//変数の宣言
public TransformGroup tg = null;
private WakeupCondition keyin = null;
WakeupOnElapsedFrames wakeTimes = null;
SpringBox spobj = null;
private World w = null;
public KeyCheck(World w, SpringBox spobj) {
this.w = w;
this.spobj = spobj;
tg = new TransformGroup();
//影響範囲の設定
BoundingSphere bounds = new BoundingSphere(
new Point3d(0.0, 0.0, 0.0), 100.);
this.setSchedulingBounds(bounds);
}
public void initialize() {
//起動条件の設定
WakeupCriterion[] events = new WakeupCriterion[2];
events[0] = new WakeupOnAWTEvent(MouseEvent.MOUSE_PRESSED);
events[1] = new WakeupOnAWTEvent(MouseEvent.MOUSE_RELEASED);
keyin = new WakeupOr(events);
wakeupOn(keyin);
}
public void processStimulus(Enumeration enum) {
if (w.pushFlag) {
// System.out.println("Key Released");
spobj.resetForce();
spobj.selectedParticle = null;
w.pushFlag = false;
}
else {
w.pushFlag = true;
}
wakeupOn(keyin);
}
}
// Mouse クリックの制御クラス(オブジェクトのピック)
class MyMouseAdapter
extends MouseAdapter {
SpringBox spObj = null;
public MyMouseAdapter(SpringBox spObj) {
super();
this.spObj = spObj;
}
public void mouseReleased(MouseEvent evnt) {
Object obj = getObject(evnt.getX(), evnt.getY());
if (obj == null) {
return;
}
delete(obj);
}
public void mousePressed(MouseEvent evnt) {
Object obj = getObject(evnt.getX(), evnt.getY());
if (obj == null) {
return;
}
add(obj);
}
// ピックされたオブジェクトの登録と削除
public void add(Object obj) {
if (obj instanceof Particle) {
Particle p = (Particle) obj;
spObj.selectedParticle = p;
System.out.println("Selected: " + p);
}
else {
}
}
public void delete(Object obj) {
System.out.println("UnSelected...");
spObj.selectedParticle = null;
}
// Pick されたオブジェクトの取り出し
private Object getObject(int x, int y) {
pickCanvas.setShapeLocation(x, y);
PickResult result = pickCanvas.pickClosest();
if (result != null) {
Node node = result.getNode(PickResult.PRIMITIVE);
Object obj = node.getUserData();
return obj;
}
return null;
}
}
// メイン
public static void main(String[] args) {
World example = new World();
MainFrame frame = new MainFrame(example, 600, 480);
}
}