2010-02-09 24 views
6

Cercando di fare il classico picking del mouse OpenGL in ES. Preferirei non utilizzare librerie di terze parti, porte GLU e stack di nomi OpenGL, ecc. Questo praticamente lascia la trasformazione della vista inversa e l'intersezione del raggio, corretta?OpenGL ES (iPhone) Touch Picking

me la sono cavata abbastanza lontano con l'aiuto di: http://trac.bookofhook.com/bookofhook/trac.cgi/wiki/MousePicking http://eigenclass.blogspot.com/2008/10/opengl-es-picking-using-ray-boundingbox.html

. . .ma non ci sono ancora. Questo puzza anche di ESISTE UN MODO PIÙ FACILE !!

Ecco il codice:

-(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!!!"); 
      } 
     } 
    } 
} 

risposta

1

sono riuscito a risolvere il problema:

-(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

In realtà, non capisco perché nella vista -> trasformazione del mondo si utilizzano voci negative (ad esempio -m [8]). Non ci dovrebbero essere voci negative. Inoltre, tPrime è sbagliato a mio avviso. mv [12] dovrebbe essere mv [3], mv [13] dovrebbe essere mv [7] e mv [14] dovrebbe essere mv [11]. E mv non è dichiarato da nessuna parte (presumo sia la modelview). – Marc

+0

D'accordo, ho pubblicato una soluzione migliore. – jbg

1

Va bene, va bene che era ancora un po 'buggy. Ecco cosa sta lavorando PIÙ ora:

-(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

Grazie a Dio copia/incolla esiste ... –

1

Questo post è molto difficile da seguire. Sto tentando di stampare da solo su iOS 5 con GLKView; Ho scoperto come toccare il pixel RGBA di rilevamento mentre descrivo here, ora sto cercando di capire come modificare rapidamente i colori dei miei oggetti scena in modo univoco, per accompagnare questo metodo.