Использование EasyAR в 3D-движке
Чтобы использовать EasyAR в 3D-движке, необходимо рендерить изображение камеры и виртуальные объекты. Рендеринг виртуальных объектов должен быть выровнен с изображением камеры. При рендеринге изображения камеры некоторые параметры на этапе формирования изображения и на этапе отображения могут не совпадать. Например, положение, ориентация, размер кадра, aspect ratio физической камеры и другие параметры могут отличаться от изображения на дисплее, и это нужно учитывать при рендеринге. Если необходимо подключить EasyAR к неподдерживаемому 3D-движку, обратите особое внимание на следующие детали.
Обрезка padding на границах изображения камеры
Обрезка, транспонирование и кодирование изображения требуют значительных вычислений. Чтобы снизить вычислительную нагрузку и latency, обычно используются относительно сырые форматы. Для удобства video encoding изображения, выдаваемые физической камерой, часто выравниваются по сеткам 8x8, 16x16, 32x32 или 64x64. Например, если на некоторых телефонах выбрать разрешение 1920x1080, выходное изображение может стать 1920x1088, потому что 1080 не кратно 64.

Это требует удаления лишних областей padding при рендеринге. Возможны разные подходы. Один из них - указать ширину при загрузке изображения в видеопамять, например в OpenGL можно использовать glPixelStorei(GL_PACK_ROW_LENGTH, ...). Другой - вручную вычислять UV-координаты во fragment shader и отсекать лишнюю часть при sampling изображения.
Рендеринг с учетом поворота экрана
На телефонах изображение, записываемое физической камерой, обычно фиксировано относительно корпуса устройства и не меняется вместе с ориентацией отображения экрана. Однако изменение ориентации корпуса телефона влияет на то, как мы определяем направления вверх, вниз, влево и вправо на изображении. При рендеринге текущая ориентация отображения экрана также влияет на направление отображаемого изображения.
Обычно при рендеринге нужно определить угол поворота изображения камеры относительно ориентации отображения экрана.
Если \(\theta_{screen}\) обозначает угол в радианах, на который изображение экрана повернуто по часовой стрелке относительно естественной ориентации экрана, \(\theta_{phycam}\) обозначает угол в радианах, на который изображение физической камеры должно быть повернуто по часовой стрелке для корректного отображения на экране в естественной ориентации, а \(\theta\) обозначает угол в радианах, на который изображение физической камеры должно быть повернуто по часовой стрелке для отображения на текущем экране.
Для задней камеры:
Например, на телефоне Android при использовании телефона в естественной ориентации \(\theta_{screen} = 0, \theta_{phycam} = \frac{\pi}{2}\), поэтому \(\theta = \frac{\pi}{2}\).
Для передней камеры, если после завершения поворота выполняется горизонтальное отражение:
Примечание
Когда изображение экрана поворачивается, \(\theta\) нужно немедленно пересчитать на первом кадре после поворота; иначе направление изображения на экране может кратковременно стать неправильным.
Рендеринг фона камеры и виртуальных объектов
При рендеринге виртуальных объектов на телефоне виртуальные объекты должны быть выровнены с изображением камеры. Для этого нужно разместить render camera и объекты в виртуальном пространстве, полностью соответствующем реальному пространству, и рендерить с тем же field of view и aspect ratio, что и у физической камеры. Perspective projection transforms, применяемые к изображению камеры и виртуальным объектам, почти полностью совпадают. Единственное отличие состоит в том, что большая часть perspective projection transform изображения камеры происходит внутри физической камеры, а perspective projection transform виртуальных объектов полностью является вычислительным процессом.
Далее используются соглашения OpenGL. При использовании других соглашений необходимо выполнить соответствующее отображение координатных осей. Предположим, оси системы координат камеры определены так: ось x направлена вправо, ось y направлена вверх, ось z направлена наружу из экрана. Оси clip coordinate system определены так: ось x направлена вправо, ось y направлена вверх, ось z направлена наружу из экрана, а ось w является виртуальной осью.
В этом случае матрица perspective projection transform, необходимая для рендеринга изображения камеры, выглядит следующим образом:
Здесь flip указывает, отражается ли изображение по горизонтали: значение 1 при отражении и 0 без отражения. \(\theta\) - угол поворота изображения по часовой стрелке в радианах. \(s_x\) и \(s_y\) - коэффициенты масштабирования для proportional scaling или proportional filling, они изменяются в зависимости от \(\theta\). Эта матрица transform сначала масштабирует изображение камеры, затем поворачивает его и в конце отражает. При рендеринге следует использовать прямоугольник, заполняющий экран. Например, в OpenGL вершины прямоугольника можно разместить в \((-1, -1, 0)\), \((1, -1, 0)\), \((1, 1, 0)\) и \((-1, 1, 0)\), задать UV-координаты в соответствующих четырех углах, а затем рендерить с этой матрицей perspective projection.
Матрица perspective projection, необходимая для рендеринга виртуальных объектов, выглядит следующим образом:
Здесь \(n\) и \(f\) - параметры near clipping и far clipping, обычно используемые в матрицах perspective projection для 3D-рендеринга. \(w\) и \(h\) - ширина и высота изображения камеры в пикселях. \(f_x\), \(f_y\), \(c_x\) и \(c_y\) - распространенные intrinsic parameters модели камеры, где \(f_x\) и \(f_y\) - фокусные расстояния в пикселях, а \(c_x\) и \(c_y\) - пиксельные координаты principal point. Эта projection matrix последовательно выполняет следующие transforms: perspective projection transform intrinsic parameters камеры (поскольку направления осей y и z в системе координат изображения OpenCV противоположны системе координат камеры OpenGL, выполняются два преобразования системы координат), transform из пиксельной системы координат изображения в прямоугольную систему координат изображения, transform near clipping и far clipping, а также perspective projection transform, используемый при рендеринге изображения камеры.
После упрощения получаем:
Из описанного процесса видно, что рендеринг обычно выполняется в два прохода: один проход рендерит изображение камеры, другой - виртуальные объекты, при этом виртуальные объекты накладываются поверх изображения камеры.
В некоторых 3D-движках матрица perspective projection задается параметрами вроде горизонтального field of view и aspect ratio. Если не учитывать поворот и отражение, а также игнорировать смещение principal point, эти параметры можно вычислить: горизонтальный field of view \(\alpha=2 arctan{\frac{w}{2 f_x}}\), aspect ratio \(r=\frac{w}{h}\).
Следует отметить, что в этом процессе не учитывается distortion камеры, потому что у большинства современных телефонов distortion камеры очень мала.