2010-02-09 13 views
6

Buscando hacer la selección clásica de mouse OpenGL en ES. Prefiero no usar libs de terceros, puertos GLU y pilas de nombres OpenGL, etc., están fuera. Esto prácticamente deja la transformación de visión inversa y la intersección de rayos, ¿correcto?OpenGL ES (iPhone) Touch Picking

he conseguido bastante lejos con la ayuda de: http://trac.bookofhook.com/bookofhook/trac.cgi/wiki/MousePicking http://eigenclass.blogspot.com/2008/10/opengl-es-picking-using-ray-boundingbox.html

. . .pero todavía no estoy allí ¡Esto también huele a HAY QUE HABER UNA MANERA MÁS FÁCIL!

Aquí hay un código:

-(void)handleTouch:(CGPoint)point { 
    GLfloat width = backingWidth; 
    GLfloat height = backingHeight; 
    GLfloat x = point.x; 
    GLfloat y = point.y; 
    GLfloat z = 0.0f; 

    //viewport -> normalized dev coord -> clip 
    GLfloat n[] = { 
     2 * x/width - 1, 
     2 * y/height, 
     2 * z - 1, 
     1 
    }; 

    float fov = 45.0f * (M_PI/180.0f); 
    float near = 0.01, far = 10.0f; 
    float aspect = (float)backingWidth/(float)backingHeight; 
    float top = tan(fov) * near; 
    //float bottom = -top; 
    //float left = aspect * bottom; 
    float right = aspect * top; 

    //I'm a viewing volume symmetric projection matrix 
    GLfloat P[] = { 
     near/right, 0, 0, 0, 
     0, near/top, 0, 0, 
     0, 0, -(far + near)/(far - near), (-2 * far * near)/(far - near), 
     0, 0, -1, 0 
    }; 

    GLfloat Pminus1[] = { 
     1/P[0], 0, 0, 0, 
     0, 1/P[5], 0, 0, 
     0, 0, 0, 1/P[14], 
     0, 0, 1/P[11], -(P[10]/ (P[11]*P[14])) 
    }; 

    //clip -> view 
    GLfloat v[] = { 
     Pminus1[0] * n[0] + Pminus1[1] * n[1] + Pminus1[2] * n[2] + Pminus1[3] * n[3], 
     Pminus1[4] * n[0] + Pminus1[5] * n[1] + Pminus1[6] * n[2] + Pminus1[7] * n[3], 
     Pminus1[8] * n[0] + Pminus1[9] * n[1] + Pminus1[10] * n[2] + Pminus1[11] * n[3], 
     Pminus1[12] * n[0] + Pminus1[13] * n[1] + Pminus1[14] * n[2] + Pminus1[15] * n[3] 
    }; 

    //view -> world 
    GLfloat Rt[] = { 
     mv[0], mv[4], mv[8], 
     mv[1], mv[5], mv[9], 
     mv[2], mv[6], mv[10] 
    }; 

    GLfloat tPrime[] = { 
     Rt[0] * mv[3] + Rt[1] * mv[7] + Rt[2] * mv[11], 
     Rt[3] * mv[3] + Rt[4] * mv[7] + Rt[5] * mv[11], 
     Rt[6] * mv[3] + Rt[7] * mv[7] + Rt[8] * mv[11] 
    }; 

    GLfloat Mminus1[] = { 
     Rt[0], Rt[1], Rt[2], -(tPrime[0]), 
     Rt[3], Rt[4], Rt[5], -(tPrime[1]), 
     Rt[6], Rt[7], Rt[8], -(tPrime[2]), 
     0, 0, 0, 1 
    }; 

    //point in world space 
    GLfloat w[] = { 
     Mminus1[0] * v[0] + Mminus1[1] * v[1] + Mminus1[2] * v[2] + Mminus1[3] * v[3], 
     Mminus1[4] * v[0] + Mminus1[5] * v[1] + Mminus1[6] * v[2] + Mminus1[7] * v[3], 
     Mminus1[8] * v[0] + Mminus1[9] * v[1] + Mminus1[10] * v[2] + Mminus1[11] * v[3], 
     Mminus1[12] * v[0] + Mminus1[13] * v[1] + Mminus1[14] * v[2] + Mminus1[15] * v[3] 
    }; 

    //r = a + t(w - a) 
    GLfloat a[] = {0.0f, -0.1f, 0.0f}; 
    GLfloat wminusa[] = {w[0] - a[0], w[1] - a[1], w[2] - a[2]}; 

    vector[0] = a[0]; 
    vector[1] = a[1], 
    vector[2] = a[2]; 
    vector[3] = w[0]; 
    vector[4] = w[1]; 
    vector[5] = -10.0f; 

    //3 non-colinear points on the plane 
    GLfloat p1[] = {rect.origin.x, rect.origin.y, 0}; 
    GLfloat p2[] = {rect.origin.x + rect.size.width, rect.origin.y, 0}; 
    GLfloat p3[] = {rect.origin.x + rect.size.width, rect.origin.y + rect.size.height, 0}; 

    //location plane normal vector, Ax + By + Cz + D = 0 
    GLfloat lp[] = { 
     p1[1] * (p2[2] - p3[2]) + p2[1] * (p3[2] - p1[2]) + p3[1] * (p1[2] - p2[2]), 
     p1[2] * (p2[0] - p3[0]) + p2[2] * (p3[0] - p1[0]) + p3[2] * (p1[0] - p2[0]), 
     p1[0] * (p2[1] - p3[1]) + p2[0] * (p3[1] - p1[1]) + p3[0] * (p1[1] - p2[1]), 
     -(p1[0] * (((p2[1] * p3[2]) - (p3[1] * p2[2]))) + p2[0] * (((p3[1] * p1[2]) - (p1[1] * p3[2]))) + p3[0] * (((p1[1] * p2[2]) - (p2[1] * p1[2])))) 
    }; 

    GLfloat PnRd = (lp[0] * wminusa[0]) + (lp[1] * wminusa[1]) + (lp[2] * wminusa[2]); 
    if(PnRd != 0) { 
     GLfloat PnR0D = -((lp[0] * a[0]) + (lp[1] * a[1]) + (lp[2] * a[2]) + lp[3]); 
     if(PnR0D != 0) { 
      GLfloat t = PnR0D/PnRd; 
      if(t >= 0) { 
       GLfloat p[] = { 
        a[0] + wminusa[0] * t, 
        a[1] + wminusa[1] * t, 
        a[2] + wminusa[2] * t 
       }; 
       if(p[0] > rect.origin.x && 
        p[0] < rect.origin.x + rect.size.width && 
        p[1] > rect.origin.y && 
        p[1] < rect.origin.y + rect.size.height) 
        NSLog(@"BOOM!!!"); 
      } 
     } 
    } 
} 

Respuesta

1

he conseguido solucionarlo:

-(void)view2WorldPoint:(CGPoint)point :(GLfloat*)worldPoint { 
    // this is the inverse translation of the modelview 
    GLfloat width = (GLfloat)backingWidth; 
    GLfloat height = (GLfloat)backingHeight; 

    float clickX = point.x; 
    float clickY = point.y; 
    float clickZ = 0.0f; 

    NSLog(@"click point : x = %f, y = %f, z = %f", clickX, clickY, clickZ); 

    // NSLog(@"Me : x = %f, y = %f, z = %f", a[0], a[1], a[2]); 
    // NSLog(@"Dev : x = %f, y = %f, z = %f", squareX, squareY, squareZ); 

    //viewport -> normalized device coord -> clip 
    GLfloat n[] = { 
     2 * clickX/width - 1, 
     2 * (480-clickY)/height - 1, 
     2 * clickZ - 1, 
     1 
    }; 
    // NSLog(@"Obj : x = %f, y = %f, z = %f", rect.origin.x, rect.origin.y, -0.5); 
    // NSLog(@"N : x = %f, y = %f, z = %f", n[0], n[1], n[2]); 

    //I'm a viewing volume symmetric projection matrix 
    // GLfloat P[] = { 
    //  near/right, 0, 0, 0, 
    //  0, near/top, 0, 0, 
    //  0, 0, -(far + near)/(far - near), (-2 * far * near)/(far - near), 
    //  0, 0, -1, 0 
    // }; 
    GLfloat P[16]; 
    glGetFloatv(GL_PROJECTION_MATRIX, P); 
    // [self dumpMatrix:P :@"P"]; 

    GLfloat Pminus1[] = { 
     1/P[0], 0, 0, 0, 
     0, 1/P[5], 0, 0, 
     0, 0, 0, 1/P[11], 
     0, 0, 1/P[14], -(P[10]/ (P[11]*P[14])) 
    }; 

    // [self dumpMatrix:Pminus1 :@"P-1"]; 

    //clip -> view 
    GLfloat v[] = { 
     (Pminus1[0] * n[0]) + (Pminus1[1] * n[1]) + (Pminus1[2] * n[2]) + (Pminus1[3] * n[3]), 
     (Pminus1[4] * n[0]) + (Pminus1[5] * n[1]) + (Pminus1[6] * n[2]) + (Pminus1[7] * n[3]), 
     (Pminus1[8] * n[0]) + (Pminus1[9] * n[1]) + (Pminus1[10] * n[2]) + (Pminus1[11] * n[3]), 
     (Pminus1[12] * n[0]) + (Pminus1[13] * n[1]) + (Pminus1[14] * n[2]) + (Pminus1[15] * n[3]) 
    }; 

    // NSLog(@"v = [%f, %f, %f, %f]", v[0], v[1], v[2], v[3]); 


    // [self dumpMatrix:mv :@"mv"]; 

    //view -> world 
    GLfloat Rt[] = { 
     mv[0], mv[4], -mv[8], 
     mv[1], mv[5], -mv[9], 
     -mv[2], -mv[6], mv[10] 
    }; 

    // NSLog(@"Rt0 = [%f, %f, %f]", Rt[0], Rt[1], Rt[2]); 
    // NSLog(@"Rt1 = [%f, %f, %f]", Rt[3], Rt[4], Rt[5]); 
    // NSLog(@"Rt2 = [%f, %f, %f]", Rt[6], Rt[7], Rt[8]); 

    GLfloat tPrime[] = { 
     Rt[0] * mv[12] + Rt[1] * mv[13] + Rt[2] * mv[14], 
     Rt[3] * mv[12] + Rt[4] * mv[13] + Rt[5] * mv[14], 
     Rt[6] * mv[12] + Rt[7] * mv[13] + Rt[8] * mv[14] 
    }; 

    // NSLog(@"tPrime = [%f, %f, %f]", tPrime[0], tPrime[1], tPrime[2]); 

    GLfloat Mminus1[] = { 
     Rt[0], Rt[1], Rt[2], -(tPrime[0]), 
     Rt[3], Rt[4], Rt[5], -(tPrime[1]), 
     Rt[6], Rt[7], Rt[8], -(tPrime[2]), 
     0, 0, 0, 1 
    }; 

    //point in world space 
    GLfloat w[] = { 
     Mminus1[0] * v[0] + Mminus1[1] * v[1] + Mminus1[2] * v[2] + Mminus1[3] * v[3], 
     Mminus1[4] * v[0] + Mminus1[5] * v[1] + Mminus1[6] * v[2] + Mminus1[7] * v[3], 
     Mminus1[8] * v[0] + Mminus1[9] * v[1] + Mminus1[10] * v[2] + Mminus1[11] * v[3], 
     Mminus1[12] * v[0] + Mminus1[13] * v[1] + Mminus1[14] * v[2] + Mminus1[15] * v[3] 
    }; 
    NSLog(@"W : x = %f, y = %f, z = %f", w[0], w[1], w[2]); 
    worldPoint[0] = w[0]; 
    worldPoint[1] = w[1]; 
    worldPoint[2] = w[2]; 
} 
+0

En realidad, no entiendo por qué en la vista -> transformación mundial utiliza entradas negativas (por ejemplo, -m [8]). No debería haber entradas negativas. Además, tPrime está mal en mi opinión. mv [12] debería ser mv [3], mv [13] debería ser mv [7] y mv [14] debería ser mv [11]. Y mv no está declarado en ningún lado (supongo que es la maqueta). – Marc

+0

De acuerdo, he publicado una mejor solución. – jbg

1

bien, está bien que era todavía un poco buggy. Esto es lo que MAYORMENTE está funcionando ahora:

-(void)view2WorldPoint:(CGPoint)point :(GLfloat*)worldPoint { 
    float clickX = point.x; 
    float clickY = point.y; 
    float clickZ = -near; 

    //viewport -> normalized device coord -> clip 
    GLint viewport[4]; 
    glGetIntegerv(GL_VIEWPORT, viewport); 

    GLfloat n[] = { 
     (clickX - (float)viewport[0])/(float)viewport[2] * 2.0 - 1.0, 
     -((clickY - (float)viewport[1])/(float)viewport[3] * 2.0 - 1.0), 
     2.0 * clickZ - 1.0, 
     1.0 
    }; 

    GLfloat MP[16], MPInv[16]; 
    MatMatMultiply(MP, projMat, modelMat); 
    GenerateInverseMatrix4f(MPInv, MP); // replace this one with the whole 1/p thang? 

    GLfloat w[] = { 
     (MPInv[0] * n[0]) + (MPInv[4] * n[1]) + (MPInv[8] * n[2]) + (MPInv[12] * n[3]), 
     (MPInv[1] * n[0]) + (MPInv[5] * n[1]) + (MPInv[9] * n[2]) + (MPInv[13] * n[3]), 
     (MPInv[2] * n[0]) + (MPInv[6] * n[1]) + (MPInv[10] * n[2]) + (MPInv[14] * n[3]), 
     (MPInv[3] * n[0]) + (MPInv[7] * n[1]) + (MPInv[11] * n[2]) + (MPInv[15] * n[3]) 
    }; 

    worldPoint[0] = w[0]/w[3]; 
    worldPoint[1] = w[1]/w[3]; 
    worldPoint[2] = w[2]/w[3]; 
} 


float Determinant4f(const float m[16]) 
{ 
    return 
    m[12]*m[9]*m[6]*m[3]- 
    m[8]*m[13]*m[6]*m[3]- 
    m[12]*m[5]*m[10]*m[3]+ 
    m[4]*m[13]*m[10]*m[3]+ 
    m[8]*m[5]*m[14]*m[3]- 
    m[4]*m[9]*m[14]*m[3]- 
    m[12]*m[9]*m[2]*m[7]+ 
    m[8]*m[13]*m[2]*m[7]+ 
    m[12]*m[1]*m[10]*m[7]- 
    m[0]*m[13]*m[10]*m[7]- 
    m[8]*m[1]*m[14]*m[7]+ 
    m[0]*m[9]*m[14]*m[7]+ 
    m[12]*m[5]*m[2]*m[11]- 
    m[4]*m[13]*m[2]*m[11]- 
    m[12]*m[1]*m[6]*m[11]+ 
    m[0]*m[13]*m[6]*m[11]+ 
    m[4]*m[1]*m[14]*m[11]- 
    m[0]*m[5]*m[14]*m[11]- 
    m[8]*m[5]*m[2]*m[15]+ 
    m[4]*m[9]*m[2]*m[15]+ 
    m[8]*m[1]*m[6]*m[15]- 
    m[0]*m[9]*m[6]*m[15]- 
    m[4]*m[1]*m[10]*m[15]+ 
    m[0]*m[5]*m[10]*m[15]; 
} 

BOOL GenerateInverseMatrix4f(float i[16], const float m[16]) 
{ 
    float x=Determinant4f(m); 
    if (x==0) return FALSE; 

    i[0]= (-m[13]*m[10]*m[7] +m[9]*m[14]*m[7] +m[13]*m[6]*m[11] 
      -m[5]*m[14]*m[11] -m[9]*m[6]*m[15] +m[5]*m[10]*m[15])/x; 
    i[4]= (m[12]*m[10]*m[7] -m[8]*m[14]*m[7] -m[12]*m[6]*m[11] 
      +m[4]*m[14]*m[11] +m[8]*m[6]*m[15] -m[4]*m[10]*m[15])/x; 
    i[8]= (-m[12]*m[9]* m[7] +m[8]*m[13]*m[7] +m[12]*m[5]*m[11] 
      -m[4]*m[13]*m[11] -m[8]*m[5]*m[15] +m[4]*m[9]* m[15])/x; 
    i[12]=(m[12]*m[9]* m[6] -m[8]*m[13]*m[6] -m[12]*m[5]*m[10] 
      +m[4]*m[13]*m[10] +m[8]*m[5]*m[14] -m[4]*m[9]* m[14])/x; 
    i[1]= (m[13]*m[10]*m[3] -m[9]*m[14]*m[3] -m[13]*m[2]*m[11] 
      +m[1]*m[14]*m[11] +m[9]*m[2]*m[15] -m[1]*m[10]*m[15])/x; 
    i[5]= (-m[12]*m[10]*m[3] +m[8]*m[14]*m[3] +m[12]*m[2]*m[11] 
      -m[0]*m[14]*m[11] -m[8]*m[2]*m[15] +m[0]*m[10]*m[15])/x; 
    i[9]= (m[12]*m[9]* m[3] -m[8]*m[13]*m[3] -m[12]*m[1]*m[11] 
      +m[0]*m[13]*m[11] +m[8]*m[1]*m[15] -m[0]*m[9]* m[15])/x; 
    i[13]=(-m[12]*m[9]* m[2] +m[8]*m[13]*m[2] +m[12]*m[1]*m[10] 
      -m[0]*m[13]*m[10] -m[8]*m[1]*m[14] +m[0]*m[9]* m[14])/x; 
    i[2]= (-m[13]*m[6]* m[3] +m[5]*m[14]*m[3] +m[13]*m[2]*m[7] 
      -m[1]*m[14]*m[7] -m[5]*m[2]*m[15] +m[1]*m[6]* m[15])/x; 
    i[6]= (m[12]*m[6]* m[3] -m[4]*m[14]*m[3] -m[12]*m[2]*m[7] 
      +m[0]*m[14]*m[7] +m[4]*m[2]*m[15] -m[0]*m[6]* m[15])/x; 
    i[10]=(-m[12]*m[5]* m[3] +m[4]*m[13]*m[3] +m[12]*m[1]*m[7] 
      -m[0]*m[13]*m[7] -m[4]*m[1]*m[15] +m[0]*m[5]* m[15])/x; 
    i[14]=(m[12]*m[5]* m[2] -m[4]*m[13]*m[2] -m[12]*m[1]*m[6] 
      +m[0]*m[13]*m[6] +m[4]*m[1]*m[14] -m[0]*m[5]* m[14])/x; 
    i[3]= (m[9]* m[6]* m[3] -m[5]*m[10]*m[3] -m[9]* m[2]*m[7] 
      +m[1]*m[10]*m[7] +m[5]*m[2]*m[11] -m[1]*m[6]* m[11])/x; 
    i[7]= (-m[8]* m[6]* m[3] +m[4]*m[10]*m[3] +m[8]* m[2]*m[7] 
      -m[0]*m[10]*m[7] -m[4]*m[2]*m[11] +m[0]*m[6]* m[11])/x; 
    i[11]=(m[8]* m[5]* m[3] -m[4]*m[9]* m[3] -m[8]* m[1]*m[7] 
      +m[0]*m[9]* m[7] +m[4]*m[1]*m[11] -m[0]*m[5]* m[11])/x; 
    i[15]=(-m[8]* m[5]* m[2] +m[4]*m[9]* m[2] +m[8]* m[1]*m[6] 
      -m[0]*m[9]* m[6] -m[4]*m[1]*m[10] +m[0]*m[5]* m[10])/x; 

    return TRUE; 
} 

void MatMatMultiply(GLfloat *result, GLfloat *matrix1, GLfloat *matrix2) 
{ 
    result[0]=matrix1[0]*matrix2[0]+ 
    matrix1[4]*matrix2[1]+ 
    matrix1[8]*matrix2[2]+ 
    matrix1[12]*matrix2[3]; 
    result[4]=matrix1[0]*matrix2[4]+ 
    matrix1[4]*matrix2[5]+ 
    matrix1[8]*matrix2[6]+ 
    matrix1[12]*matrix2[7]; 
    result[8]=matrix1[0]*matrix2[8]+ 
    matrix1[4]*matrix2[9]+ 
    matrix1[8]*matrix2[10]+ 
    matrix1[12]*matrix2[11]; 
    result[12]=matrix1[0]*matrix2[12]+ 
    matrix1[4]*matrix2[13]+ 
    matrix1[8]*matrix2[14]+ 
    matrix1[12]*matrix2[15]; 
    result[1]=matrix1[1]*matrix2[0]+ 
    matrix1[5]*matrix2[1]+ 
    matrix1[9]*matrix2[2]+ 
    matrix1[13]*matrix2[3]; 
    result[5]=matrix1[1]*matrix2[4]+ 
    matrix1[5]*matrix2[5]+ 
    matrix1[9]*matrix2[6]+ 
    matrix1[13]*matrix2[7]; 
    result[9]=matrix1[1]*matrix2[8]+ 
    matrix1[5]*matrix2[9]+ 
    matrix1[9]*matrix2[10]+ 
    matrix1[13]*matrix2[11]; 
    result[13]=matrix1[1]*matrix2[12]+ 
    matrix1[5]*matrix2[13]+ 
    matrix1[9]*matrix2[14]+ 
    matrix1[13]*matrix2[15]; 
    result[2]=matrix1[2]*matrix2[0]+ 
    matrix1[6]*matrix2[1]+ 
    matrix1[10]*matrix2[2]+ 
    matrix1[14]*matrix2[3]; 
    result[6]=matrix1[2]*matrix2[4]+ 
    matrix1[6]*matrix2[5]+ 
    matrix1[10]*matrix2[6]+ 
    matrix1[14]*matrix2[7]; 
    result[10]=matrix1[2]*matrix2[8]+ 
    matrix1[6]*matrix2[9]+ 
    matrix1[10]*matrix2[10]+ 
    matrix1[14]*matrix2[11]; 
    result[14]=matrix1[2]*matrix2[12]+ 
    matrix1[6]*matrix2[13]+ 
    matrix1[10]*matrix2[14]+ 
    matrix1[14]*matrix2[15]; 
    result[3]=matrix1[3]*matrix2[0]+ 
    matrix1[7]*matrix2[1]+ 
    matrix1[11]*matrix2[2]+ 
    matrix1[15]*matrix2[3]; 
    result[7]=matrix1[3]*matrix2[4]+ 
    matrix1[7]*matrix2[5]+ 
    matrix1[11]*matrix2[6]+ 
    matrix1[15]*matrix2[7]; 
    result[11]=matrix1[3]*matrix2[8]+ 
    matrix1[7]*matrix2[9]+ 
    matrix1[11]*matrix2[10]+ 
    matrix1[15]*matrix2[11]; 
    result[15]=matrix1[3]*matrix2[12]+ 
    matrix1[7]*matrix2[13]+ 
    matrix1[11]*matrix2[14]+ 
    matrix1[15]*matrix2[15]; 
} 
+2

Gracias a Dios copiar/pegar existe ... –

1

Esta publicación es muy difícil de seguir. Estoy intentando lanzar el mío en iOS 5 con GLKView; He descubierto cómo detectar el píxel de detección RGBA como describo here, ahora estoy tratando de encontrar la forma de cambiar rápidamente los colores de mis objetos de escena para que sean únicos, para acompañar este método.

Cuestiones relacionadas