iOS용 Google Cardboard 빠른 시작

이 가이드에서는 iOS용 Cardboard SDK를 사용하여 나만의 가상 현실 (VR) 경험을 만드는 방법을 설명합니다.

Cardboard SDK를 사용하면 스마트폰을 VR 플랫폼으로 전환할 수 있습니다. 스마트폰은 입체 렌더링으로 3D 장면을 표시하고, 머리 움직임을 추적하여 반응하며, 사용자가 뷰어 버튼을 누를 때 이를 감지하여 앱과 상호작용할 수 있습니다.

먼저 Cardboard SDK의 핵심 기능을 보여주는 데모 게임인 HelloCardboard를 사용합니다. 게임에서 사용자는 가상 세계를 둘러보고 객체를 찾고 수집합니다. 이 도구는 다음을 수행하는 방법을 보여줍니다.

  • 개발 환경 설정
  • 데모 앱 다운로드 및 빌드
  • 매개변수를 저장하려면 Cardboard 뷰어의 QR 코드를 스캔하세요.
  • 사용자의 머리 움직임 추적
  • 각 눈에 맞는 왜곡을 설정하여 입체 영상 렌더링

개발 환경 설정

하드웨어 요구사항:

소프트웨어 요구사항:

데모 앱 다운로드 및 빌드

Cardboard SDK는 사전 컴파일된 프로토콜 버퍼 C++ 소스 파일을 사용하여 빌드됩니다. 소스 파일을 처음부터 빌드하는 단계는 여기에서 확인할 수 있습니다.

  1. 다음 명령어를 실행하여 GitHub에서 Cardboard SDK와 Hello Cardboard 데모 앱을 클론합니다.

    git clone https://github.com/googlevr/cardboard.git
  2. 저장소 루트에서 다음 명령어를 실행하여 Xcode 프로젝트에 프로토콜 버퍼 종속 항목을 설치합니다.

    pod install
  3. Xcode에서 Cardboard 작업공간 (Cardboard.xcworkspace)을 엽니다.

  4. 팀에서 앱에 서명할 수 있도록 앱의 번들 ID를 변경하세요.

  5. SDK > Build Stages(빌드 단계) > Link Binary With Library(바이너리를 라이브러리와 연결)로 이동합니다.

    1. libPods-sdk.a를 선택하고 '-' 버튼을 클릭하여 목록에서 삭제합니다.
    2. '+' 버튼을 클릭하고 선택하여 목록에 libProtobuf-C++.a를 추가합니다. XCFramework 사용을 제안하는 메시지가 나타나면 "Add Anyway(무시하고 추가)"를 클릭합니다.
  6. 실행을 클릭합니다.

QR 코드 스캔

기기 매개변수를 저장하려면 Cardboard 뷰어에서 QR 코드를 스캔합니다.

데모 사용해 보기

HelloCardboard에서 3D 공간에서 최단 거리 구를 찾아 수집합니다.

구를 찾아서 수집하는 방법:

  1. 떠다니는 구가 보일 때까지 머리를 아무 방향으로나 움직입니다.

  2. 구체를 똑바로 바라봅니다. 색상이 변경됩니다.

  3. Cardboard 뷰어 버튼을 눌러 구를 '수집'합니다.

기기 구성

사용자가 톱니바퀴 아이콘을 탭하여 Cardboard 뷰어를 전환하면 HelloCardboardOverlayView에서 didTapSwitchButton 메서드가 호출됩니다.

- (void)didTapSwitchButton:(id)sender {
  if ([self.delegate respondsToSelector:@selector(didTapBackButton)]) {
    [self.delegate didChangeViewerProfile];
  }
  self.settingsBackgroundView.hidden = YES;
}

그러면 CardboardQrCode_scanQrCodeAndSaveDeviceParams가 호출되어 뷰어의 QR 코드를 스캔하는 창이 열립니다. 사용자가 QR 코드를 스캔하면 기기의 왜곡 매개변수가 업데이트됩니다.

- (void)switchViewer {
  CardboardQrCode_scanQrCodeAndSaveDeviceParams();
}

- (void)didChangeViewerProfile {
  [self pauseCardboard];
  [self switchViewer];
  [self resumeCardboard];
}

머리 추적

헤드 추적기 만들기

헤드 추적기는 HelloCardboardViewControllerviewDidLoad 메서드에서 한 번 생성됩니다.

_cardboardHeadTracker = CardboardHeadTracker_create();

헤드 추적기 일시중지 및 다시 시작

HelloCardboardViewController 클래스의 pauseCardboardresumeCardboard 메서드는 각각 헤드 추적기를 일시중지했다가 다시 시작합니다. resumeCardboard는 다음 그리기 호출에서 기기 매개변수가 업데이트되도록 하는 _updateParams 플래그도 설정합니다.

- (void)pauseCardboard {
  self.paused = true;
  CardboardHeadTracker_pause(_cardboardHeadTracker);
}

- (void)resumeCardboard {
  // Parameters may have changed.
  _updateParams = YES;

  // Check for device parameters existence in app storage. If they're missing,
  // we must scan a Cardboard QR code and save the obtained parameters.
  uint8_t *buffer;
  int size;
  CardboardQrCode_getSavedDeviceParams(&buffer, &size);
  if (size == 0) {
    [self switchViewer];
  }
  CardboardQrCode_destroy(buffer);

  CardboardHeadTracker_resume(_cardboardHeadTracker);
  self.paused = false;
}

렌즈 왜곡

Cardboard가 새 QR 코드를 스캔할 때마다 다음 코드는 저장된 매개변수를 읽고 이를 사용하여 렌즈 왜곡 객체를 만듭니다. 그러면 렌더링된 콘텐츠에 적절한 렌즈 왜곡이 적용됩니다.

CardboardQrCode_getSavedDeviceParams(&encodedDeviceParams, &size);

// Create CardboardLensDistortion.
CardboardLensDistortion_destroy(_cardboardLensDistortion);
_cardboardLensDistortion =
    CardboardLensDistortion_create(encodedDeviceParams, size, width, height);

// Initialize HelloCardboardRenderer.
_renderer.reset(new cardboard::hello_cardboard::HelloCardboardRenderer(
      _cardboardLensDistortion, _cardboardHeadTracker, width, height));

렌더링

Cardboard에서 콘텐츠를 렌더링하는 작업은 다음과 같습니다.

  • 텍스처 만들기
  • 왼쪽 및 오른쪽 눈의 뷰 및 투영 행렬 가져오기
  • 렌더기 만들기 및 왜곡 메시 설정
  • 각 프레임 렌더링

텍스처 만들기

콘텐츠는 텍스처에 그려지고 왼쪽 및 오른쪽 눈의 섹션으로 분할됩니다. 이러한 섹션은 _leftEyeTexture_rightEyeTexture에서 각각 초기화됩니다. 샘플 앱은 양쪽 눈에 단일 텍스처를 사용하지만 각 눈에 별도의 텍스처를 만들 수도 있습니다.

// Generate texture to render left and right eyes.
glGenTextures(1, &_eyeTexture);
glBindTexture(GL_TEXTURE_2D, _eyeTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);

_leftEyeTexture.texture = _eyeTexture;
_leftEyeTexture.left_u = 0;
_leftEyeTexture.right_u = 0.5;
_leftEyeTexture.top_v = 1;
_leftEyeTexture.bottom_v = 0;

_rightEyeTexture.texture = _eyeTexture;
_rightEyeTexture.left_u = 0.5;
_rightEyeTexture.right_u = 1;
_rightEyeTexture.top_v = 1;
_rightEyeTexture.bottom_v = 0;
CheckGLError("Create Eye textures");

이러한 텍스처는 매개변수로 CardboardDistortionRenderer_renderEyeToDisplay에 전달됩니다.

왼쪽 및 오른쪽 눈에 대한 뷰 및 투영 행렬 가져오기

먼저 왼쪽 및 오른쪽 눈의 눈 행렬을 가져옵니다.

CardboardLensDistortion_getEyeFromHeadMatrix(_lensDistortion, kLeft, _eyeMatrices[kLeft]);
CardboardLensDistortion_getEyeFromHeadMatrix(_lensDistortion, kRight, _eyeMatrices[kRight]);
CardboardLensDistortion_getProjectionMatrix(_lensDistortion, kLeft, kZNear, kZFar,
                                            _projMatrices[kLeft]);
CardboardLensDistortion_getProjectionMatrix(_lensDistortion, kRight, kZNear, kZFar,
                                            _projMatrices[kRight]);

이제 각 눈의 왜곡 메시를 가져와서 왜곡 렌더기에 전달합니다.

CardboardLensDistortion_getDistortionMesh(_lensDistortion, kLeft, &leftMesh);
CardboardLensDistortion_getDistortionMesh(_lensDistortion, kRight, &rightMesh);

렌더기 만들기 및 올바른 왜곡 메시 설정

렌더기는 한 번만 초기화해야 합니다. 렌더기가 생성되면 CardboardLensDistortion_getDistortionMesh 함수에서 반환된 메시 값에 따라 왼쪽 눈과 오른쪽 눈의 새 왜곡 메시를 설정합니다.

_distortionRenderer = CardboardOpenGlEs2DistortionRenderer_create();
CardboardDistortionRenderer_setMesh(_distortionRenderer, &leftMesh, kLeft);
CardboardDistortionRenderer_setMesh(_distortionRenderer, &rightMesh, kRight);

콘텐츠 렌더링

CardboardHeadTracker_getPose에서 현재 헤드 방향을 가져옵니다.

CardboardHeadTracker_getPose(_headTracker, targetTime, position, orientation);
_headView =
    GLKMatrix4Multiply(GLKMatrix4MakeTranslation(position[0], position[1], position[2]),
                       GLKMatrix4MakeWithQuaternion(GLKQuaternionMakeWithArray(orientation)));

뷰 및 투영 행렬과 함께 현재 헤드 방향을 사용하여 뷰 투영 행렬을 작성하고 이를 사용하여 각 눈의 세계 콘텐츠를 렌더링합니다.

// Draw left eye.
glViewport(0, 0, _width / 2.0, _height);
glScissor(0, 0, _width / 2.0, _height);
DrawWorld(_leftEyeViewPose, GLKMatrix4MakeWithArray(_projMatrices[kLeft]));

// Draw right eye.
glViewport(_width / 2.0, 0, _width / 2.0, _height);
glScissor(_width / 2.0, 0, _width / 2.0, _height);
DrawWorld(_rightEyeViewPose, GLKMatrix4MakeWithArray(_projMatrices[kRight]));

CardboardDistortionRenderer_renderEyeToDisplay를 사용하여 콘텐츠에 왜곡 수정을 적용하고 콘텐츠를 화면에 렌더링합니다.

CardboardDistortionRenderer_renderEyeToDisplay(_distortionRenderer, renderTarget, /*x=*/0,
                                               /*y=*/0, _width, _height, &_leftEyeTexture,
                                               &_rightEyeTexture);