Here’s the whole code for picking that also gets you the position and the shape:
Vector branchGroups;
public PickResult pick(int x, int y) {
Point3f o = new Point3f();
Vector3f d = new Vector3f();
canvas.createPickRay(x,y,o,d);
TreeSet intersecting = new TreeSet();
Stack s = new Stack();
Point3f pos = new Point3f();
Vector3f pos1 = new Vector3f();
Vector3f pos2 = new Vector3f();
Vector3f pos3 = new Vector3f();
boolean result;
boolean nopos;
for(Enumeration e = branchGroups.elements(); e.hasMoreElements(); ) {
BranchGroup tg = (BranchGroup) e.nextElement();
s.clear();
s.push(tg);
while(!s.empty()) {
Node n = (Node) s.pop();
Bounds b = n.getVworldBounds();
result = false;
nopos = false;
if(b instanceof Sphere) result = ((Sphere) b).rayIntersection(o, d, pos);
else if(b instanceof Box) result = ((Box) b).rayIntersection(o, d, pos);
else if(b instanceof ConvexHull) result = ((ConvexHull) b).rayIntersection(o, d, pos);
else {
result = b.intersect(o,d);
nopos = true;
}
if(result) {
if(Group.class.isInstance(n)) {
Group g = (Group) n;
s.addAll(g.getChildren());
}
else {
float dist;
if(!nopos) dist = pos.distanceSquared(o);
else dist = 0;
if(n instanceof Shape3D) intersecting.add(new PickResult(c.getVObject(),(Shape3D) n, dist));
}
}
}
}
Triangle t = new Triangle();
Point3f transOrigin = new Point3f();
Vector3f transDirection = new Vector3f();
float closestIntersect = Float.POSITIVE_INFINITY;
PickResult nearest = null;
for(Iterator i = intersecting.iterator(); i.hasNext(); ) {
PickResult r = (PickResult) i.next();
Geometry geom = r.getGeom();
GeometryArray geomArr;
if(geom instanceof GeometryArray) geomArr = (GeometryArray) geom;
else if(geom instanceof GeometryTranslocator) geomArr = ((GeometryTranslocator) geom).getGeometry();
else geomArr = null; //User-defined Geometry is not supported - should be changed
transOrigin.set(o);
r.transform(transOrigin);
transDirection.set(d);
r.transform(transDirection);
if(geomArr != null) {
if(geomArr instanceof QuadArray) {
System.out.println("quad");
}
if(geomArr instanceof TriangleArray) {
int length = geomArr.getVertexCount();
for(int j = 0; j < length; j+=3) {
geomArr.getVertex(j,pos1);
geomArr.getVertex(j+1,pos2);
geomArr.getVertex(j+2,pos3);
t.set(pos1,pos2,pos3);
float f = t.test(transOrigin,transDirection,closestIntersect);
if(f != -1) { // there is a collision
f = f/transDirection.length();
if(f < closestIntersect) {
closestIntersect = f;
r.setDistance(f);
nearest = r;
}
}
}
}
if(geomArr instanceof TriangleFanArray) {
System.out.println("tri-fan");
}
if(geomArr instanceof TriangleStripArray) {
System.out.println("tri-strip");
}
}
}
if(nearest != null) {
Point3f p = new Point3f();
p.scaleAdd((float)Math.sqrt(nearest.getDistance()),d,o);
nearest.setPos(p);
return(nearest);
}
return(null);
}
public class Triangle {
Vector3f p1;
Vector3f p2;
Vector3f p3;
Point3f temp;
Vector3f t1,t2,t3;
public Triangle() {
temp = new Point3f();
t1 = new Vector3f();
t2 = new Vector3f();
t3 = new Vector3f();
}
public void set(Vector3f p1, Vector3f p2, Vector3f p3) {
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
}
public boolean testForIntersection(Tuple3f q, Vector3f dir) {
temp.scaleAdd(100000,dir,q);
int i = sign3D(temp,p1,q,p2);
int j = sign3D(temp,p3,p2,q);
int k = sign3D(temp,p1,p3,q);
if(i == 0 && j == 0) return true; // intersects in C
if(i == 0 && k == 0) return true; // intersects in A
if(j == 0 && k == 0) return true; // intersects in B
if(i == 0 && j == k) return true; // intersects in AC
if(j == 0 && i == k) return true; // intersects in BC
if(k == 0 && j == i) return true; // intersects in AB
if(i == j && j == k) return true; // intersects inside
return false; // does not intersect
}
public int sign3D(Tuple3f a, Tuple3f b, Tuple3f c, Tuple3f d) {
Matrix3f m = new Matrix3f(a.x-d.x, a.y-d.y, a.z-d.z,
b.x-d.x, b.y-d.y, b.z-d.z,
c.x-d.x, c.y-d.y, c.z-d.z);
float det = m.determinant();
if(det > 0.00001) return 1;
else if(det < -0.00001) return -1;
else return(0);
}
public float intersect(Point3f orig, Vector3f dir) {
t3.set(orig);
float r, a, b;
p2.sub(p1);
p3.sub(p1);
t1.cross(p2, p3);
if (t1.length() == 0) {
return(-1);
}
t3.sub(p1);
a = -t1.dot(t3);
b = t1.dot(dir);
if ((float)Math.abs(b) < 0.00001) {
return(-1);
}
r = a / b;
if (r < 0.0) {
return -1;
}
return r*r;
}
public float test(Point3f start, Vector3f dir, float nearestDist) {
// first check, if any intersection with the triangle can result in a nearer result
if(testForIntersection(start,dir)) { // if this is possible, check if there is an intersection with the triangle
// if there is an intersection calculate the exact position
float r = intersect(start,dir);
return(r);
}
return(-1);
}
}
public class PickResult implements Comparable{
VObject vobject;
Shape3D l;
Point3f pos = null;
Point3f direction = null;
Point3f origin = null;
float distance;
Transform3D temp;
Vector3f tvec;
/** Creates a new instance of PickResult */
public PickResult(VObject v, Shape3D l, float dist) {
vobject = v;
this.l = l;
distance = dist;
temp = new Transform3D();
tvec = new Vector3f();
}
public VObject getVObject() {
return(vobject);
}
public Geometry getGeom() {
return(l.getGeometry());
}
public void transform(Vector3f v) {
l.getLocalToVworld(temp);
temp.invert();
temp.transform(v);
}
public void transform(Point3f p) {
l.getLocalToVworld(temp);
temp.invert();
temp.transform(p);
}
public Point3f getPos() {
return(pos);
}
public void setPos(Point3f p) {
pos = p;
}
public float getDistance() {
return(distance);
}
public void setDistance(float f) {
distance = f;
}
public Vector3f getRayDir() {
return(null);
}
public Point3f getRayStart() {
return(null);
}
public String toString() {
return(vobject+": Leaf: "+l+" Pos:"+pos);
}
public int compareTo(Object o) {
if(o instanceof PickResult) {
PickResult r = (PickResult) o;
if(distance - r.distance > 0) return(1);
if(distance - r.distance < 0) return(-1);
}
return(0);
}
public boolean equals(Object o) {
if(o instanceof PickResult) {
PickResult r = (PickResult) o;
if(r.vobject == vobject && r.l == l && r.pos == pos && r.direction == direction) {
return(true);
}
}
return(false);
}
}
Please note, that there is still need to improvement, and it also works only for Trianglearrays.