Question

I'm drawing a globe using OpenGL on Android platform and trying to find a point on the sphere where user tapped. I am new to OpenGL at all and I'm using opensource lib Rajawali as it is show in example Touch & Drag but if someone know better way to do this please suggest me as the code of Rajawali is completely without comments and huge part of docs are outdated :(

double[] np4 = new double[4]; //near plane
double[] fp4 = new double[4]; // far plane

GLU.gluUnProject(
        x, mViewportHeight - y, 0.0f, 
        mViewMatrix.getDoubleValues(), 0, 
        mProjectionMatrix.getDoubleValues(), 0, 
        mViewport, 0, 
        np4, 0
);

GLU.gluUnProject(
        x, mViewportHeight - y, 1.0f, 
        mViewMatrix.getDoubleValues(), 0, 
        mProjectionMatrix.getDoubleValues(), 0, 
        mViewport, 0, 
        fp4, 0
);

// transform 4D coordinates (x, y, z, w) to 3D (x, y, z) by dividing each coordinate (x, y, z) by w.
return new Ray(
        new Vector3(np4[0] / np4[3], np4[1] / np4[3], np4[2] / np4[3]),
        new Vector3(fp4[0] / fp4[3], fp4[1] / fp4[3], fp4[2] / fp4[3])
    );

and then find an intersection point with sphere (radius = 1, center (0,0,0)) as described here

    /**
     * Calculate point of intersection of line and sphere.
     * 
     * @param p1 Point the line goes throw
     * @param p2 Point the line goes throw
     * @param center Center of the sphere
     * @param r Radius of the sphere
     * @return <code>Vector3</code> Coordinates of intersection point
     */
    private Vector3 getIntersectionPoint(Vector3 p1, Vector3 p2, Vector3 center, double r){
        if (p1 == null || p2 == null || center == null)
            return null;

        double a = in2(p2.x - p1.x) + in2(p2.y - p1.y) + in2(p2.z - p1.z);
        double b = 2*( (p2.x - p1.x)*(p1.x - center.x) + (p2.y - p1.y)*(p1.y - center.y) + (p2.z - p1.z)*(p1.z - center.z) );
        double c = in2(center.x) + in2(center.y) + in2(center.z) + in2(p1.x) + in2(p1.y) + in2(p1.z) - 2*(center.x*p1.x + center.y*p1.y + center.z*p1.z) - in2(r);

        //simplified equations for Sphere coordinates are (0, 0, 0) r=1 and cam.x = cam.y = 0
//      double a = in2(p2.x) + in2(p2.y) + in2(p2.z - p1.z);
//      double b = 2*( (p2.z - p1.z)*p1.z );
//      double c = in2(p1.z) - 1;

        for (Vector3 poi : solveQuadraticEquation(a, b, c, p1, p2)){
            if (poi.z > 0)
                return poi;
        }

        return null;
    }


    /**
     * Solve quadratic equation.
     * 
     * @param a Parameter A in equation Ax^2 + Bx + C = 0
     * @param b Parameter B in equation Ax^2 + Bx + C = 0
     * @param c Parameter C in equation Ax^2 + Bx + C = 0
     * @param p1 <code>Vector3</code> Start point for the line
     * @param p2 <code>Vector3</code> End point for the line
     * 
     * @return <code>List<Vector3></code> of results. Empty if no results found.
     */
    private List<Vector3> solveQuadraticEquation(double a, double b, double c, Vector3 p1, Vector3 p2){
        double D = in2(b) - 4*a*c;

        List<Vector3> rez = new ArrayList<Vector3>();

        if (D < 0) {

            return rez;

        } else  if (D == 0) {

            double t = (-b) / (2*a);
            rez.add(new Vector3(p1.x + (p2.x - p1.x)*t, p1.y + (p2.y - p1.y)*t, p1.z + (p2.z - p1.z)*t));

            return rez;

        } else {


            double t = (Math.sqrt(D)-b) / (2*a);
            rez.add(new Vector3(p1.x + (p2.x - p1.x)*t, p1.y + (p2.y - p1.y)*t, p1.z + (p2.z - p1.z)*t));

            t = (-Math.sqrt(D)-b) / (2*a);
            rez.add(new Vector3(p1.x + (p2.x - p1.x)*t, p1.y + (p2.y - p1.y)*t, p1.z + (p2.z - p1.z)*t));

            return rez;

        }
    }

and here is a result:

enter image description here

Here: BLUE dots are (-1, -1, -1), (1, -1, -1), (1, 1, -1) and (-1, 1, -1) GREEN dots are (-1, -1, 1), (1, -1, 1), (1, 1, 1) and (-1, 1, 1) YELLOW dots are (1, 0, 0), (0, 1, 0), (-1, 0, 0) and (0, -1, 0)

small red dot is a point of intersection when I tapped on top yellow circle: x: 405.10202 y: 430.5059 (event.getX(), evet.getY() in touch listener) here is a unprojected points: near: Vector3 : <0.0038529188490706075, 0.08910624125329661, 4.999999999999999> far: Vector3 : <0.46235026188847467, 10.692748950395632, -114.00000000000048> intersection: Vector3 : <0.019687997272589165, 0.45532322467387265, 0.8901085011592542>

camera position is (0,0,-6)

Could anybody help me put this small red dot under the finger, please ?

P.S. I need a point of intersection not just an object picking beckause I'm going to get country code by this point later...

Was it helpful?

Solution

The problem is that ViewPort correspond to the view dimensions (GLSurfaceView in this case) but point hase absolute coordinates, so the should be converted to relative, for example like this:

final float x = e.getX() - getLeft();
final float y = e.getY() - getTop();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top