Надеясь делать классический выбор мыши OpenGL в ES. Я предпочел бы не использовать третье лицо, освобождает, порты GLU и стопки имени OpenGL, и т.д., отсутствуют. Это в значительной степени оставляет обратное преобразование представления и пересечение лучом, корректное?
Я стал довольно далеким с помощью: http://trac.bookofhook.com/bookofhook/trac.cgi/wiki/MousePicking http://eigenclass.blogspot.com/2008/10/opengl-es-picking-using-ray-boundingbox.html
.. .but я еще не там. Это также сильно пахнет ДОЛЖЕН БЫТЬ AN БОЛЕЕ ЛЕГКИЙ ПУТЬ!!
Вот некоторый код:
-(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!!!");
}
}
}
}
Мне удалось это исправить:
-(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];
}
Ладно, ладно, это все еще было немного глючно. Вот что сейчас почти работает:
-(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];
}