Я использую Vuforia на Android для разработки дополненной реальности. Мы можем получить modelViewMatrix
, используя
Matrix44F modelViewMatrix_Vuforia = Tool.convertPose2GLMatrix(trackableResult.getPose());
Это прекрасно работает. Любая геометрия, умноженная на эту матрицу, а затем на матрицу проекции, отображается на экране, как и ожидалось, с (0,0,0) в центре отслеживаемой цели.
Но я также хочу одновременно рисовать геометрию относительно устройства пользователя, поэтому для этого мы можем разработать обратную модель ViewMatrix, используя:
Matrix44F inverseMV = SampleMath.Matrix44FInverse(invTranspMV);
Matrix44F invTranspMV = SampleMath.Matrix44FTranspose(modelViewMatrix_Vuforia);
modelViewMatrixInverse = invTranspMV.getData();
Это работает очень хорошо, например если я нарисую куб, используя эту матрицу, то, когда я наклоняю свой телефон вверх и вниз, куб также наклоняется вверх и вниз правильно, но когда я поворачиваюсь влево и вправо, возникает проблема. Левый поворот заставляет куб поворачиваться не в ту сторону, как будто я смотрю в правую сторону от него. Аналогично с поворотом направо. Что должно произойти, так это то, что куб должен казаться «прилипшим» к экрану, то есть, как бы я ни повернулся, я всегда должен видеть одно и то же лицо, «прилипшее» к экрану.
Я думаю, что проблема может быть связана с матрицей проекции Vuforia, и я собираюсь создать свою собственную матрицу проекции (используя руководство здесь), чтобы поэкспериментировать с различными настройками. Как это сообщение говорит, что это могло быть связано с внутренней калибровкой камеры конкретного устройства.
Я на правильном пути? Есть идеи, что может быть не так и как я могу это решить?
ОБНОВЛЕНИЕ
Я больше не думаю, что это матрица проекции (из-за экспериментов и комментария к ответу peedee ниже)
Посмотрев этот пост, я думаю, что добился некоторого прогресса. Сейчас я использую следующий код:
Matrix44F modelViewMatrix_Vuforia = Tool.convertPose2GLMatrix(trackableResult.getPose());
Matrix44F inverseMV = SampleMath.Matrix44FInverse(modelViewMatrix_Vuforia);
Matrix44F invTranspMV = SampleMath.Matrix44FTranspose(inverseMV);
modelViewMatrixInverse = invTranspMV.getData();
float [] position = {0, 0, 0, 1};
float [] lookAt = {0, 0, 1, 0};
float [] cam_position = new float[16];
float [] cam_lookat = new float[16];
Matrix.multiplyMV(cam_position, 0, modelViewMatrixInverse, 0, position, 0);
Matrix.multiplyMV(cam_lookat, 0, modelViewMatrixInverse, 0, lookAt, 0);
Log.v("QCV", "posx = " + cam_position[0] + ", posy = " + cam_position[1] + ", posz = " + cam_position[2]);
Log.v("QCV", "latx = " + cam_lookat[0] + ", laty = " + cam_lookat[1] + ", latz = " + cam_lookat[2]);
Это успешно возвращает положение камеры и нормаль к камере, когда вы перемещаете камеру вокруг цели. Думаю, я смогу использовать это для проецирования геометрии так, как я хочу. Обновится позже, если работает.
ОБНОВЛЕНИЕ2
Хорошо, некоторый прогресс достигнут. Сейчас я использую следующий код. Он делает то же самое, что и предыдущий блок кода, но использует класс Matrix вместо класса SampleMath.
float [] temp = new float[16];
temp = modelViewMatrix_Vuforia.getData();
Matrix.invertM(modelViewMatrixInverse, 0, temp, 0);
float [] position = {0, 0, 0, 1};
float [] lookAt = {0, 0, 1, 0};
float [] cam_position = new float[16];
float [] cam_lookat = new float[16];
Matrix.multiplyMV(cam_position, 0, modelViewMatrixInverse, 0, position, 0);
Matrix.multiplyMV(cam_lookat, 0, modelViewMatrixInverse, 0, lookAt, 0);
Log.v("QCV", "posx = " + cam_position[0] / kObjectScale + ", posy = " + cam_position[1] / kObjectScale + ", posz = " + cam_position[2] / kObjectScale);
Log.v("QCV", "latx = " + cam_lookat[0] + ", laty = " + cam_lookat[1] + ", latz = " + cam_lookat[2]);
Следующий фрагмент кода дает (почти) желаемый результат:
modelViewMatrix = modelViewMatrix_Vuforia.getData();
Matrix.translateM(modelViewMatrix, 0, 0, 0, kObjectScale);
Matrix.scaleM(modelViewMatrix, 0, kObjectScale, kObjectScale, kObjectScale);
line.setVerts(cam_position[0] / kObjectScale,
cam_position[1] / kObjectScale,
cam_position[2] / kObjectScale,
cam_position[0] / kObjectScale + 0.5f,
cam_position[1] / kObjectScale + 0.5f,
cam_position[2] / kObjectScale - 30);
Это определяет линию вдоль отрицательной оси z от вектора положения, равного положению камеры (которое рассчитывается исходя из положения фактического физического устройства). Поскольку вектор нормален, я сместил X / Y, чтобы нормаль можно было визуализировать.
По мере того, как вы перемещаете свое физическое устройство, нормальное состояние перемещается вместе с вами. Большой!
Однако, удерживая телефон в том же положении, но наклоняя телефон вперед / назад или поворачивая влево / вправо, линия не сохраняет свое центральное положение на дисплее камеры. Эффект, который я хочу, заключается в том, чтобы линия вращалась в мировом пространстве, когда я наклоняюсь / поворачиваюсь, чтобы в пространстве камеры / экрана линия выглядела нормально и занимала центральное место на физическом дисплее.
Примечание - вы можете спросить, почему я не использую что-то вроде:
line.setVerts(cam_position[0] / kObjectScale,
cam_position[1] / kObjectScale,
cam_position[2] / kObjectScale,
cam_position[0] / kObjectScale + cam_lookat[0] * 30,
cam_position[1] / kObjectScale + cam_lookat[1] * 30,
cam_position[2] / kObjectScale + cam_lookat[2] * 30);
Простой ответ: я пытался, но это не сработало! Все это достигается тем, что один конец линии остается там, где он есть, а другой конец указывает в направлении нормали экранного устройства. Что нам нужно, так это повернуть линию в мировом пространстве на основе углов, полученных из cam_lookat, чтобы линия фактически появлялась перед камерой в центре и перпендикулярно камере.
Следующим этапом является корректировка положения линии в мировом пространстве на основе углов, вычисленных из единичного вектора cam_lookat. Их можно использовать для обновления вершин линии, чтобы нормаль всегда появлялась в центре камеры независимо от того, как вы ориентируете телефон.
Я думаю, это правильный путь. Я обновлю еще раз, если это сработает!