Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect touch on OpenGL object?

Tags:

android

I am developing an application which uses OpenGL for rendering of the images.

Now I just want to determine the touch event on the opengl sphere object which I have drwn.

Here i draw 4 object on the screen. now how should I come to know that which object has been

touched. I have used onTouchEvent() method. But It gives me only x & y co-ordinates but my

object is drawn in 3D.

please help since I am new to OpenGL.

Best Regards, ~Anup enter image description here

like image 877
Anup Rojekar Avatar asked May 13 '11 10:05

Anup Rojekar


5 Answers

t Google IO there was a session on how OpenGL was used for Google Body on Android. The selecting of body parts was done by rendering each of them with a solid color into a hidden buffer, then based on the color that was on the touch x,y the corresponding object could be found. For performance purposes, only a small cropped area of 20x20 pixels around the touch point was rendered that way.

like image 68
Will Kru Avatar answered Nov 04 '22 15:11

Will Kru


Both approach (1. hidden color buffer and 2. intersection test) has its own merit. 1. Hidden color buffer: pixel read-out is a very slow operation. Certainly an overkill for a simple ray-sphere intersection test.

  1. Ray-sphere intersection test: this is not that difficult. Here is a simplified version of an implementation in Ogre3d.

    std::pair<bool, m_real> Ray::intersects(const Sphere& sphere) const
     {
    const Ray& ray=*this;
    const vector3& raydir = ray.direction();
    // Adjust ray origin relative to sphere center
    const vector3& rayorig = ray.origin() - sphere.center;
    m_real radius = sphere.radius;
    
    // Mmm, quadratics
    // Build coeffs which can be used with std quadratic solver
    // ie t = (-b +/- sqrt(b*b + 4ac)) / 2a
    m_real a = raydir%raydir;
    m_real b = 2 * rayorig%raydir;
    m_real c = rayorig%rayorig - radius*radius;
    
    // Calc determinant
    m_real d = (b*b) - (4 * a * c);
    if (d < 0)
    {
        // No intersection
        return std::pair<bool, m_real>(false, 0);
    }
    else
    {
        // BTW, if d=0 there is one intersection, if d > 0 there are 2
        // But we only want the closest one, so that's ok, just use the
        // '-' version of the solver
        m_real t = ( -b - sqrt(d) ) / (2 * a);
        if (t < 0)
        t = ( -b + sqrt(d) ) / (2 * a);
        return std::pair<bool, m_real>(true, t);
    }
    

    }

Probably, a ray that corresponds to cursor position also needs to be calculated. Again you can refer to Ogre3d's source code: search for getCameraToViewportRay. Basically, you need the view and projection matrix to calculate a Ray (a 3D position and a 3D direction) from 2D position.

like image 41
tbear Avatar answered Nov 04 '22 15:11

tbear


In my project, the solution I chose was:

  1. Unproject your 2D screen coordinates to a virtual 3D line going through your scene.
  2. Detect possible intersections of that line and your scene objects.

This is quite a complex tast.

like image 2
Cobra_Fast Avatar answered Nov 04 '22 13:11

Cobra_Fast


for find touch point is inside circle or not..

public boolean checkInsideCircle(float x,float y, float centerX,float centerY, float Radius)
    {
        if(((x - centerX)*(x - centerX))+((y - centerY)*(y - centerY)) < (Radius*Radius))
            return true;
        else
            return false;
    }

where

1) centerX,centerY are center point of circle.
2) Radius is radius of circle.
3) x,y point of touch..
like image 1
Niranj Patel Avatar answered Nov 04 '22 15:11

Niranj Patel


I have only done this in Direct3D rather than OpenGL ES, but these are the steps:

  1. Find your modelview and projection matrices. It seems that OpenGL ES has removed the ability to retrieve the matrices set by gluProject() etc. But you can use android.opengl.Matrix member functions to create these matrices instead, then set with glLoadMatrix().

  2. Call gluUnproject() twice, once with winZ=0, then with winZ=1. Pass the matrices you calculated earlier.

  3. This will output a 3d position from each call. This pair of positions define a ray in OpenGL "world space".

  4. Perform a ray - sphere intersection test on each of your spheres in order. (Closest to camera first, otherwise you may select a sphere that is hidden behind another.) If you detect an intersection, you've touched the sphere.

like image 2
Martin Stone Avatar answered Nov 04 '22 15:11

Martin Stone