Great!  I had overlooked the Shape3D.intersect method.  This is the key!
Once you have the picked Shape3D just intersect a ray generated from the
mouse x,y with the shape, which gives you the distance.  Use the ray origin
and vector scaled by this distance.  This makes it very easy...

Shape3D pick(Canvas3D canvas, BranchGroup rootBranchGroup, int x, int y,
Point3d pickedPoint)
{
    PickObject po = new PickObject(canvas, rootBranchGroup);
    SceneGraphPath sgp = po.pickClosest(x, y, PickObject.USE_GEOMETRY);
    if(sgp!=null) {
        PickRay ray = (PickRay)po.generatePickRay(x,y);
        double distance[] = new double[1];
        Vector3d rayvect = new Vector3d();
        for( int i=sgp.nodeCount()-1 ; i>=0 ; i-- ) {
            if(sgp.getNode(i) instanceof Shape3D) {
                Shape3D pickedShape = (Shape3D)sgp.getNode(i);
                if(pickedShape.intersect(sgp, ray, distance)) {
                    ray.get(pickedPoint, rayvect);
                    rayvect.scale(distance[0]);
                    pickedPoint.add(rayvect);
                    return pickedShape;
                }
            }
        }
    }
    return null;
}

Roger




At 12:55 PM 3/9/99 -0600, Weylin Debetaz wrote:
>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.
>
=====================================================================
To subscribe/unsubscribe, send mail to [EMAIL PROTECTED]
Java 3D Home Page: http://java.sun.com/products/java-media/3D/

Reply via email to