Looking to do classic OpenGL mouse picking in ES. I'd prefer not to use third party libs, GLU ports and OpenGL name stacks, etc, are out. This pretty much leaves inverse view transformation and ray intersection, correct?
I've gotten pretty far with the help of: http://trac.bookofhook.com/bookofhook/trac.cgi/wiki/MousePicking http://eigenclass.blogspot.com/2008/10/opengl-es-picking-using-ray-boundingbox.html
. . .but I'm not there yet. This also reeks of THERE MUST BE AN EASIER WAY!!
Here is some code:
-(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!!!");
}
}
}
}
This post is very hard to follow. I'm attempting to roll my own on iOS 5 with GLKView
; I've worked out how to touch detect pixel RGBA as I describe here, now I'm trying to work out how to quickly change the colours of my scene objects to be unique, to accompany this method.
I managed to fix it:
-(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];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With