I also needed to get the point in world and local coordinates. I lifted some code from
various sources to get the desired results. Here is a snippet from my "pick" behavior
that should generate the correct values. worldHitPoint and localHitPoint must be
instantiated before they are passed into pickTarget().
// preconstructed in instance for speed
transient private Point3d pickEyePos_ = new Point3d();
transient private Point3d pickMousePos_ = new Point3d();
transient private Transform3D pickXform_ = new Transform3D();
transient private Vector3d pickRayDir_ = new Vector3d();
transient private PickRay pickRay_ = new PickRay();
transient private double pickDist_[] = {0.0};
/**
* @param pickCanvas The canvas object that is the source of the mouse event
* @param mouseX MouseEvent's x coordinate
* @param mouseY MouseEvent's y coordinate
* @param worldHitPoint World coordinate for a valid hit
* @param localHitPoint Local coordinate for a valid hit
* @return True if the intersection is with a valid object
*/
public boolean pickTarget(Canvas3D pickCanvas,
int mouseX,
int mouseY,
Point3d worldHitPoint,
Point3d localHitPoint)
{
// build pick ray
/// get display positions
pickCanvas.getCenterEyeInImagePlate(pickEyePos_);
pickCanvas.getPixelLocationInImagePlate(mouseX, mouseY,
pickMousePos_);
/// transform to world positions
pickCanvas.getImagePlateToVworld(pickXform_);
pickXform_.transform(pickEyePos_);
pickXform_.transform(pickMousePos_);
/// build world ray
pickRayDir_.sub(pickMousePos_, pickEyePos_);
pickRayDir_.normalize();
pickRay_.set(pickEyePos_, pickRayDir_);
// pick test according to flag
SceneGraphPath hitPath[] = null;
// geometry picking
/// throw pick ray at bounds of objects under pick root
hitPath = pickRoot_.pickAllSorted(pickRay_);
/// if nothing hit, quit
if (hitPath != null)
{
for (int i=0; i<hitPath.length; i++)
{
if (hitPath[i] != null)
{
/// check for real hit against geometry
Node hitNode = hitPath[i].getObject();
boolean isHit = false;
if (hitNode instanceof Shape3D)
{
try
{
isHit = ((Shape3D) hitNode).intersect(hitPath[i], pickRay_, pickDist_);
if (isHit)
{
worldHitPoint.scaleAdd(pickDist_[0], pickRayDir_, pickEyePos_);
Transform3D t3d = new Transform3D();
hitNode.getLocalToVworld(t3d);
t3d.invert();
t3d.transform(worldHitPoint, localHitPoint);
return true;
}
}
catch (CapabilityNotSetException e)
{
// Catch all CapabilityNotSet exceptions and
// throw them away, prevents renderer from
// locking up when encountering "non-selectable"
// objects.
}
}
}
}
}
// no target hit
return false;
}
Hope this is helpful,
Weylin
Guillaume Bilodeau wrote:
> Hi,
>
> Thank you for your answer. It is indeed pretty complex and probably very
>slow
> to do all those calculations. Like you say, I hope Sun includes such a method
> in a future release, I know other 3D libraries offer it and I have to say, it is
> a must.
>
> For now, if this could be of interest to anyone, I have resorted to an
> approximation of the 3d point. I generate a PickRay with the PickObject class,
> get the closest Shape3D, and then get the associated Transform3D from the
> SceneGraphPath. Then I use the z component of the Transform3D translation as an
> approximation for the z component of the picked point. I finally use the
> PickRay vector to calculate the x and y components of the picked point.
>
> This is obviously very approximate, but it still does a good job most of the
> time.
>
> > After thinking about this some more it isn't so easy. When I answered I
> > was looking at some code which manually intersects a ray and a single quad
> > from a generated ray, which does give the distance to the picked point. It
> > is possible to do what you want but it will take quite a bit of code.
> > Maybe the Java3D team at Sun has a better solution???
> >
> > 1) pick the closest geometry using the mouse x,y
> > 2) get the picked Shape3D from the SceneGraphPath object returned by
> > pickClosest
> > 3) generate a ray using generatePickRay with the mouse x,y (the same ray
> > used to pick the Shape3D)
> > 4) intersect that ray with all the quads or tris in the Shap3D's geometry
> > (this is a lot of code for all the different geometry types)
> > 5) when you find an intersection use the distance, ray origin, and ray
> > vector as I described before to get your 3D point
> >
> > I would provide this code but it will take a while and I don't need it
> > right now. This is vital functionality so maybe Sun will put it in a
> > future release. It would be MUCH easier to do this inside the pickClosest
> > code where the needed information should already be available.
begin:vcard
adr;dom:;;;Dallas;TX;75234;
n:Debetaz;Weylin
x-mozilla-html:FALSE
org:i2 Technologies
version:2.1
email;internet:[EMAIL PROTECTED]
title:Software Engineer
tel;fax:(214) 860-6067
tel;work:(214) 515-3789
x-mozilla-cpt:;0
fn:Weylin Debetaz
end:vcard