이 가이드는 RayNeo X2 AR 애플리케이션 개발을 위한 초기 환경 설정부터 RayNeo X2 고유의 아키텍처를 설명하는 가이드예요. 순서대로 따라오시면 개발 환경 구축은 물론, 양안 디스플레이와 포커스 기반 UI 같은 AR 글래스 환경의 핵심을 이해하고, RayNeo X2에서 동작하는 간단한 안드로이드 애플리케이션을 개발할 수 있을 거예요. RayNeo X2 개발이 처음인 분도 쉽게 따라 할 수 있도록 단계별로 안내해 드릴게요. <br> > [!todo] 필수 선행 지식 > - [ ] Kotlin 기본 문법 > - [ ] Android, Activity 생명주기에 대한 이해 > - [ ] Android, Manifest에 메타데이터를 추가해 본 경험 <br><br> # 1. 개발 환경, 어떻게 구축해야 할까요? RayNeo X2는 독립적인 Android OS<span style="color:rgb(209, 209, 209)">(Android 12L 기반, API Level 32)</span> 위에서 동작해요. 따라서 개발자는 일반적인 Android 기기처럼 ADB(Android Debug Bridge)를 사용해서 개발한 APK를 설치하고 테스트할 수 있답니다. <br> > [!info] ADB(Android Debug Bridge)란? > ADB는 개발자가 PC에서 Android 기기를 제어하고, 만든 애플리케이션을 설치하거나, 기기 상태를 확인하거나, 애플리케이션 실행 중에 발생하는 로그를 볼 수 있게 해주는 만능 명령어 도구예요. <br><br> ## 1.1 ADB를 통해 외부 APK 설치하기 직접 개발한 애플리케이션을 설치하려면, 먼저 설치 권한을 부여해야 해요. 이를 위해서는 ADB 도구가 필수랍니다. ADB는 터미널 환경에서 사용되는 명령어 도구이기 때문에, 아래 가이드에 따라 사용 중인 OS에 맞는 패키지 관리 도구를 통해 설치를 진행해 주세요. <br> > [!info] 패키지 관리 도구란? > 패키지 관리 도구는 프로그램을 설치, 업데이트, 삭제하는 과정을 명령어 한 줄로 편리하게 처리해주는 도구예요. 예를 들어 macOS 사용자는 Homebrew를, Windows 사용자는 Chocolatey를 사용해서 ADB를 쉽게 설치할 수 있답니다. <br> 1. **macOS (Homebrew를 사용하여 설치)** - Homebrew가 설치되어 있지 않다면, 다음 명령어를 터미널에 입력하여 설치해 주세요. ```Bash /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ``` - Homebrew 설치가 완료되었다면, 다음 명령어로 ADB 툴을 설치할 수 있어요. ```Bash brew install android-platform-tools ``` 2. **Windows (Chocolatey를 사용하여 설치)** - Chocolatey가 설치되어 있지 않다면, 먼저 `PowerShell`을 관리자 권한으로 실행해 주세요. 그리고 다음 명령어를 PowerShell에 입력하여 Chocolatey를 설치합니다. ```Bash Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) ``` - Chocolatey 설치가 완료되었다면, 다음 명령어로 ADB 툴을 설치할 수 있어요. ```Bash choco install android-platform-tools ``` <br> ADB를 통해 RayNeo X2에 외부 APK 파일을 설치하는 순서는 다음과 같아요. RayNeo X2 기기를 컴퓨터에 연결한 후 순서대로 진행해주세요. 1. **기기 연결 확인** ```Bash adb devices ``` 컴퓨터와 RayNeo X2 기기가 ADB로 정상적으로 연결되었는지 확인해요. 이 명령어를 실행했을 때 기기의 고유 번호가 목록에 표시되어야 다음 단계로 진행할 수 있답니다. 2. **외부 APK 설치 권한 부여** ```bash adb shell settings put global mercury_install_allowed 1 ``` RayNeo X2는 기본적으로 보안을 위해 외부에서 들어오는 APK 설치를 제한하고 있어요. 이 명령어는 시스템 설정을 변경하여 외부 APK 설치를 명시적으로 허용하는 역할을 해요. 여기서 `1`은 '허용(True)'을 의미한답니다. 이 단계를 건너뛰면 APK 설치가 실패할 수 있으니 꼭 진행해 주세요. 3. **APK 설치** ```Bash adb install [apk 경로] ``` 앞서 권한을 부여한 후, 이 명령어를 사용하여 개발한 APK 파일을 RayNeo X2에 설치해요. `[apk 경로]` 부분은 컴퓨터에서 설치할 파일의 경로와 이름으로 바꿔주면 돼요. <br><br> ## 1.2 링 컨트롤러 없이도 애플리케이션을 실행하려면? <br> ![[RayNeo screenshot2.jpg|center|w70]] <br> RayNeo X2는 기본적으로 링 컨트롤러(Ring Controller)가 없으면 외부 애플리케이션 실행을 제한하는 정책을 시행하고 있어요. 그러나 개발 및 테스트 시 링 컨트롤러 없이 애플리케이션을 실행해야 할 경우, 다음의 설정을 통해 시스템 제한을 해제할 수 있어요. 시스템은 애플리케이션의 매니페스트(`AndroidManifest.xml`) 파일을 확인하여 해당 애플리케이션이 RayNeo 전용 애플리케이션인지 구분해요. 개발자는 메타데이터를 추가하여 애플리케이션을 RayNeo 전용으로 인식하도록 설정해야 합니다. <br><br> **✅ 메타데이터 선언** ```xml <application ... > <meta-data android:name="com.rayneo.mercury.app" android:value="true" /> </application> ``` 이 메타데이터를 `value="true"`로 설정하면, 시스템이 애플리케이션을 RayNeo 전용으로 인식하여 링 컨트롤러 없이도 정상적으로 실행해요. 이 설정을 빠뜨리면 시스템 프롬프트가 표시되며 애플리케이션 실행이 불가능해진답니다. <br><br> <br> # 2. RayNeo X2 아키텍처 이해하기 RayNeo X2 애플리케이션은 일반 Android 애플리케이션과 입력 방식, UI 상호작용, 디스플레이 레이아웃 등에서 큰 차이를 보여요. 성공적인 개발을 위해 이 차이점을 이해해야 해요. | 특징 | 일반적인 Android 애플리케이션 (스마트폰) | **RayNeo X2 애플리케이션** (AR 글래스) | | ----------- | ---------------------------- | ------------------------------- | | **입력 방식** | 손가락 제스처 (2D 터치) | 안경다리 터치 또는 링 (1차원 입력에 한정) | | **UI 상호작용** | 탭 기반 (바로 누름) | 포커스 → 탭 흐름 (초점 맞추고 선택) | | **디스플레이** | 단일 화면 | 양안 디스플레이 | | **확장성** | Google Play Services 자유롭게 사용 | Google Play Services 미지원, 기능 제한 | <br><br> ## 2.1 사용자를 위한 3D UI 동기화 (Binocular Synchronization) ![[rayneox2-binocular-synchronization.png|center|w70]] 큰 특징 중 하나는 디스플레이 구조예요. RayNeo X2는 왼쪽 눈과 오른쪽 눈 각각에 콘텐츠를 렌더링하는 양안(Binocular) 디스플레이 아키텍처를 사용해요. 만약 좌우 화면의 UI 위치나 크기가 어긋나면 뇌가 정보를 통합하지 못해 어지러움과 눈의 피로를 유발할 수 있어요. 따라서 개발자는 레이아웃 설계 시 좌우 화면이 완벽하게 동기화되도록 유의해야 합니다. <br> **✅ 입체감을 시뮬레이션하는 방법** 안정적인 3D 경험을 제공하려면 ARDK(Augmented Reality Development Kit)의 `make3DEffectForSide()` 메서드를 반드시 사용해야 해요. 이 메서드는 3D 인터페이스 요소를 양쪽 디스플레이에 정확히 동기화하며, 수평 차이(Horizontal Disparity)를 통해 사용자가 깊이를 느낄 수 있도록 입체감을 시뮬레이션한답니다. 이와 관련된 내용은 아래에서 더 자세히 설명할게요. <br> <br><br> ## 2.2 포커스 기반 상호작용 이해하기 일반 스마트폰처럼 화면의 특정 위치를 바로 탭 하는 방식은 RayNeo X2에서 작동하지 않아요. 이는 입력이 안경다리의 1차원 터치로 제한되기 때문이에요. 마치 키보드 방향키로만 화면을 조작해야 하는 상황과 비슷해요. <br> 이러한 제약을 극복하기 위해 RayNeo X2는 2단계 상호작용 프로세스를 따릅니다. 1. **포커스(Focus):** 사용자가 원하는 UI 요소에 먼저 초점을 맞춥니다. ![[RayNeo screenshot1.jpg|center|w70]] <div style="text-align:center"><span style="color:gray;">'Lens' 애플리케이션에 초점을 맞춘 상황</span></div> 2. **선택(Tap):** 그 후에 안경다리를 터치하여 선택을 확정합니다. <br> 개발자는 이 상호작용 모델을 구현하기 위해 ARDK의 핵심 컴포넌트인 `FocusHolder`, `FocusInfo`, `FixPosFocusTracker` 를 활용하여 동적으로 조정 가능한 포커스 커서를 설계해야 한답니다. <br><br><br> # 3. RayNeo ARDK 앞서 언급한 RayNeo ARDK는 RayNeo X2의 특수한 하드웨어와 1차원 입력의 한계를 해결하기 위해 특별히 개발된 소프트웨어 개발 키트예요. ARDK는 양안 디스플레이 제어, 포커스 관리, 그리고 터치 입력을 처리하는 데 필수적인 요소들로 구성되어 있어요. 다음은 ARDK의 주요 클래스와 그 핵심 역할을 기능별로 요약한 내용이에요. | 분류 | 핵심 역할 | 주요 클래스 | | ------------- | ------------------------------------------------------ | ---------------------------------------- | | **UI 동기화** | 좌우 디스플레이에 동일한 UI를 동시에 표시하여 시각적 불편함을 방지함 | `BindingPair`, `BaseMirrorActivity` | | **3D 시각 효과** | 좌우 시야에 차이를 주어 입체감(깊이)을 시뮬레이션함 | `make3DEffect` / `make3DEffectForSide` | | **입력 이벤트 해석** | 안경다리의 원시적인 1차원 터치를 다른 제스처로 변환함 | `TouchDispatcher`, `CommonTouchCallback` | | **제스처 흐름 처리** | 변환된 제스처를 Click, DoubleClick과 같은 이벤트(TempleAction)로 처리함 | `TempleAction`, `BaseTouchActivity` | | **포커스 기반 UI** | 사용자가 상호작용할 UI 요소의 포커스 상태를 추적하고 관리함 | `FocusHolder`, `FixPosFocusTracker` | <br><br> ## 3.1 SDK 라이브러리 통합 및 초기화 과정 개발을 시작하기 전, 프로젝트에 ARDK 라이브러리를 추가하고 올바르게 초기화하는 것이 중요해요. 여기서는 ARDK v.0.2.2를 기준으로 설명드릴게요. 안드로이드용 ARDK 파일은 [공식 홈페이지](https://leiniao-ibg.feishu.cn/wiki/QS9dw9l0FiaZbskS0KVcnZVUnEc) 에서 다운받을 수 있답니다. <br> **🛠️ SDK 통합 단계** 1. **라이브러리 추가** - 공식 홈페이지에서 다운받은 `.aar` 파일을 프로젝트의 `app/libs` 폴더로 옮겨주세요. - 이제 `build.gradle`파일에 아래와 같이 Local AAR과 핵심 Kotlin/AndroidX 의존성을 선언해야 해요. ```Plain // Local AAR implementation fileTree(dir: "libs", include: ["*.aar"]) // Core AndroidX + Kotlin implementation "androidx.core:core-ktx:1.8.0" implementation "androidx.appcompat:appcompat:1.3.0" implementation "androidx.fragment:fragment-ktx:1.5.3" implementation "androidx.activity:activity-ktx:1.3.0-alpha08" implementation "androidx.recyclerview:recyclerview:1.1.0" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1" ``` 2. **SDK 초기화** - ARDK의 모든 핵심 기능이 애플리케이션의 전체 생명주기 동안 문제없이 작동하려면, `Application class`에서 SDK를 초기화해야 해요. - 반드시 `super.onCreate()` 아래에 `MercurySDK.init(this)`를 호출해 주세요. ```Plain class MercuryDemoApplication : Application() { override fun onCreate() { super.onCreate() MercurySDK.init(this) } } ``` <br><br> <br> # 4. 핵심 기능 구현: 카메라 프리뷰 RayNeo X2는 양안 디스플레이의 특성상 하나의 화면을 좌우 양안 디스플레이에 동기화해야 해요. 이 가이드에서는 카메라 프리뷰 기능을 양안 디스플레이 구현 예시로 활용하여 AR 글래스의 특수 환경을 해결하는 방법을 알아보겠습니다. 이 기능 구현에는 호환성과 개발 편의성이 높은 Google Jetpack CameraX 라이브러리를 기본으로 사용할 거예요. <br> > [!warning] 참고: > AR 글래스의 실제 사용 환경에서는 사용자의 시야 자체가 카메라 프리뷰와 같으므로, 투명 디스플레이 위에 별도의 영상 표시가 필요하지 않을 수 있어요. 그러나 이 가이드에서는 ARDK의 ViewBinding/BinderPair 구조를 명확히 시연하기 위한 예시로 카메라 프리뷰 기능을 활용합니다. <br> > [!note] 코드를 보기 전 알아야 할 핵심 용어 > - **CameraX:** 안드로이드 카메라 기능을 개발자들이 쉽고 일관성 있게 사용할 수 있도록 도와주는 라이브러리예요. 복잡한 카메라 설정을 대신 처리해 준답니다. > - **SurfaceProvider:** `CameraX`가 카메라 영상을 화면에 '보여주기' 위해 영상을 전달하는 출력 통로를 제공하는 역할을 해요. 카메라 데이터를 실제로 보여줄 View화면 영역와 카메라를 연결해 주는 '중개자'라고 생각하면 쉬워요. > - **ViewBinding/BinderPair:** RayNeo ARDK에서 듀얼 디스플레이를 관리하기 위해 정의한 구조예요. 왼쪽 눈과 오른쪽 눈에 해당하는 화면 출력 영역(`viewFinder`)을 짝지어 관리해 준답니다. <br> ## 4.1 CameraX와 BinderPair 구조의 결합 CameraX와 ARDK를 결합하는 과정은 하나의 카메라 영상을 복제하여 두 화면에 전달하는 파이프라인을 구축하는 것과 같아요. <br> 1. **CameraX를 통한 영상 스트림 복제** 먼저, `startCamera()` 함수 내에서 CameraX가 물리적 카메라의 원본 영상 스트림을 확보해요. 이 원본 스트림을 기반으로, 실제 화면에 데이터를 공급할 두 개의 독립적인 `Preview` 객체(좌/우)를 생성합니다. 이 `Preview` 객체는 마치 카메라 영상을 복사하는 전용 TV 화면과 같아서, 이 객체를 우리가 원하는 디스플레이 영역(`viewFinder`)에 연결해 주기만 하면 영상이 나타나게 된답니다. 2. **ARDK의 ViewBinding/BinderPair 활용** RayNeo ARDK는 양안 디스플레이를 관리하기 위해 `ViewBinding/BinderPair`라는 구조를 제공하며, 이는 좌우 화면에 대응하는 두 개의 출력 대기 영역을 미리 정의해둡니다. - `mBindingPair.left.viewFinder`: 왼쪽 화면에 할당된 디스플레이 영역 - `mBindingPair.right.viewFinder`: 오른쪽 화면에 할당된 디스플레이 영역 3. **SurfaceProvider를 통한 연결** 마지막으로 CameraX로 생성한 두 `Preview` 객체의 `SurfaceProvider`를 ARDK의 각 `viewFinder`에 연결해 주면 됩니다. <br><br> 코드를 보시면, 우리는 `Preview` 객체를 생성(`Builder().build()`)함과 동시에 `also`를 사용하여 생성된 객체에 곧바로 `setSurfaceProvider` 설정을 적용하고 있어요. 이 코드가 좌우 화면 연결의 핵심이랍니다. 또한, `cameraProvider`를 통해 `bindToLifecycle()`을 호출하면 카메라 리소스를 액티비티의 생명주기에 자동으로 연결해요. 이로써 애플리케이션이 백그라운드로 전환될 때 카메라를 자동으로 해제하여 배터리 소모와 충돌을 방지하는 역할을 한답니다. <br> ```Kotlin val leftPreview = Preview.Builder().build().also { // SurfaceProvider를 통해 왼쪽 viewFinder와 CameraX의 Preview를 연결해요. it.setSurfaceProvider(mBindingPair.left.viewFinder.surfaceProvider) } val rightPreview = Preview.Builder().build().also { // 오른쪽도 마찬가지로 연결해요. it.setSurfaceProvider(mBindingPair.right.viewFinder.surfaceProvider) } // 액티비티의 생명주기에에 연결합니다. cameraProvider.bindToLifecycle( this, cameraSelector, leftPreview, rightPreview ) ``` <br> 이러한 `BinderPair` 구조를 통해 사용자에게 일관성 있고 몰입감 있는 양안 카메라 프리뷰를 제공할 수 있어요. <br> ![[RayNeo X2 구현.png]] <div style="text-align:center"><span style="color:gray;">양안에 카메라 프리뷰가 각각 연결된 모습 </span></div> <br><br> <br> 이 가이드에서는 RayNeo X2 AR 개발을 위한 필수 환경 설정과 핵심 아키텍처(양안 디스플레이, 포커스 기반 입력)를 다뤘어요. 다음 2부에서는 카메라 프리뷰를 기반으로 안경다리 제스처 감지를 다뤄볼 거예요. 또한, RayNeo X2 플랫폼의 한계점과 이를 극복하기 위한 전략에 대해서도 더 자세히 이야기해 드릴게요. <br><br><br><br>