Я пытаюсь выяснить, как заставить указанный объект OpenGL отображаться корректно в соответствии с ориентацией устройства (т.е. в соответствии с вектором гравитации от акселерометра и курсом от компаса).
Пример проекта GLGravity имеет пример, который почти такой (несмотря на игнорирование заголовка), но он имеет некоторые глюки. Например, чайник подскочил на 180 градусов, когда угол обзора устройства пересекает горизонт, и он также резко поворачивается, если вы наклоняете устройство из портретного в горизонтальное положение. Это хорошо для контекста этого приложения, так как оно просто демонстрирует объект и не имеет значения, что оно делает эти вещи. Но это означает, что код просто не работает, когда вы пытаетесь эмулировать просмотр объекта OpenGL в реальной жизни в соответствии с ориентацией устройства. Что происходит, так это то, что он почти работает, но вращение курса, которое вы применяете с компаса, «искажается» ложными дополнительными поворотами, замеченными в примере проекта GLGravity.
Может ли кто-нибудь предоставить пример кода, который показывает, как правильно отрегулировать ориентацию устройства (например, вектор гравитации) или исправить пример GLGravity, чтобы он не включал ложные изменения курса?
//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);
Вот пояснение, показывающее, как получить угол возвышения и наклона, необходимые для решения gluLookAt, как показано в моем последнем ответе:
// 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;
Вслед за предложением Криса: я не уверен, правильно ли я все понял из-за различных соглашений порядка строк / столбцов и заголовка cw или ccw. Однако следующий код - это то, что я придумал:
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);
Когда я запускаю этот код, поведение чайника явно «улучшилось», например. курс больше не переворачивается на 180 градусов, когда экран устройства (в книжной ориентации) наклонен вперед / назад через вертикальное положение. Тем не менее, он все еще делает большие скачки в курсе, когда устройство (в горизонтальной ориентации) наклонено вперед / назад. Так что что-то не так. Это говорит о том, что приведенный выше расчет фактического курса неверен ...