Polygon picking?

Started by Kaiidyn, February 09, 2011, 11:01:35 AM

Previous topic - Next topic

Kaiidyn

So I got my terrain now.
What I need now is something like polygon picking?
I want to be able to tap the terrain at any position and return the world-space coordinates of where I tapped the terrain.
I think the most logical way to do this is to check which polygon is being tapped on, and return it's (x y and z) position..
I was looking at http://www.jpct.net/wiki/index.php/Picking but the 'fast way' does not work on android ( ? ) as world.getVisibilityList() does not exist..
Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer's intent but rather is full of crisp abstractions and straightforward lines of control. - Grady Booch

EgonOlsen

You can get the polygon from a CollisionListener implementation if you need it. Keep in mind that doing a collision detection on a high polygon terrain isn't particularly fast. You might want to experiment with an OcTree (might take some time to generate on Android, currently there's no support for serializing octrees created by the desktop version) for collision detection.

Kaiidyn

#2
Ok, got something working, however i get coordinates like
x: -0.18257418
y: -0.91287094
z: 0.36514837

public void collision(CollisionEvent ce) {
if (ce.getType()==CollisionEvent.TYPE_TARGET) {
PolygonManager pm = terrain.getPolygonManager();
SimpleVector polypos = pm.getTransformedNormal(ce.getPolygonIDs()[0]);
Log.d(polypos.x+":"+polypos.y+":"+polypos.z);
}
}


edit: got it working by changing getTransformedNormal to getTransformedVertex :D
Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer's intent but rather is full of crisp abstractions and straightforward lines of control. - Grady Booch

Kaiidyn

#3
New problem, this worked well when my player is 30 units high, now that I down-scaled it to 1 unit high to make my landscape look bigger it snaps to a vertex (long distance :o)
Is it possible to get a SimpleVector on the terrain where I actually touch it? (even between vertices).
Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer's intent but rather is full of crisp abstractions and straightforward lines of control. - Grady Booch

EgonOlsen

calcMinDistance() calculates the distance. The intersection point is position vector + distance*direction vector.

Kaiidyn

#5
the position vector, is that the vector of my box, or the polypos ?

how do i get the direction i need for this?
as i assume its not the direction i get with Interact2D.reproject2D3DWS
Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer's intent but rather is full of crisp abstractions and straightforward lines of control. - Grady Booch

EgonOlsen

calcMinDistance takes two vectors. The first one is the position, the second one the direction vector.

Kaiidyn

i know that, but how do i get the value of the direction vector?
Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer's intent but rather is full of crisp abstractions and straightforward lines of control. - Grady Booch

EgonOlsen

Which value? I don't get the question. The wiki already states how to create the direction vector for picking and reading your post, i assume that you already did this with success... ???

paulscode

The method I've always used to determine the "click point" works like this (I've not done this in an Android project, but the concept should be the same):

1) Use Interact2D.reproject2D3D to convert 2D click coordinates into 3D camera space
2) Use SimpleVector.matMul and SimpleVector.add to converted that to world space
3) Use SimpleVector.calcSub and SimpleVector.normalize to calculate the direction vector
4) Use World.calcMinDistance to obtain the distance
5) Use SimpleVector.add to obtain the 3D coordinates of the "click point".

So in an applet, I've used this procedure as follows:
        // Get the mouse's coordinates on the applet window:
        int x = e.getX();
        int y = e.getY();
       
        // Get the 3D coordinates in Camera space:
        SimpleVector position = new SimpleVector( Interact2D.reproject2D3D(
                                                       camera, buffer, x, y ) );
        // Convert the coordinates to World space:
        position.matMul( camera.getBack().invert3x3() );
        position.add( camera.getPosition() );
       
        // Determine the direction from the camera position to the click point:
        SimpleVector direction = position.calcSub( camera.getPosition() ).normalize();
       
        // Calculate the distance to whatever was clicked on:
        float distance = world.calcMinDistance( position, direction, 10000 );
       
        // Check if we clicked on something:
        if( distance == Object3D.COLLISION_NONE )
        {
            // Nope, didn't click on anything.
        }
        else
        {
            // Calculate the exact 3D coordinates for the point that was clicked:
            SimpleVector collisionPoint = new SimpleVector( direction );
            collisionPoint.scalarMul( distance );
            collisionPoint.add( position );
        }

EgonOlsen

Interesting...i stared at your code for a while being sure that it can't be correct. I wrote a test case and it actually is correct...however, it's "one step beyond". The example code in the wiki starts the calculation at the camera's position. You start the calculation at the camera's position + direction vector. So the results for distance will be different but the intersection point is the same. I think you came up with this, because it feels more natural to see the result of Interact2D.reproject2D3D as a position vector (which it actually is). However, it can be seen as a direction vector too, because the camera in camera space is always located at (0,0,0). In the wiki and other examples, i'm making use of this fact but i admit that it's not easy to understand why that works at first glance. Anyway, you can replace the matMul-step now. Newer version of jPCT have a method that returns the reprojected vector in world space.

EgonOlsen

I've just noticed that the code in the wiki was missing the normalize() calls for the direction vector. Again, the actual outcome (i.e. the intersection point) is the same, but the distance is correct only with normalize(). I've changed that in the wiki.

Kaiidyn

Thanks paul for your reply...
It works :) i have no idea how and why though,
I really need to study these kinds of maths more..
;D
Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer's intent but rather is full of crisp abstractions and straightforward lines of control. - Grady Booch

paulscode

#13
Quote from: EgonOlsen on February 15, 2011, 11:09:13 PMit can be seen as a direction vector too, because the camera in camera space is always located at (0,0,0).
Doh!  Talk about being redundant.  I always seem to come up with overly-complicated ways to do something simple..

So taking that into account and considering the new method you mentioned, the procedure becomes much simpler:

1) Use Interact2D.reproject2D3DWS and SimpleVector.normalize to convert 2D click coordinates into a direction vector in world space.
2) Use World.calcMinDistance to obtain the distance to the "click point".
3) Use SimpleVector.add to obtain the 3D coordinates of the "click point".

Using my earlier example, the code would look something like this:

        // Get the mouse's coordinates on the applet window:
        int x = e.getX();
        int y = e.getY();
       
        // Convert that into a direction vector in world space:
        SimpleVector direction = new SimpleVector( Interact2D.reproject2D3DWS(
                                                       camera, buffer, x, y ) ).normalize();

        // Calculate the distance to whatever was clicked on:
        float distance = world.calcMinDistance( camera.getPosition(), direction, 10000 );
       
        // Check if we clicked on something:
        if( distance == Object3D.COLLISION_NONE )
        {
            // Nope, didn't click on anything.
        }
        else
        {
            // Calculate the exact 3D coordinates for the point that was clicked:
            SimpleVector collisionPoint = new SimpleVector( direction );
            collisionPoint.scalarMul( distance );
            collisionPoint.add( camera.getPosition() );
        }

Kaiidyn

Ok, so I got the goto position now..
What I need next is for the player to move toward this position but keeping terrain height on x,z in consideration.
I have been thinking about a way to do this, but fact is, I have no clue how something like this works.
Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer's intent but rather is full of crisp abstractions and straightforward lines of control. - Grady Booch