Picking

i seem to be running into problems with all this :frowning:

i have tryed useing the view.pick(…) and the also
implemented the createPickRay(…)…

  1. view.pick(…) just doesnt seem to work… my nodes
    are node.setPickable(true); When i click the mouse
    sending the x, y location of the mouseClick (over a
    shape) it doesnt work. i have pritty much copyed the
    test case and its just not having it :(- do the PolygonAttributes
    matter with picking? what is if am using transparancy?

  2. createPickRay(…) i just dont no how to get this to
    work? how do i implement it so it returns me what
    i clicked on? every time i use it with:

     Point3f point = new Point3f(0, 0, 50f);
    Vector3f vec = new Vector3f(0, 0, 1);
    createPickRay(x, y, point, vec);
    Ray ray = new Ray(point, vec);
    System.out.println("ray, x, y: " + ray + ", " + x + ", " + y);

the ray doesnt seem to change when i click the mouse
all over the canvas? I dont need to no where on a shape
i clicked for now- just what shape got clicked…

can anyone help here? i guess i’ve missed the point
somewhere…

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.

You can also include it in Gamma, arne.

Yeah, but it’s not even a java class it’s just a function, but I think I could encapsulate it in a class. But I think it should then go to xith-tk anyways.

You’re right. ( in fact, we should merge jogl, xith3d, odejava in gamma :slight_smile: ).
You can include it in the org.magicspark.gamma.util.Util class. It’s made for that ! :wink:

arne thanks dude… :slight_smile:

VObject? is it the View? or somthing? also the lines:


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);

n.getVworldBounds(); returns a BoundingSphere not
a Bounds… so that doesnt compile so i changed it.

All the if elses dont work because its a BoundingSphere
so there not all needed. At this point. not sure if u are
using other packages here.


if(n instanceof Shape3D) intersecting.add(new PickResult(c.getVObject(),(Shape3D) n, dist));

no joy at all because i dont no what a VObject is…
c.getVObject()? whats ‘c’?

You can remove the VObject stuff, because that’s just something I use for my Game (to know which Object got picked and not only the Shape) - I thought I removed everything of this stuff, when I posted the code.

[quote]n.getVworldBounds(); returns a BoundingSphere not
a Bounds… so that doesnt compile so i changed it.
[/quote]
Oh yeah you’re right. n.getBounds() returns Bounds(), so I probably just had Bounds there because I used getBounds() before which was wrong and I haven’t noticed, that it changed to BoundingSphere when I corrected it.
But it should work anyways: BoundingSphere implements Bounds. That’s simply in com.xith3d.scenegraph. BoundingSphere extends Sphere in com.xith3d.spatial.bounds. So it should work, but your’s is simpler.

  • you will have to move all this instance creating out of this, if you want to use it frequently, so this will leave you with a lot of temporary variables.

If you have questions don’t bother asking!!

Arne

THANKS A LOT ARNE !!!

It’s so wonderful ! After a few minutes trying to understand something to the Picking posts in the JOGL/LWJGL sections, I remembered you had made some code and rushed on it.
I adapted it a bit :

  • I removed the VObject stuff entirely
  • I put it in a class (GraphicUtils, in Gamma)
  • I made it use the Triangle3D class in Gamma (and added your functions to this class)
    You can take a look at the code in the SVN repository.
    I’m actually making a pre-“level editor” (for now it’s just a test for the line intersection test in 2D).