¿Cómo utilizo el vector de gravedad para transformar correctamente escenario para la realidad aumentada?

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

  •  23-09-2019
  •  | 
  •  

Pregunta

Estoy intentando encontrar la manera de obtener una OpenGL especifica objeto a visualizar correctamente de acuerdo con la orientación del dispositivo (es decir. De acuerdo con el vector de gravedad desde el acelerómetro, y la partida de brújula).

El proyecto de ejemplo GLGravity tiene un ejemplo que es casi como este (a pesar de ignorar título), pero tiene algunos problemas. Por ejemplo, la tetera salta 180 grados ya que el dispositivo ángulo de visión cruza el horizonte, y que también gira espuria si se inclina el dispositivo de vertical a horizontal. Esto está bien para el contexto de esta aplicación, ya que sólo demuestra de un objeto y no importa que hace estas cosas. Pero significa que el código no funciona cuando se intenta emular la vida real de un objeto de visualización OpenGL según la orientación del dispositivo. Lo que pasa es que casi funciona, pero la rotación epígrafe se aplica a partir de la brújula se "dañado" por las rotaciones adicionales espurios observados en el proyecto de ejemplo GLGravity.

Puede cualquier persona proporcionar código de ejemplo que muestra cómo ajustar correctamente para la orientación del dispositivo (es decir. Vector de gravedad), o para fijar el ejemplo GLGravity de manera que no incluye cambios de rumbo espurias?

//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);

Esta es una aclaración que muestra cómo conseguir la elevación e inclinación que son necesarios para la solución de gluLookAt como se muestra en mi última respuesta:

// 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;

En seguimiento a la sugerencia de Chris: No estoy seguro si lo he entendido los correctos debido a las diferentes convenciones de la orden de fila / columna y en dirección CW o CCW. Sin embargo, el siguiente código es lo que ocurrió:

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);

Al ejecutar este código, el comportamiento de la tetera aparentemente ha "mejorado" por ejemplo. ya no partida voltea 180 grados cuando la pantalla del dispositivo (en la vista vertical) se cayó hacia delante / hacia atrás a través vertical. Sin embargo, todavía tiene grandes saltos en la partida cuando el dispositivo (en la vista horizontal) se lanzó hacia adelante / atrás. Así que algo no está bien. Se sugiere que el cálculo anterior del rumbo actual es incorrecta ...

No hay solución correcta

Otros consejos

Finalmente encontré una solución que funcione. : -)

Me dejó caer el enfoque de matriz de rotación, y en su lugar adoptó gluLookAt. Para hacer este trabajo lo que necesita saber el dispositivo de "elevación" (ángulo de visión con respecto al horizonte es decir. 0 en el horizonte, 90 por encima), y "inclinación" de la cámara (hasta qué punto el dispositivo es de la vertical de su plano x / y es decir, . 0 cuando / retrato vertical, +/- 90 cuando / paisaje horizontal), ambos de los cuales se obtienen a partir de los componentes de la gravedad dispositivo vectoriales.

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;

A continuación, sólo se aplica la transformación gluLookAt, y también rotar la escena de acuerdo con el título dispositivo.

// 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);

intente girar el objeto, dependiendo de los valores de aceleración de 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();

Donde centerPoint es el punto medio del objeto.

oo, agradable.

GLGravity parece tener todo bien excepto por el desvío. Esto es lo que lo intentaría. Hacer todo GLGravity hace, y luego esto:

Proyecto de un vector en la dirección que quiere la tetera a cara, usando la brújula o lo que usted así lo desea. Luego se multiplica un vector "hacia adelante", de matriz de rotación actual de la tetera, que le dará la dirección de la tetera es frente. Acoplar los dos vectores al plano horizontal y tomar el ángulo entre ellos.

Este ángulo de guiñada es su correctiva. A continuación, sólo glRotatef por ella.

Sea o no la brújula del 3GS es lo suficientemente fiable y robusto para que esto funcione es otra cosa. brújulas normales no funcionan cuando el vector norte es perpendicular a la cara. Pero he intentado la aplicación Mapas en 3GS de mi compañero de trabajo y parece que hacer frente, así que tal vez tienen una solución mecánica en ese país. Saber lo que el dispositivo está haciendo realmente ayuda interpretará los resultados que da.

Asegúrese de probar su aplicación en los polos norte y sur, una vez que haya terminado. : -)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top