androidopengl-esopengl-es-2.0raycastingglsurfaceview

How to identify click inside the 3D object or outside 3D object using near and far positions


I am working in 3D object rendering using OpenGLES 2.0 with Android,Java code.How to identify click inside the 3D object or outside 3D object using following code near and far positions?

public static PointF screenToWorld(float[] viewMatrix,
                                       float[] projMatrix, float screenX, float screenY) {
        float[] nearPos = unProject(viewMatrix, projMatrix, screenX, screenY, 0);
        float[] farPos = unProject(viewMatrix, projMatrix, screenX, screenY, 1);

        Log.d(LOGTAG,"nearPos ->"+nearPos.length+" "+nearPos);
        Log.d(LOGTAG,"farPos ->"+farPos.length+" "+farPos);

        // The click occurred in somewhere on the line between the two points
        // nearPos and farPos. We want to find
        // where that line intersects the plane at z=0
        float distance = nearPos[2] / (nearPos[2] - farPos[2]); // Distance between nearPos and z=0
        float x = nearPos[0] + (farPos[0] - nearPos[0]) * distance;
        float y = nearPos[1] + (farPos[1] - nearPos[0]) * distance;
        return new PointF(x, y);
    }

    private static float[] unProject(float[] viewMatrix,
                                     float[] projMatrix, float screenX, float screenY, float depth) {
        float[] position = {0, 0, 0, 0};
        int[] viewPort = {0, 0, 1, 1};
        GLU.gluUnProject(screenX, screenY, depth, viewMatrix, 0, projMatrix, 0,
                viewPort, 0, position, 0);
        position[0] /= position[3];
        position[1] /= position[3];
        position[2] /= position[3];
        position[3] = 1;
        return position;

    }

Solution

  • How to identify click inside the 3D object or outside 3D objec?

    You have to verify if you hit any of the primitives of the object.

    The point at the near plane and the point at the far plane define a ray through the world:

    float[] nearPos = unProject(viewMatrix, projMatrix, screenX, screenY, 0);
    float[] farPos  = unProject(viewMatrix, projMatrix, screenX, screenY, 1);
    

    pseudo code:

    R0 = nearPos
    D  = normalize(farPos - nearPos)
    


    Find the intersection point of a ray with a primitive

    To find the surface which is hit by the ray, the distance of the intersection point of each surface (primitive) with the ray and the start point of the ray has to be calculated. The surface which has the lowest distance (in the ray direction), is hit.

    To find the distance of the intersection point of a ray with a triangle primitive, the following steps has to be done:

    1. Find the intersection point of the ray and the plane which is defined by the 3 points of the triangle primitive.
    2. Calculate the distance between the interection point and the start point of the ray.
    3. Test if the intersection point is in the direction of the ray (not in the opposite direction)
    4. Test if the intersection point is in or on the triangle contur.

    Find the intersection point and the intersection distance:

    enter image description here

    A plane is defined by a norm vector (NV) and a point on the plane (P0). If a triangle is given by the 3 points PA, PB and PC, the plane can be calculated as follows:

    P0 = PA
    NV = normalize( cross( PB-PA, PC-PA ) )
    

    The intersection of a ray with a plane is calculated by substituting the equation of the ray
    P_isect = dist * D + R0 into the equation of the plane dot( P_isect - P0, NV ) == 0.
    It follows:

    dist_isect = dot( P0 - R0, NV ) / dot( D, NV ) 
    P_isect    = R0 + D * dist_isect
    

    Test if the intersection point is in the direction of the ray:

    The intersection point is in the direction of the ray, if `dist_isect is greater or equal 0.0.

    Test if the intersection point is in or on the triangle contur

    To find out, if a point is inside a triangle, has to be tested, if the line from a corner point to the intersection point is between the to legs which are connect to the corner point:

    bool PointInOrOn( P1, P2, A, B )
    {
        CP1 = cross( B - A, P1 - A )
        CP2 = cross( B - A, P2 - A )
        return dot( CP1, CP2 ) >= 0
    }
    
    bool PointInOrOnTriangle( P, A, B, C )
    {
        return PointInOrOn( P, A, B, C ) &&
               PointInOrOn( P, B, C, A ) &&
               PointInOrOn( P, C, A, B )
    } 
    


    See also: Is it possble get which surface of cube will be click in OpenGL?