Je travaille sur ce sujet depuis plusieurs jours et j'ai été bloqué. Je dois être en mesure de toucher l'écran et de renvoyer les coordonnées x, y, z du point de mon modèle le plus proche du plan proche qui coupe le rayon généré au point de sélection. Je pense qu'une partie de mon problème est que je fais un tas de transformations matricielles et de rotations à travers le code de rendu pour mon modèle, bien que la géométrie qui m'intéresse soit rendue à un état de transformation spécifique. Mon code que j'utilise est ci-dessous. Si quelqu'un peut m'aider à comprendre comment cela fonctionne, ce serait génial. checkCollision() est alimenté par le point sur lequel l'utilisateur clique, et gluUnProject() est supposé transformer mon point de prélèvement 2D en coordonnées 3D sur mes plans proches et lointains, 0 étant le plan proche et 1 étant le plan lointain. Mon utilisation est ici et est appelé juste avant la géométrie est rendue, de sorte que tous les transformations ont déjà été appliquées:Carrefour d'intersection Ray-Triangle ne fonctionnant pas
[self checkCollision:touchPoint panVector:panVec];
Ce code ci-dessous est le code de vérification de collision:
-(Boolean) checkCollision:(CGPoint)winPos panVector:(Vector3f*)panVec
{
glGetIntegerv(GL_VIEWPORT, viewport);
winPos.y = (float)viewport[3] - winPos.y;
Vector3f nearPoint;
Vector3f farPoint;
glGetFloatv(GL_PROJECTION_MATRIX, projection);
glGetFloatv(GL_MODELVIEW_MATRIX, modelview);
//Retreiving position projected on near plane
gluUnProject(winPos.x, winPos.y , 0, modelview, projection, viewport, &nearPoint.x, &nearPoint.y, &nearPoint.z);
//Retreiving position projected on far plane
gluUnProject(winPos.x, winPos.y, 1, modelview, projection, viewport, &farPoint.x, &farPoint.y, &farPoint.z);
Vector3f *near = [[Vector3f alloc] initWithFloatsX:nearPoint.x Y:nearPoint.y Z:nearPoint.z];
Vector3f *far = [[Vector3f alloc] initWithFloatsX:farPoint.x Y:farPoint.y Z:farPoint.z];
Vector3f *d = [Vector3f subtractV1:far minusV2:near];
Vector3f *v0 = [[Vector3f alloc] init];
Vector3f *v1 = [[Vector3f alloc] init];
Vector3f *v2 = [[Vector3f alloc] init];
Vector3f *e1; // = [[Vector3f alloc] init];
Vector3f *e2; // = [[Vector3f alloc] init];
for (int i = 0; i < assemblyObj->numObjects; i++) {
for (int j = 0; j < assemblyObj->partList[i].numVertices; j+=18) {
v0.x = assemblyObj->partList[i].vertices[j+0];
v0.y = assemblyObj->partList[i].vertices[j+1];
v0.z = assemblyObj->partList[i].vertices[j+2];
v1.x = assemblyObj->partList[i].vertices[j+6];
v1.y = assemblyObj->partList[i].vertices[j+7];
v1.z = assemblyObj->partList[i].vertices[j+8];
v2.x = assemblyObj->partList[i].vertices[j+12];
v2.y = assemblyObj->partList[i].vertices[j+13];
v2.z = assemblyObj->partList[i].vertices[j+14];
e1 = [Vector3f subtractV1:v1 minusV2:v0];
e2 = [Vector3f subtractV1:v2 minusV2:v0];
Vector3f *p = [[Vector3f alloc] init];
[Vector3f cross:p V1:d V2:e2];
float a = [Vector3f dot:e1 V2:p];
if (a > -.000001 && a < .000001) {
continue;
}
float f = 1/a;
Vector3f *s = [Vector3f subtractV1:near minusV2:v0];
float u = f*([Vector3f dot:s V2:p]);
if (u<0 || u>1) {
continue;
}
Vector3f *q = [[Vector3f alloc] init];
[Vector3f cross:q V1:s V2:e1];
float v = f*([Vector3f dot:d V2:q]);
if (v<0 || (u+v)>1) {
continue;
}
//NSLog(@"hit polygon");
return true;
}
}
//NSLog(@"didn't hit polygon");
return FALSE;
}
GLint gluUnProject(GLfloat winx, GLfloat winy, GLfloat winz,
const GLfloat model[16], const GLfloat proj[16],
const GLint viewport[4],
GLfloat * objx, GLfloat * objy, GLfloat * objz)
{
/* matrice de transformation */
GLfloat m[16], A[16];
GLfloat in[4], out[4];
/* transformation coordonnees normalisees entre -1 et 1 */
in[0] = (winx - viewport[0]) * 2/viewport[2] - 1.f;
in[1] = (winy - viewport[1]) * 2/viewport[3] - 1.f;
in[2] = 2 * winz - 1.f;
in[3] = 1.f;
/* calcul transformation inverse */
matmul(A, proj, model);
invert_matrix(A, m);
/* d'ou les coordonnees objets */
transform_point(out, m, in);
if (out[3] == 0.f)
return GL_FALSE;
*objx = out[0]/out[3];
*objy = out[1]/out[3];
*objz = out[2]/out[3];
return GL_TRUE;
}
void transform_point(GLfloat out[4], const GLfloat m[16], const GLfloat in[4])
{
#define M(row,col) m[col*4+row]
out[0] =
M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
out[1] =
M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
out[2] =
M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
out[3] =
M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
#undef M
}
void matmul(GLfloat * product, const GLfloat * a, const GLfloat * b)
{
/* This matmul was contributed by Thomas Malik */
GLfloat temp[16];
GLint i;
#define A(row,col) a[(col<<2)+row]
#define B(row,col) b[(col<<2)+row]
#define T(row,col) temp[(col<<2)+row]
/* i-te Zeile */
for (i = 0; i < 4; i++) {
T(i, 0) =
A(i, 0) * B(0, 0) + A(i, 1) * B(1, 0) + A(i, 2) * B(2, 0) + A(i,
3) *
B(3, 0);
T(i, 1) =
A(i, 0) * B(0, 1) + A(i, 1) * B(1, 1) + A(i, 2) * B(2, 1) + A(i,
3) *
B(3, 1);
T(i, 2) =
A(i, 0) * B(0, 2) + A(i, 1) * B(1, 2) + A(i, 2) * B(2, 2) + A(i,
3) *
B(3, 2);
T(i, 3) =
A(i, 0) * B(0, 3) + A(i, 1) * B(1, 3) + A(i, 2) * B(2, 3) + A(i,
3) *
B(3, 3);
}
#undef A
#undef B
#undef T
memcpy(product, temp, 16 * sizeof(GLfloat));
}
int invert_matrix(const GLfloat * m, GLfloat * out)
{
/* NB. OpenGL Matrices are COLUMN major. */
#define SWAP_ROWS(a, b) { GLfloat *_tmp = a; (a)=(b); (b)=_tmp; }
#define MAT(m,r,c) (m)[(c)*4+(r)]
GLfloat wtmp[4][8];
GLfloat m0, m1, m2, m3, s;
GLfloat *r0, *r1, *r2, *r3;
r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
r0[0] = MAT(m, 0, 0), r0[1] = MAT(m, 0, 1),
r0[2] = MAT(m, 0, 2), r0[3] = MAT(m, 0, 3),
r0[4] = 1.f, r0[5] = r0[6] = r0[7] = 0.f,
r1[0] = MAT(m, 1, 0), r1[1] = MAT(m, 1, 1),
r1[2] = MAT(m, 1, 2), r1[3] = MAT(m, 1, 3),
r1[5] = 1.f, r1[4] = r1[6] = r1[7] = 0.f,
r2[0] = MAT(m, 2, 0), r2[1] = MAT(m, 2, 1),
r2[2] = MAT(m, 2, 2), r2[3] = MAT(m, 2, 3),
r2[6] = 1.f, r2[4] = r2[5] = r2[7] = 0.f,
r3[0] = MAT(m, 3, 0), r3[1] = MAT(m, 3, 1),
r3[2] = MAT(m, 3, 2), r3[3] = MAT(m, 3, 3),
r3[7] = 1.f, r3[4] = r3[5] = r3[6] = 0.f;
/* choose pivot - or die */
if (fabsf(r3[0]) > fabsf(r2[0]))
SWAP_ROWS(r3, r2);
if (fabsf(r2[0]) > fabsf(r1[0]))
SWAP_ROWS(r2, r1);
if (fabsf(r1[0]) > fabsf(r0[0]))
SWAP_ROWS(r1, r0);
if (0.f == r0[0])
return GL_FALSE;
/* eliminate first variable */
m1 = r1[0]/r0[0];
m2 = r2[0]/r0[0];
m3 = r3[0]/r0[0];
s = r0[1];
r1[1] -= m1 * s;
r2[1] -= m2 * s;
r3[1] -= m3 * s;
s = r0[2];
r1[2] -= m1 * s;
r2[2] -= m2 * s;
r3[2] -= m3 * s;
s = r0[3];
r1[3] -= m1 * s;
r2[3] -= m2 * s;
r3[3] -= m3 * s;
s = r0[4];
if (s != 0.f) {
r1[4] -= m1 * s;
r2[4] -= m2 * s;
r3[4] -= m3 * s;
}
s = r0[5];
if (s != 0.f) {
r1[5] -= m1 * s;
r2[5] -= m2 * s;
r3[5] -= m3 * s;
}
s = r0[6];
if (s != 0.f) {
r1[6] -= m1 * s;
r2[6] -= m2 * s;
r3[6] -= m3 * s;
}
s = r0[7];
if (s != 0.f) {
r1[7] -= m1 * s;
r2[7] -= m2 * s;
r3[7] -= m3 * s;
}
/* choose pivot - or die */
if (fabsf(r3[1]) > fabsf(r2[1]))
SWAP_ROWS(r3, r2);
if (fabsf(r2[1]) > fabsf(r1[1]))
SWAP_ROWS(r2, r1);
if (0.f == r1[1])
return GL_FALSE;
/* eliminate second variable */
m2 = r2[1]/r1[1];
m3 = r3[1]/r1[1];
r2[2] -= m2 * r1[2];
r3[2] -= m3 * r1[2];
r2[3] -= m2 * r1[3];
r3[3] -= m3 * r1[3];
s = r1[4];
if (0.f != s) {
r2[4] -= m2 * s;
r3[4] -= m3 * s;
}
s = r1[5];
if (0.f != s) {
r2[5] -= m2 * s;
r3[5] -= m3 * s;
}
s = r1[6];
if (0.f != s) {
r2[6] -= m2 * s;
r3[6] -= m3 * s;
}
s = r1[7];
if (0.f != s) {
r2[7] -= m2 * s;
r3[7] -= m3 * s;
}
/* choose pivot - or die */
if (fabs(r3[2]) > fabs(r2[2]))
SWAP_ROWS(r3, r2);
if (0.f == r2[2])
return GL_FALSE;
/* eliminate third variable */
m3 = r3[2]/r2[2];
r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], r3[7] -= m3 * r2[7];
/* last check */
if (0.f == r3[3])
return GL_FALSE;
s = 1.f/r3[3]; /* now back substitute row 3 */
r3[4] *= s;
r3[5] *= s;
r3[6] *= s;
r3[7] *= s;
m2 = r2[3]; /* now back substitute row 2 */
s = 1.f/r2[2];
r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
m1 = r1[3];
r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
m0 = r0[3];
r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
m1 = r1[2]; /* now back substitute row 1 */
s = 1.f/r1[1];
r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
m0 = r0[2];
r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
m0 = r0[1]; /* now back substitute row 0 */
s = 1.f/r0[0];
r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
MAT(out, 0, 0) = r0[4];
MAT(out, 0, 1) = r0[5], MAT(out, 0, 2) = r0[6];
MAT(out, 0, 3) = r0[7], MAT(out, 1, 0) = r1[4];
MAT(out, 1, 1) = r1[5], MAT(out, 1, 2) = r1[6];
MAT(out, 1, 3) = r1[7], MAT(out, 2, 0) = r2[4];
MAT(out, 2, 1) = r2[5], MAT(out, 2, 2) = r2[6];
MAT(out, 2, 3) = r2[7], MAT(out, 3, 0) = r3[4];
MAT(out, 3, 1) = r3[5], MAT(out, 3, 2) = r3[6];
MAT(out, 3, 3) = r3[7];
return GL_TRUE;
#undef MAT
#undef SWAP_ROWS
}
Edit:
J'ai suivi la suggestion de Justin Meiners de montrer des points pour montrer où mon rayon de prise est généré et je peux voir ce qui se passe maintenant, mais je ne sais pas pourquoi. Ma scène implémente la rotation d'arcball, le zoom et le panoramique à travers les quaternions. Je vais énoncer à peu près ce que ma scène est en train de faire, alors ce qui se passe avec mon rayon.
D'abord, configurer ma fenêtre:
glViewport(0, 0, scene.width, scene.height);
glOrthof(-11.25, 11.25, -14.355, 14.355, -1000, 1000);
Ensuite, je prends la matrice de l'élément 16 que j'utilise dans le cadre de ma méthode arcball pour naviguer ma scène et multiplier ma matrice modelview par celle-ci:
float mat[16];
[arcball get_Renamed:mat];
glMultMatrixf(mat);
maintenant, je fais mon choix ray:
glGetIntegerv(GL_VIEWPORT, viewport);
glGetFloatv(GL_PROJECTION_MATRIX, projection);
glGetFloatv(GL_MODELVIEW_MATRIX, modelview);
touchPoint.y = (float)viewport[3] - touchPoint.y;
Vector3f nearPoint, farPoint;
//Retreiving position projected on near plane
gluUnProject(touchPoint.x, touchPoint.y , 0, modelview, projection, viewport, &nearPoint.x, &nearPoint.y, &nearPoint.z);
//Retreiving position projected on far plane
gluUnProject(touchPoint.x, touchPoint.y, 1, modelview, projection, viewport, &farPoint.x, &farPoint.y, &farPoint.z);
float coords[3] = {nearPoint.x, nearPoint.y, nearPoint.z};
float coords2[3] = {farPoint.x, farPoint.y, farPoint.z};
glPointSize(100);
glColor4f(1, 0, 0, 1);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(coords[0])*3, coords);
glDrawArrays(GL_POINTS, 0, 1);
glPointSize(150);
glColor4f(0, 0, 1, 1);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(coords2[0])*3, coords2);
glDrawArrays(GL_POINTS, 0, 1);
glDisableClientState(GL_VERTEX_ARRAY);
je fais cela, et il fonctionne très bien avant que je fais tourner ma scène , mais dès que je commence à tourner ma scène, le point lointain commence à bouger. Si je fais pivoter la scène d'exactement 180 degrés, le point éloigné est de retour au point le plus proche. Une idée de ce qui se passe? L'arcball est basé sur l'algorithme de Ken Shoemake.
Comment dessinez-vous votre rayon de souris en utilisant GL_LINES? J'essayais de le faire, mais je n'arrivais pas à comprendre comment. C'est OpenGL-ES dont vous parlez, n'est-ce pas? En outre, où dois-je effectuer glGetIntegerv et glGetFloatv pour obtenir les valeurs de matrice correctes pour viewport, projection et modelview? – Davido
Il est difficile à décrire, mais il doit être dans la boucle de rendu où vous commencez à rendre les choses. Ainsi, toutes les transformations de scène et de projection sont appliquées lorsque vous l'obtenez. –
Je l'ai édité pour ajouter le code de dessin –