|
Pick root
Bounds intersection, which is the low precision and first portion of the picking process,
is performed relative to a pick root node in the scene graph. The operation itself
is executed using one of the pick methods in the Locale or BranchGroup classes,
which limits your candidates for pick root in the scene graph to being one of these
types. Your pick root choice is important because only the leaf shape nodes under the
root will be considered. Also, the fewer nodes, especially pickable leaf nodes, that you
have under the pick root, the better the overall picking performance will be.
Bounds intersection
Bounds intersection is low precision and is performed using one of the pick methods
in the pick root object. These methods take a PickShape object as a parameter. Your
choice of pick method determines how thoroughly Java 3D will search the pick root
subgraph and how the hit results will be sorted. The methods pickAll, pickAllSorted,
and pickClosest perform an exhaustive search of the subgraph for
shape target hits, whereas the pickAny method searches only until the first one is
found. As their names indicate, pickAny and pickClosest return a single
SceneGraphPath hit result, which may be null if no shape target was hit, and pick-All
and pickAllSorted return an array of hits, which could be null.
If all you are interested in is low-precision bounds picking, then pickClosest
will probably do, which returns the single closest hit. The closest hit is the one that
the user sees as being immediately under the cursor (or should be under the cursor but
may not be because of the imprecision of bounds-based picking). In figure 13.2 the
closest hit would be the jet object, as shown. If, however, you need high-precision
geometry picking, then pickAll or pickAllSorted is needed. The pickAll
returns all the hits— the ship, the truck, and the jet— and pickAllSorted returns
them sorted closest to farthest— jet, then ship, then truck.
The following code fragment shows a simple example of how to use pickAllSorted
for bounds intersection as the first stage in picking, and to combine it
with geometry intersection and hit point determination in the second stage, which will
be covered next. The pick ray origin and direction are obtained as described in the previous
code sample.
// establish pick root
BranchGroup root;
...
// build pick ray
/// compute ray parameters from eye and mouse position
Point3d rayOrg = new Point3d();
Vector3d rayDir = new Vector3d ();
...
/// build pick ray object from ray origin and direction
PickRay ray = new PickRay(rayOrg, rayDir);
// throw the pick ray into the scene at all the leaf shape
// nodes under the pick root
SceneGraphPath paths[] = root.pickAllSorted(ray);
if( paths== null) {
System.out.println("no hits");
} else {
// shape target bounds were hit, check for real hits
for( int hitI= 0; hitI< paths.length; hitI++) {
System.out.println(" hit [" + hitI+ "]=" + paths[ hitI]);
// intersect pick ray with shape target geometry
Node shape = paths[ hitI].getObject();
double dist[] = {0.0};
boolean isRealHit = (( Shape3D) shape).intersect(
paths[ hitI], ray, dist);
if( isRealHit) {
// compute hit point from hit distance and pick ray
Point3d point = new Point3d();
point.scaleAdd( dist[ 0], rayDir, rayOrg);
System. out. println(" real hit at " + point);
}
}
}
Geometry intersection
The second portion of the overall picking process is geometry intersection, which provides
high precision picking by determining whether or not the pick shape actually
intersected the hit node's geometry and not just its bounds. It is performed using one
of the intersect methods on the hit leaf nodes returned by the bounds, picking
process. These methods take the pick shape and the hit's scene graph path as parameters.
Conveniently, bounds intersection returns only leaf nodes containing shape
geometry, which are the only types of leaf nodes capable of performing geometry inter-section.
This was shown in the previous code sample. Note, however, that the shape
was assumed to be a Shape3D object, but in general it could also be a Morph object.
One of the intersect methods takes a PickShape object as its parameter. The
other one takes only a PickRay object, but returns the hit distance. Thus, you have
to choose between using a general purpose pick shape, and determining the 3D hit
point. Neither bounds nor geometry intersection depends on the direction of the
shape's surface normals. This may seem like a non sequitur, but not if you are trying
to perform picking while looking through a backward facing shape, such as an invisible
wall in a room. Although the shape is invisible, it can still be picked, and will be if it
is a shape leaf under the pick root that is pickable.
In order for a node's intersect method to work, the Geometry.
ALLOW_ INTERSECT capability bit must be set on it's geometry component object.
Unlike pick reporting, however, there is no setIntersectable method in the API;
so, you must either set it in every shape leaf that you create and want to pick, or recursively
walk the scene graph and set it. The methods in the framework utility class
j3dui.utils.PickUtils should help with the latter approach.
Pick closest or all
Earlier it was mentioned that pickAll or pickAllSorted would be needed to
perform bounds picking if geometry intersection were to follow. For the highest
quality picking, the pickAll method should be used, and the hit that is closest as
determined by its intersect method hit distance would be deemed the closest hit.
This form of picking is also the slowest because all the bounds hits must be intersected
for geometry. A much faster but slightly less precise approach is to use the
pickAllSorted method and stop checking the bounds hit list when the first
geometry intersection is found. This compromise approach is used in the frame-work,
which can be seen in the j3dui.control.mappers.PickEngine.pick-TargetGeometry
method.
At this point in the picking process, what you have found is the closest shape tar-get
whose geometry intersects the pick shape. What you really want, however, is the
object target that was hit. As described above under pick reporting, if you took the
pains to set up the scene graph properly then the single group node in the hit shape's
SceneGraphPath object is the hit object. If not, then you will need to test the hit
shape's scene graph path nodes to see if any match the object targets in the target list.
If a shape hit is found but it doesn't contain an object hit, you can either quit (because
the closest object under the cursor was not a designated target object), or you can keep
looking. For direct manipulation, you probably want to quit if the object that the user
sees and is trying to drag is not an object target. For WRM, however, you probably
want to ignore all non-object target hits and, instead, keep hit testing until you find
the first (closest) valid target object that is hit.
Stop by in one week for the next installment!
New on the Java Boutique:
New Review:
Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling
API boasts simplicity, ease-of-integration, a well-rounded feature
set, and it's free!
New Applet:
Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA
sequences into three useful formats.
Elsewhere on internet.com:
WebDeveloper Java
Lots of Java information on webdeveloper.com
WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.
ScriptSearch Java
Hundreds of free Java code files to download.
jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.
|