// Java 3Dテストプログラム // WallCollisionBehavior.java // Copyright (c) 1999 ENDO Yasuyuki // mailto:yasuyuki@javaopen.org // http://www.javaopen.org/j3dbook/index.html import java.util.*; import javax.media.j3d.*; import javax.vecmath.*; public class WallCollisionBehavior extends Behavior { public static final int USE_BOUNDS = WakeupOnCollisionMovement.USE_BOUNDS; public static final int USE_GEOMETRY = WakeupOnCollisionMovement.USE_GEOMETRY; private static final Vector3d ORIGIN = new Vector3d(0.0, 0.0, 0.0); // 原点 private static final double VSCALE = 0.1; // 衝突時の移動量 private Transform3D ot3d = new Transform3D(); // 衝突を検知したい物体のT3D private TransformGroup otrans = null; // 衝突を検知したい物体のTG private Node onode = null; // 衝突を検知したい物体 private Vector3d ovector = null; // 衝突を検知したい物体の進行方向 private Transform3D nt3d = new Transform3D(); // 壁のT3D private Transform3D rt3d = new Transform3D(); // 衝突による移動 private int hint = USE_BOUNDS; // 領域検査か幾何学的検査か private WakeupOnCollisionMovement move = null; // Behavior起動条件 public WallCollisionBehavior(TransformGroup trans, Node node, Vector3d vector) { this(trans, node, vector, USE_BOUNDS); } public WallCollisionBehavior(TransformGroup trans, Node node, Vector3d vector, int hint) { onode = node; otrans = trans; ovector = vector; hint = hint; } public void initialize() { move = new WakeupOnCollisionMovement(onode, hint); wakeupOn(move); } public void processStimulus(Enumeration criteria) { while (criteria.hasMoreElements()) { WakeupOnCollisionMovement wakeup = (WakeupOnCollisionMovement)criteria.nextElement(); SceneGraphPath npath = wakeup.getTriggeringPath(); // 衝突した壁を含むPath Node node = npath.getObject(); System.out.println("\nnode.getBounds()=" + node.getBounds());//DEBUG System.out.println("onode.getBounds()=" + onode.getBounds());//DEBUG TransformGroup ntrans = (TransformGroup)node.getUserData();//壁にセットしてあったTG if (ntrans != null) { ntrans.getTransform(nt3d); // 壁のT3D System.out.println("nt3d=\n" + nt3d);//DEBUG nt3d.setTranslation(ORIGIN); // 原点に戻しておく Vector3d nvec = new Vector3d(0.0, 0.0, 1.0); // 壁の法線ベクトル初期値 nt3d.transform(nvec); // 壁の法線ベクトルを計算 otrans.getTransform(ot3d); // 視点のT3D System.out.println("o.x=" + ovector.x + ", o.y=" + ovector.y + ", o.z=" + ovector.z);//DEBUG System.out.println("ot3d=\n" + ot3d);//DEBUG ot3d.setTranslation(ORIGIN); // 原点に戻しておく ot3d.transpose(); // 視点マトリックスの転置 ot3d.transform(nvec); // 壁の法線を視点座標に変換 System.out.println("n.x=" + nvec.x + ", n.y=" + nvec.y + ", n.z=" + nvec.z);//DEBUG Vector3d onegate = new Vector3d(); // 物体の逆ベクトル onegate.negate(ovector); // 逆ベクトルを計算 double odotn = onegate.dot(nvec); // 内積 O・N System.out.println("odotn=" + odotn);//DEBUG nvec.scale(2.0 * odotn); // 2(O・N)N System.out.println("n.x=" + nvec.x + ", n.y=" + nvec.y + ", n.z=" + nvec.z);//DEBUG Vector3d rvec = new Vector3d(nvec); // 反射ベクトル rvec.sub(nvec, onegate); // 2(O・N)N - O // Phong の式 rvec.normalize(); // 正規化 rvec.scale(VSCALE); // 移動量でスカラー倍 System.out.println("r.x=" + rvec.x + ", r.y=" + rvec.y + ", r.z=" + rvec.z);//DEBUG rt3d.set(rvec); // 移動ベクトルをセットする otrans.getTransform(ot3d); // もう一度現在のTransform取得 ot3d.mul(rt3d); // 移動を乗算 otrans.setTransform(ot3d); // 移動させる } } wakeupOn(move); } public Node cloneNodeComponent(boolean forceDuplication) { WallCollisionBehavior wallCollisionBehavior = new WallCollisionBehavior(otrans, onode, ovector, hint); wallCollisionBehavior.duplicateNode(this, forceDuplication); return wallCollisionBehavior; } public void duplicateNode(Node node, boolean forceDuplication) { super.duplicateNode(node, forceDuplication); } public void updateNodeReference(NodeReferenceTable table) { super.updateNodeReferences(table); Node newNode = (Node)table.getNewObjectReference(onode); onode = newNode; TransformGroup newTransformGroup = (TransformGroup)table.getNewObjectReference(otrans); otrans = newTransformGroup; } }