3D 엔진에서 EasyAR 사용
3D 엔진에서 EasyAR를 사용하려면 카메라 이미지와 가상 객체를 렌더링해야 합니다. 렌더링된 가상 객체는 카메라 이미지와 정렬되어야 합니다. 카메라 이미지를 렌더링할 때 이미지 생성 시점과 표시 시점의 일부 파라미터가 일치하지 않을 수 있습니다. 예를 들어 물리 카메라의 위치, 방향, frame size, aspect ratio 등의 파라미터가 디스플레이 이미지와 다를 수 있으므로 렌더링 시 이를 고려해야 합니다. EasyAR를 지원되지 않는 3D 엔진에 연결해야 하는 경우 다음 세부 사항에 특히 주의하십시오.
카메라 이미지 경계 padding의 crop
이미지 crop, 전치 및 encoding은 모두 큰 계산량을 필요로 합니다. 계산량과 latency를 줄이기 위해 일반적으로 비교적 raw한 형식을 사용합니다. video encoding을 편리하게 하기 위해 물리 카메라가 출력하는 이미지는 8x8, 16x16, 32x32, 64x64와 같은 grid에 정렬되는 경우가 많습니다. 예를 들어 일부 휴대폰에서 1920x1080 해상도를 선택하면, 1080이 64의 배수가 아니기 때문에 출력 이미지가 1920x1088이 될 수 있습니다.

따라서 렌더링할 때 이러한 여분의 padding 부분을 제거해야 합니다. 가능한 방법은 여러 가지입니다. 하나는 이미지를 비디오 메모리에 업로드할 때 width를 지정하는 것으로, 예를 들어 OpenGL에서는 glPixelStorei(GL_PACK_ROW_LENGTH, ...)를 사용할 수 있습니다. 또 다른 방법은 fragment shader에서 UV 좌표를 수동으로 계산하고 이미지에서 sampling할 때 초과 부분을 잘라내는 것입니다.
화면 회전 방향을 따라 렌더링
휴대폰에서 물리 카메라가 기록한 이미지는 일반적으로 기기 본체에 대해 고정되어 있으며 화면 표시 방향의 변화에 따라 변하지 않습니다. 그러나 휴대폰 본체 방향의 변화는 이미지의 위, 아래, 왼쪽, 오른쪽 방향을 정의하는 방식에 영향을 줍니다. 렌더링할 때 현재 화면 표시 방향도 표시되는 이미지의 방향에 영향을 줍니다.
일반적으로 렌더링 시 카메라 이미지가 화면 표시 방향에 대해 가지는 회전각을 결정해야 합니다.
$\theta_{screen}$이 화면 이미지가 화면의 자연 방향에 대해 시계 방향으로 회전한 라디안을 나타내고, $\theta_{phycam}$이 물리 카메라 이미지가 자연 방향의 화면에 올바르게 표시되기 위해 시계 방향으로 회전해야 하는 라디안을 나타내며, $\theta$가 물리 카메라 이미지가 현재 화면에 표시되기 위해 시계 방향으로 회전해야 하는 라디안을 나타낸다고 합니다.
후면 카메라의 경우:
예를 들어 Android 휴대폰에서 자연 방향으로 사용할 때 $\theta_{screen} = 0, \theta_{phycam} = \frac{\pi}{2}$이므로 $\theta = \frac{\pi}{2}$입니다.
전면 카메라의 경우, 회전이 완료된 후 좌우 반전을 수행하면:
참고
화면 이미지가 회전할 때는 회전이 발생한 뒤 첫 frame에서 즉시 $\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 matrix는 다음과 같습니다.
여기서 flip은 이미지가 좌우 반전되는지 여부를 나타냅니다. 반전 시 값은 1, 반전하지 않을 때 값은 0입니다. $\theta$는 이미지의 시계 방향 회전각이며 단위는 라디안입니다. $s_x$와 $s_y$는 proportional scaling 또는 proportional filling에 사용되는 scale factor이며 $\theta$에 따라 변합니다. 이 transform matrix는 먼저 카메라 이미지를 scaling하고, 그다음 회전한 뒤, 마지막으로 반전합니다. 렌더링 시에는 화면을 가득 채우는 사각형을 사용해야 합니다. 예를 들어 OpenGL에서는 사각형의 vertex를 \((-1, -1, 0)\), \((1, -1, 0)\), \((1, 1, 0)\), $(-1, 1, 0)$에 배치하고, UV 좌표를 대응하는 네 모서리에 설정한 뒤 이 perspective projection matrix로 렌더링할 수 있습니다.
가상 객체를 렌더링하는 데 필요한 perspective projection matrix는 다음과 같습니다.
여기서 $n$과 $f$는 일반적인 3D 렌더링 perspective projection matrix에서 사용하는 near clipping 및 far clipping 파라미터입니다. $w$와 $h$는 카메라 이미지의 pixel width와 height입니다. \(f_x\), \(f_y\), \(c_x\), $c_y$는 카메라 모델에서 일반적으로 사용하는 intrinsic parameter이며, $f_x$와 $f_y$는 pixel focal length이고 $c_x$와 $c_y$는 principal point의 pixel 위치입니다. 이 projection matrix는 다음 변환을 순서대로 수행합니다. 카메라 intrinsics의 perspective projection transform(OpenCV의 이미지 좌표계에서 y, z축 방향이 OpenGL 카메라 좌표계와 반대이므로 두 번의 좌표계 변환을 수행), 이미지 pixel 좌표계에서 이미지 사각형 좌표계로의 변환, near clipping 및 far clipping 변환, 카메라 이미지를 렌더링할 때의 perspective projection transform입니다.
정리하면 다음과 같습니다.
위 과정에서 알 수 있듯이 렌더링은 일반적으로 두 번에 나누어 수행해야 합니다. 한 번은 카메라 이미지를 렌더링하고, 한 번은 가상 객체를 렌더링하며, 가상 객체는 카메라 이미지 위에 겹쳐집니다.
일부 3D 엔진에서는 perspective projection matrix를 horizontal field of view, aspect ratio 등의 파라미터로 나타냅니다. 회전과 반전을 고려하지 않고 principal point offset을 무시하면 계산할 수 있으며, horizontal field of view는 \(\alpha=2 arctan{\frac{w}{2 f_x}}\), aspect ratio는 $r=\frac{w}{h}$입니다.
이 과정에서는 camera distortion을 고려하지 않았다는 점에 유의해야 합니다. 현재 대부분의 휴대폰 camera distortion은 매우 작기 때문입니다.