Hi Josh,
I have code which does about what you are looking for. However, I did not
yet test
the part which translates the center of rotation away from the origin (it is
from an old
test project that got abandoned). The code is based somewhat on sourcecode
from
the sun utilities. You can find the sun code in the directory where you
installed J3D,
and it's name is java3d-utils-src.jar. You can open it with WinZip.
Here is a brief description of how to solve the problem before you look at
the (somewhat
incomplete, the picking part does not work) code.
1) Create a behavior which subclasses Behavior and wakes up on AWT events
for
mouse press, mouse release and mouse dragged.
2) Make your central point the center of the universe. You can do this by
having a "topmost"
transform group in your scene graph, call it maybe tgOrigin, and assign it
the coordinates
(0.0, 0.0, 0.0).
If you need to change the center of rotation from time to time and only
apply it to some objects
in the scene graph, you need to do the following:
Identify the TransformGroup which needs to be "orbited". Call it tgOrbit.
Get it's Transform3D, and call that Torbit.
Get the translation from that. Say the components are Tx, Ty, Tz. Create a
new Transform3D called Tinv which
is an identity matrix except that the translational components
are -Tx, -Ty, -Tz.
Now you are going to move tgOrbit to the origin, apply the necessary
rotation, and move it back to where it used to be.
To do that, create a new Transform3D which is given by the product Tinv *
Trot * Torbit
Trot is a Transform3D specifying the desired rotation you need based on the
mouse events.
My code is below. Feel free to use it any way you need, modify it or
whatever.
=== BEGIN OF CODE BLOCK
=======================================================
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.mouse.*;
/**
* MouseRotateXY is a Java3D behavior object that lets users control the
* rotation of an object on two axis via a mouse.
* <p>
* To use this utility, first create a transform group that this
* rotate behavior will operate on. Then,
*<blockquote><pre>
*
* MouseRotateXY behavior = new MouseRotateXY();
* behavior.setTransformGroup(tg);
* tg.addChild(behavior);
* behavior.setSchedulingBounds(bounds);
*
*</pre></blockquote>
* The above code will add the rotate behavior to the transform
* group. The user can rotate any object attached to the tg.
*/
public class MouseRotateXY extends MouseBehavior
{
protected double x_angle;
protected double x_factor;
protected double y_angle;
protected double y_factor;
protected BranchGroup bgApplyTo;
protected TransformGroup tgAnchor;
protected Canvas3D canvas3D;
protected Vector3d v3dRotationCenter = new Vector3d(0.0, 0.0, 0.0);
protected Vector3d v3dOrigin = new Vector3d(0.0, 0.0, 0.0);
protected boolean allowXrot = false;
/**
* Creates a rotate behavior given the transform group.
* @param transformGroup The transformGroup to operate on.
*/
public MouseRotateXY(Canvas3D canvas3D, BranchGroup branchGroup,
TransformGroup transformGroup, TransformGroup tgAnchor)
{
super(transformGroup);
bgApplyTo = branchGroup;
this.tgAnchor = tgAnchor;
this.canvas3D = canvas3D;
}
/**
* Creates a default mouse rotate behavior.
**/
public MouseRotateXY()
{
super(0);
}
/**
* Creates a rotate behavior.
* Note that this behavior still needs a transform
* group to work on (use setTransformGroup(tg)) and
* the transform group must add this behavior.
* @param flags interesting flags (wakeup conditions).
*/
public MouseRotateXY(int flags)
{
super(flags);
}
public void initialize()
{
super.initialize();
x_angle = 0;
x_factor = 0.01;
y_angle = 0;
y_factor = 0.01;
if ((flags & INVERT_INPUT) == INVERT_INPUT)
{
invert = true;
x_factor *= -1;
y_factor *= -1;
}
}
public double getXFactor()
{
return y_factor;
}
public void setXFactor( double factor)
{
x_factor = factor;
}
public double getYFactor()
{
return y_factor;
}
public void setYFactor( double factor)
{
y_factor = factor;
}
public void processStimulus (Enumeration criteria)
{
WakeupCriterion wakeup;
AWTEvent[] event;
int id;
int dx;
int dy;
while (criteria.hasMoreElements())
{
wakeup = (WakeupCriterion) criteria.nextElement();
if (wakeup instanceof WakeupOnAWTEvent)
{
event = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
for (int i=0; i<event.length; i++)
{
processMouseEvent((MouseEvent) event[i]);
if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) ||
((wakeUp)&&((flags & MANUAL_WAKEUP) != 0)))
{
id = event[i].getID();
if ((id == MouseEvent.MOUSE_DRAGGED) &&
!((MouseEvent)event[i]).isMetaDown() && !((MouseEvent)event[i]).isAltDown())
{
//
// Normal mouse drag
//
x = ((MouseEvent)event[i]).getX();
y = ((MouseEvent)event[i]).getY();
dx = x - x_last;
dy = y - y_last;
if (!reset)
{
y_angle = dx * x_factor;
x_angle = dy * y_factor;
if (allowXrot) transformX.rotX(x_angle);
transformY.rotY(y_angle);
transformGroup.getTransform(currXform);
Matrix4d mat = new Matrix4d();
// Remember old matrix
currXform.get(mat);
// Translate to origin
currXform.setTranslation(v3dOrigin);
if (invert)
{
currXform.mul(currXform, transformX);
currXform.mul(currXform, transformY);
}
else
{
currXform.mul(transformX, currXform);
currXform.mul(transformY, currXform);
}
// Set old translation back
Vector3d translation = new Vector3d(mat.m03,
mat.m13, mat.m23);
currXform.setTranslation(translation);
// Update xform
transformGroup.setTransform(currXform);
}
else
{
reset = false;
}
x_last = x;
y_last = y;
}
else if (id == MouseEvent.MOUSE_PRESSED)
{
System.out.println("Mouse pressed");
x = x_last = ((MouseEvent)event[i]).getX();
y = y_last = ((MouseEvent)event[i]).getY();
Point3d eyePos = new Point3d();
canvas3D.getCenterEyeInImagePlate(eyePos);
Point3d mousePos = new Point3d();
canvas3D.getPixelLocationInImagePlate(x, y,
mousePos);
Transform3D transform3D = new Transform3D();
canvas3D.getImagePlateToVworld(transform3D);
transform3D.transform(eyePos);
transform3D.transform(mousePos);
Vector3d mouseVec;
boolean parallel = false; // could check for
kind of projection here...
if (parallel)
{
mouseVec = new Vector3d(0.f, 0.f, -1.f);
}
else
{
mouseVec = new Vector3d();
mouseVec.sub(mousePos, eyePos);
mouseVec.normalize();
}
PickRay pickRay = new PickRay();
pickRay.set(mousePos, mouseVec);
SceneGraphPath sceneGraphPath[];
sceneGraphPath =
bgApplyTo.pickAllSorted(pickRay);
if (sceneGraphPath != null)
{
for (int j=0; j<sceneGraphPath.length; j++)
{
if (sceneGraphPath[j] != null)
{
Node node =
sceneGraphPath[j].getObject();
//System.out.println("Node type: " +
node.getClass().getName());
if (node instanceof Shape3D)
{
try
{
System.out.println("Found
Shape3D, moving anchor...");
Shape3D sph = (Shape3D)
node;
// HOW THE HELL DO I GET THE
COORDS FROM tgAnchor???
// This is just to compile!
// NOTE: THIS IS WHERE I GOT
STUCK..., BUT YOU SHOULD BE ABLE TO USE THE GENERAL
// CODE STRUCTURE.
Point3d pt = new
Point3d(0.0, 0.0, 0.0);
System.out.println("Click on
star not working!");
v3dRotationCenter.x = pt.x;
v3dRotationCenter.y = pt.y;
v3dRotationCenter.z = pt.z;
currXform.setTranslation(v3dRotationCenter);
tgAnchor.setTransform(currXform);
}
catch (CapabilityNotSetException
eCNS)
{
System.out.println("CapabilityNotSetException: " + eCNS.getMessage());
}
catch (Exception e)
{
System.out.println("Exception: " + e.getMessage());
}
} // if Shape3D
}
} // for loop
} // if sgp != null
} // else if PRESSED
}
}
}
}
wakeupOn (mouseCriterion);
}
}
=== END OF CODE BLOCK
=========================================================
----- Original Message -----
From: "Josh Richmond" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Wednesday, January 10, 2001 12:49 PM
Subject: [JAVA3D] Good orbit behaviour?
> Hi everyone,
>
> I've been struggling trying to write a good orbit behaviour (i.e, move the
view transform in response to mouse movement such that it appears as though
the scene is rotating around an arbitrary point in the scene). I know this
must be common code since many 3D viewers have, yet I can't find any sample
code to implement it.
>
> I also tried the arcball concept, but it seems to require the center of
rotation to be on the screen (unless I implemented it incorrectly).
>
> Most of my attempts work fine when the camera's frame is mostly aligned
with the world frame, but the mapping gets ruined after a lot of
manipulation.
>
> Can anyone point me to some sample code or at least a good reference on
how to implement this?
>
> Thanks!
> josh
>
>
===========================================================================
> To unsubscribe, send email to [EMAIL PROTECTED] and include in the
body
> of the message "signoff JAVA3D-INTEREST". For general help, send email to
> [EMAIL PROTECTED] and include in the body of the message "help".
>
===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff JAVA3D-INTEREST". For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".