Comment puis-je utiliser le vecteur de gravité pour transformer correctement la scène pour la réalité augmentée?

StackOverflow https://stackoverflow.com/questions/2541668

  •  23-09-2019
  •  | 
  •  

Question

Je suis en train figure comment obtenir un objet spécifié OpenGL à afficher correctement en fonction de l'orientation de l'appareil (ie. En fonction du vecteur de gravité de l'accéléromètre, et le cap de la boussole).

Le projet exemple GLGravity a un exemple qui est presque comme celui-ci (malgré ignorant cap), mais il a quelques problèmes. Par exemple, la théière saute 180deg comme l'angle de vision de l'appareil traverse l'horizon, et il tourne également spuriously si vous inclinez l'appareil de portrait en paysage. Ceci est très bien pour le cadre de cette application, car il montre juste à côté d'un objet et il n'a pas d'importance qu'il fait ces choses. Mais cela signifie que le code ne fonctionne pas lorsque vous essayez d'imiter l'affichage de la vie réelle d'un objet OpenGL selon l'orientation de l'appareil. Ce qui se passe est que cela fonctionne presque, mais la rotation de cap vous appliquez de la boussole se « corrompu » par les rotations supplémentaires parasites vus dans le projet exemple GLGravity.

Quelqu'un peut-il fournir le code exemple qui montre comment correctement ajuster l'orientation de l'appareil (ie. Vecteur de gravité), ou pour fixer l'exemple GLGravity de sorte qu'il ne comprend pas les changements de cap parasites?

//Clear matrix to be used to rotate from the current referential to one based on the gravity vector
bzero(matrix, sizeof(matrix));
matrix[3][3] = 1.0;

//Setup first matrix column as gravity vector
matrix[0][0] = accel[0] / length;
matrix[0][1] = accel[1] / length;
matrix[0][2] = accel[2] / length;

//Setup second matrix column as an arbitrary vector in the plane perpendicular to the gravity vector {Gx, Gy, Gz} defined by by the equation "Gx * x + Gy * y + Gz * z = 0" in which we arbitrarily set x=0 and y=1
matrix[1][0] = 0.0;
matrix[1][1] = 1.0;
matrix[1][2] = -accel[1] / accel[2];
length = sqrtf(matrix[1][0] * matrix[1][0] + matrix[1][1] * matrix[1][1] + matrix[1][2] * matrix[1][2]);
matrix[1][0] /= length;
matrix[1][1] /= length;
matrix[1][2] /= length;

//Setup third matrix column as the cross product of the first two
matrix[2][0] = matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1];
matrix[2][1] = matrix[1][0] * matrix[0][2] - matrix[1][2] * matrix[0][0];
matrix[2][2] = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];

//Finally load matrix
glMultMatrixf((GLfloat*)matrix);

Voici une clarification montrant comment obtenir l'élévation et l'inclinaison qui sont nécessaires pour la solution gluLookAt comme indiqué dans ma dernière réponse:

// elevation comes from z component (0 = facing horizon)
elevationRadians = asin(gravityVector.z / Vector3DMagnitude(gravityVector));

// tilt is how far screen is from vertical, looking along z axis
tiltRadians = atan2(-gravityVector.y, -gravityVector.x) - M_PI_2;

Faisant suite à la suggestion de Chris: Je ne sais pas si j'ai tout cela correct en raison de différentes conventions de l'ordre de ligne / colonne et tête ou CCW cw. Toutefois, le code suivant est ce que je suis venu avec:

Vector3D forward = Vector3DMake(0.0f, 0.0f, -1.0f);

// Multiply it by current rotation matrix to get teapot direction
Vector3D direction;     
direction.x = matrix[0][0] * forward.x + matrix[1][0] * forward.y + matrix[2][0] * forward.z;
direction.y = matrix[0][1] * forward.x + matrix[1][1] * forward.y + matrix[2][1] * forward.z;
direction.z = matrix[0][2] * forward.x + matrix[1][2] * forward.y + matrix[2][2] * forward.z;

heading = atan2(direction.z, direction.x) * 180 / M_PI;

// Use this heading to adjust the teapot direction back to keep it fixed
// Rotate about vertical axis (Y), as it is a heading adjustment
glRotatef(heading, 0.0, 1.0, 0.0);

Quand je lance ce code, le comportement de théière a apparemment « amélioré » par exemple. rubrique ne flips 180deg lorsque l'écran de l'appareil (en mode portrait) est incliné vers l'avant / arrière à travers la verticale. Cependant, il fait encore des sauts majeurs dans la position lorsque l'appareil (en mode paysage) est incliné vers l'avant / arrière. Donc, quelque chose qui ne va pas. Il suggère que le calcul de la position réelle ci-dessus est incorrect ...

Pas de solution correcte

Autres conseils

J'ai finalement trouvé une solution qui fonctionne. : -)

Je lâchai l'approche de la matrice de rotation, et au lieu gluLookAt adopté. Pour faire ce travail, vous devez connaître le dispositif « élévation » (angle de vision par rapport à l'horizon ie. 0 à l'horizon, +90 frais généraux), et le « tilt » de la caméra (dans quelle mesure l'appareil est à la verticale de son plan x / y à savoir . 0 lorsque vertical / portrait, +/- 90 quand / paysage horizontal), les deux étant obtenus à partir des composantes du vecteur de gravité de l'appareil.

Vector3D eye, scene, up;
CGFloat distanceFromScene = 0.8;
// Adjust eye position for elevation (y/z)
eye.x = 0;
eye.y = distanceFromScene * -sin(elevationRadians); // eye position goes down as elevation angle goes up
eye.z = distanceFromScene * cos(elevationRadians);  // z position is maximum when elevation is zero 
// Lookat point is origin
scene = Vector3DMake(0, 0, 0); // Scene is at origin
// Camera tilt - involves x/y plane only - arbitrary vector length
up.x = sin(tiltRadians);
up.y = cos(tiltRadians);
up.z = 0;

Ensuite, vous appliquez simplement la transformation gluLookAt, et aussi tourner la scène en fonction de la tête de l'appareil.

// Adjust view for device orientation
gluLookAt(eye.x, eye.y, eye.z, scene.x, scene.y, scene.z, up.x, up.y, up.z);
// Apply device heading to scene
glRotatef(currentHeadingDegrees, 0.0, 1.0, 0.0);

Essayez faire tourner l'objet en fonction de valeurs d'accélération iphone.

float angle = -atan2(accelX, accelY);

glPushMatrix();     
glTranslatef(centerPoint.x, centerPoint.y, 0);
glRotatef(angle, 0, 0, 1);
glTranslatef(-centerPoint.x, -centerPoint.y, 0);
glPopMatrix();

Où centerPoint est le point central de l'objet.

oo, agréable.

GLGravity semble obtenir tout droit, sauf pour le lacet. Voici ce que je voudrais essayer. Faites tout GLGravity fait, puis ceci:

Projet un vecteur dans la direction voulez la théière à face, en utilisant la boussole ou tout ce que vous le souhaitez. Puis, multiplier un vecteur « avant » par matrice de rotation actuelle de la théière, qui vous donnera la direction de la théière face. Aplatir les deux vecteurs par rapport au plan horizontal et de prendre l'angle entre eux.

Cet angle est votre lacet de correction. Ensuite, il suffit glRotatef par elle.

Si oui ou non la boussole 3GS est assez fiable et robuste pour que cela fonctionne est une autre chose. compas normaux ne fonctionnent pas lorsque le vecteur nord est perpendiculaire à leur visage. Mais je viens d'essayer l'application Maps sur 3GS de mon collègue et il semble faire face, alors peut-être ils ont obtenu une solution mécanique là-dedans. Savoir ce que l'appareil est en train de faire va aider à interpréter les résultats qu'il donne.

Assurez-vous de tester votre application au pôles nord et sud une fois que vous avez terminé. : -)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top