Table of Contents

Usar EasyAR en un motor 3D

Para usar EasyAR en un motor 3D, debe renderizar la imagen de la cámara y los objetos virtuales. Los objetos virtuales renderizados deben alinearse con la imagen de la cámara. Al renderizar la imagen de la cámara, algunos parámetros durante la generación de la imagen y durante la visualización pueden no coincidir. Por ejemplo, la posición, orientación, tamaño de frame, aspect ratio y otros parámetros de la cámara física pueden ser diferentes de la imagen del display, y esto debe considerarse durante el rendering. Si necesita integrar EasyAR en un motor 3D no compatible, preste especial atención a los siguientes detalles.

Recortar el padding de los bordes de la imagen de la cámara

El recorte, la transposición y la codificación de imágenes requieren bastante cálculo. Para reducir el cálculo y la latency, normalmente se usan formatos relativamente raw. Para facilitar el video encoding, las imágenes de salida de las cámaras físicas suelen alinearse con cuadrículas como 8x8, 16x16, 32x32 o 64x64. Por ejemplo, si se selecciona una resolución de 1920x1080 en algunos teléfonos, la imagen de salida puede convertirse en 1920x1088, porque 1080 no es múltiplo de 64.

image with padding

Esto exige eliminar esas partes de padding extra durante el rendering. Hay varios enfoques posibles. Uno es especificar el ancho al subir la imagen a la memoria de video; por ejemplo, en OpenGL se puede usar glPixelStorei(GL_PACK_ROW_LENGTH, ...). Otro es calcular manualmente las coordenadas UV en el fragment shader y truncar la parte excedente al hacer sampling de la imagen.

Renderizar siguiendo la rotación de pantalla

En teléfonos móviles, la imagen registrada por la cámara física normalmente está fija respecto al cuerpo del dispositivo y no cambia con la orientación de visualización de la pantalla. Sin embargo, los cambios de orientación del cuerpo del teléfono afectan a cómo definimos las direcciones arriba, abajo, izquierda y derecha de la imagen. Durante el rendering, la orientación actual de visualización de la pantalla también afecta a la dirección de la imagen mostrada.

Normalmente, durante el rendering, se debe determinar el ángulo de rotación de la imagen de la cámara respecto a la orientación de visualización de la pantalla.

Si usamos \(\theta_{screen}\) para representar los radianes de rotación horaria de la imagen de pantalla respecto a la orientación natural de la pantalla, \(\theta_{phycam}\) para representar los radianes de rotación horaria necesarios para que la imagen de la cámara física se muestre correctamente en una pantalla en orientación natural, y \(\theta\) para representar los radianes de rotación horaria necesarios para que la imagen de la cámara física se muestre en la pantalla actual.

Para la cámara trasera:

\[ \theta = \theta_{phycam} - \theta_{screen} \]

Por ejemplo, en un teléfono Android, cuando el teléfono se usa en la orientación natural, \(\theta_{screen} = 0, \theta_{phycam} = \frac{\pi}{2}\), por lo que \(\theta = \frac{\pi}{2}\).

Para la cámara frontal, si después de completar la rotación se realiza un volteo horizontal:

\[ \theta = \theta_{phycam} + \theta_{screen} \]
Nota

Cuando la imagen de pantalla rota, \(\theta\) debe recalcularse inmediatamente en el primer frame después de que ocurra la rotación; de lo contrario, la dirección de la imagen de pantalla puede ser incorrecta momentáneamente.

Rendering del fondo de cámara y de objetos virtuales

Al renderizar objetos virtuales en un teléfono móvil, los objetos virtuales deben alinearse con la imagen de la cámara. Esto requiere colocar tanto la cámara de rendering como los objetos en un espacio virtual que corresponda por completo al espacio real, y renderizar con el mismo field of view y aspect ratio que la cámara física. Las transformaciones de perspective projection aplicadas a la imagen de la cámara y a los objetos virtuales son casi idénticas. La única diferencia es que la mayor parte de la perspective projection transform de la imagen de la cámara ocurre dentro de la cámara física, mientras que la perspective projection transform de los objetos virtuales es completamente un proceso computacional.

Lo siguiente usa las convenciones de OpenGL. Si se usan otras convenciones, se requiere el mapeo correspondiente de ejes de coordenadas. Suponga que los ejes del sistema de coordenadas de la cámara se definen así: el eje x apunta a la derecha, el eje y apunta hacia arriba y el eje z apunta hacia fuera de la pantalla. Los ejes del sistema de coordenadas de clip se definen así: el eje x apunta a la derecha, el eje y apunta hacia arriba, el eje z apunta hacia fuera de la pantalla y el eje w es un eje virtual.

En este momento, la matriz de perspective projection transform necesaria para renderizar la imagen de la cámara es la siguiente:

\[ P_i=\left( \begin{array}{cccc} (-1)^{\text{flip}} & \phantom{0} & \phantom{0} & \phantom{0} \\ \phantom{0} & 1 & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & 1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right)\left( \begin{array}{cccc} \cos (-\theta ) & -\sin (-\theta ) & \phantom{0} & \phantom{0} \\ \sin (-\theta ) & \cos (-\theta ) & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & 1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right)\left( \begin{array}{cccc} s_x & \phantom{0} & \phantom{0} & \phantom{0} \\ \phantom{0} & s_y & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & 1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right) \]

Aquí, flip indica si la imagen se voltea horizontalmente. Su valor es 1 cuando se voltea y 0 cuando no se voltea. \(\theta\) es el ángulo de rotación horaria de la imagen, en radianes. \(s_x\) y \(s_y\) son factores de escala usados para proportional scaling o proportional filling, y varían con \(\theta\). Esta matriz de transformación primero escala la imagen de la cámara, luego la rota y finalmente la voltea. Durante el rendering se debe usar un rectángulo que llene la pantalla. Por ejemplo, en OpenGL, los vértices del rectángulo pueden colocarse en \((-1, -1, 0)\), \((1, -1, 0)\), \((1, 1, 0)\) y \((-1, 1, 0)\), con las coordenadas UV establecidas en las cuatro esquinas correspondientes, y luego renderizar con esta matriz de perspective projection.

La matriz de perspective projection necesaria para renderizar objetos virtuales es la siguiente:

\[ P=P_i\left( \begin{array}{cccc} 1 & \phantom{0} & \phantom{0} & \phantom{0} \\ \phantom{0} & 1 & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & -\frac{f+n}{f-n} & -\frac{2 f n}{f-n} \\ \phantom{0} & \phantom{0} & -1 & \phantom{0} \\ \end{array} \right)\left( \begin{array}{cccc} \frac{2}{w} & \phantom{0} & \phantom{0} & \phantom{0} \\ \phantom{0} & \frac{2}{h} & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & 1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right)\left( \begin{array}{cccc} 1 & \phantom{0} & \phantom{0} & \phantom{0} \\ \phantom{0} & -1 & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & -1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right)\left( \begin{array}{cccc} f_x & \phantom{0} & c_x & \phantom{0} \\ \phantom{0} & f_y & c_y & \phantom{0} \\ \phantom{0} & \phantom{0} & 1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right)\left( \begin{array}{cccc} 1 & \phantom{0} & \phantom{0} & \phantom{0} \\ \phantom{0} & -1 & \phantom{0} & \phantom{0} \\ \phantom{0} & \phantom{0} & -1 & \phantom{0} \\ \phantom{0} & \phantom{0} & \phantom{0} & 1 \\ \end{array} \right) \]

Aquí, \(n\) y \(f\) son los parámetros de near clipping y far clipping usados normalmente en matrices de perspective projection de rendering 3D. \(w\) y \(h\) son el ancho y alto en pixels de la imagen de la cámara. \(f_x\), \(f_y\), \(c_x\) y \(c_y\) son parámetros intrínsecos comunes del modelo de cámara, donde \(f_x\) y \(f_y\) son focal lengths en pixels, y \(c_x\) y \(c_y\) son las posiciones en pixels del principal point. Esta matriz de projection realiza las siguientes transformaciones en orden: la perspective projection transform de los intrinsics de cámara (como las direcciones de los ejes y y z del sistema de coordenadas de imagen en OpenCV son opuestas al sistema de coordenadas de cámara de OpenGL, se realizan dos transformaciones de sistema de coordenadas), la transformación del sistema de coordenadas de pixels de imagen al sistema de coordenadas de rectángulo de imagen, la transformación de near clipping y far clipping, y la perspective projection transform usada al renderizar la imagen de la cámara.

Después de simplificar, se obtiene:

\[ P=P_i\left( \begin{array}{cccc} \frac{2 f_x}{w} & \phantom{0} & 1-\frac{2 c_x}{w} & \phantom{0} \\ \phantom{0} & \frac{2 f_y}{h} & -1+\frac{2 c_y}{h} & \phantom{0} \\ \phantom{0} & \phantom{0} & -\frac{f+n}{f-n} & -\frac{2 f n}{f-n} \\ \phantom{0} & \phantom{0} & -1 & \phantom{0} \\ \end{array} \right) \]

Del proceso anterior se deduce que el rendering normalmente debe realizarse en dos pasadas: una para renderizar la imagen de la cámara y otra para renderizar los objetos virtuales, con los objetos virtuales superpuestos sobre la imagen de la cámara.

Algunos motores 3D representan la matriz de perspective projection con parámetros como horizontal field of view y aspect ratio. Si no se consideran la rotación ni el volteo y se ignora el desplazamiento del principal point, se pueden calcular, donde el horizontal field of view es \(\alpha=2 arctan{\frac{w}{2 f_x}}\) y el aspect ratio es \(r=\frac{w}{h}\).

Debe tenerse en cuenta que este proceso no considera la distorsión de cámara, porque actualmente la distorsión de cámara de la mayoría de teléfonos móviles es muy ligera.