오늘 Apple Vision Pro Challenge 세션에 참가하여 공간 컴퓨팅 앱을 개발할 때 도움이 될 수 있는 내용들에 대해서 배웠습니다. 아쉽게도 일정 때문에 세션의 뒷 부분은 듣지 못하였습니다.
이전에 VisionOS를 개발하면서 겪었던 어려움과 관련한 키워드들이나, WWDC를 보면서 학습했던 내용들을 많이 다루어주셔서 반갑게 리마인드를 할 수 있었고, 보다 깊이감 있게 알려주셔서 기존에 몰랐던 내용들에 대해서도 알게 된 재밌는 경험이었습니다.
이번 포스팅에서는 오늘 세션을 듣고 나중에 다시 개발할 때 구현의 첫걸음을 쉽게 띌 수 있도록 간략하게 정리한 내용들입니다.
공간 컴퓨팅 환경에서 사용자의 입력은 아래와 같은 형태를 가집니다.
간접 입력이란 눈과 손을 이용하여 컴포넌트를 보면서 탭하는 상호작용을 말합니다. 보여지는 물체로부터 거리가 있고, 터치가 아닌 탭만 가능하며 손을 뻗어서 물체를 직접 만질 필요가 없기 때문에 간접이란 이름을 사용합니다.
반면, 직접 입력은 손가락을 이용한 상호작용입니다. 물체와 가까이서 직접 물체를 터치하는 입력을 말합니다.
공간 컴퓨팅 환경에서 트랙패드는 iPad를 사용할 때와 비슷하게 동작하지만, 조금 더 향상된 기능을 포함한다고 합니다.
키보드는 직접 혹은 간접 입력을 통해 동작 가능합니다. VisionOS를 사용할 때 실제 키보드를 사용하면 iPad와 비슷하게 동작하지만, 자동완성과 같은 assist 기능을 하는 창이 실제 키보드 위에 나타나게 됩니다.
사용자의 음성을 통해서는 Siri를 사용하거나 접근성 명령을 수행핤 수 있습니다.
마크업 모드는 손 또는 애플 펜슬을 통해 그림을 그릴 수 있습니다. (VisionOS에서는 PencilKit을 사용하는 것을 권장)
공간 컴퓨팅을 하기 위한 상호작용은 이와 같이 다양하므로, 기획할 때 사용자의 다양한 상호작용 input들을 고려하는 것이 중요합니다.
상호작용 입력에 대해서는 문서를 통해 자세히 살펴볼 수 있습니다.
앞서 알아본 다양한 입력들을 통해 사용자는 제스처를 만들어 앱과 상호작용 할 수 있습니다.
일반적으로 SwiftUI에서 사용하는 RotateGesture와 비슷하게, RotateGesture3D를 사용할 수 있습니다.
DragGesture를 사용하여 사용자가 pinch 후 드래그를 제스쳐를 하였을 때 처리할 수 있습니다.
이 때, Entity와 드래그 상호작용을 하기 위해서는 해당 엔티티는 Collision Component와 Input Target Component 컴포넌트를 가지고 있어야 합니다.
SpatialTapGesture를 통해서 사용자의 탭 제스처를 처리할 수 있습니다.
또한 이번 세션을 통해 상호작용 엔티티를 제한시키는 새로운 방법을 배우게 되었습니다.
.targetedToEntity(where: .has(MyComponent.self) // MyComponent를 가진 엔티티로 제한
ARKit을 사용해서 손을 추적하여 상호작용을 더욱 풍부하게 제공할 수도 있습니다.
Meet ARKit for Spatial Computing - WWDC23을 통해 더 자세히 알아볼 수 있습니다.
트랙패드를 활용하면 화면에 회색 점이 보이며 커서로 활용할 수 있습니다. 이 회색 점은 2D 공간 상에서만 존재하고, 3D 컨텐츠에서는 트랙패드를 활용할 수 없습니다. 즉 RealityView에서는 사용할 수 없습니다.
트랙패드를 사용하는 환경에서는 호버 이팩트와 멀티터치 제스처로 포커스를 강제화하는 것을 꼭 주의해야 한다고 합니다.
VisionOS에서 가상 키보드는 현재 윈도우 공간이 아니라 별도의 창으로 가상 키보드가 나타나게 됩니다. 눈으로 가상 키보드를 바라보면서 탭을 통해 입력을 할 수도 있고, 가까이 가져와서 직접 입력을 통해 텍스트를 입력할 수도 있습니다.
키보드와 입력 중인 텍스트필드가 멀리 있더라도 가상 키보드의 텍스트 미리보기 란을 통해서 현재 입력하고 있는 텍스트필드의 내용을 확인할 수 있다는 것도 이번 세션을 통해 알게 되었습니다.
여러 앱을 동시에 사용할 때, 앱 간 드래그&드롭을 사용할 수도 있습니다.
이를 위해 DropDelegate 또는 Transferable을 사용할 수 있습니다.
.onDrag modifier를 통해 드래그 시 로직을 처리할 수 있고, .onDrop modifier를 통해 설정한 delegate에서 performDrop(info: ) 메소드를 동작시킬 수 있습니다.
이번 세션 내내 강조를 하신 호버 이팩트입니다.
사용자는 현재 보고 있는 곳이 어디인지, 해당 컴포넌트가 상호작용이 가능한지 등을 알려는 니즈가 있습니다. 그러나 사용자가 보고 있는 위치는 개인정보이기 때문에 이를 트래킹할 수는 없습니다.
.hoverEffect() modifier를 통해 이팩트를 추가할 수 있고, contentShape() modifier를 통해 모양을 설정할 수 있습니다. 이 때, 주의할 점으로는 contentShape 모디파이어가 hoverEffect 모디파이어 보다 위에 있어야 합니다.
이렇게 호버 이팩트를 직접 설정할 수도 있지만, 시스템에서 기본적으로 제공하는 컴포넌트를 사용하는 것을 권장합니다. 다양한 표준 컴포넌트들을 사용하면 호버 이팩트는 물론 다음에 알아볼 접근성과 같은 다양한 속성들이 이미 구현되어 있기 때문에 보다 쉽게 개발할 수 있고 사용자들오 이들을 보장받을 수 있습니다.
HoverEffectComponent를 통해 엔티티에도 호버 이팩트를 추가할 수도 있습니다.
공간 컴퓨팅을 기획할 때에는 항상 호버 이팩트에 대해서 고려해야 하고, 상황에 맞는 시스템이 제공하는 컴포넌트를 활용하는 것이 중요합니다.
접근성은 개발할 때 쉽게 잊을 수 있는 기능 중 하나입니다. 하지만 우리가 개발할 서비스를 이용하는 사용자는 아주 다양하므로 접근성 기능을 통해 모든 사용자들에게 다가가는 것은 중요합니다.
VisionOS에서는 보이스 오버, 드웰 컨트롤, 스위치 컨트롤을 통해 접근성을 지원할 수 있습니다.
또한 개발할 때 가능한 모든 상황에서 대체 상호작용을 지원하는 것이 좋고, 최대한 표준 컴포넌트를 사용하여 기본적인 접근성을 지원 받는 것이 좋습니다.
접근성은 설정에서 쉽게 켜고 끌 수 있으니, VisionOS 앱 뿐만 아니라 기존 플랫폼에서도 접근성을 켜고 앱을 이용해보는 것도 좋은 경험이 될 것 같습니다.
접근성과 관련한 자세한 내용은 아래 세션들을 참고하시면 좋습니다.
Create accessible spatial experiences - WWDC23
Accessibility in SwiftUI - WWDC19
SwiftUI와 RealityKit을 통합하기 위해서 사용할 수 있는 것이 RealityView입니다.
RealityView는 Window, Volume, ImmersiveSpace 형태로 보여질 수 있으며 각각 2D 윈도우, 3D 컨텐츠를 담을 수 있는 윈도우, 사용자 주변을 모두 앱 컨텐츠로 둘러싸는 윈도우를 말합니다.
RealityView는 ECS 패러다임을 기반으로 하고 있으며 보다 자세한 내용은 Meet SwiftUI for spatial computing - WWDC23을 확인하실 수 있습니다.
RealityView를 이용하면
SwiftUI와 RealityKit의 좌표계에는 차이가 있습니다. (혼자 진행해봤던 프로젝트에서도 좌표계 때문에 많은 어려움이 있었습니다..)
좌표계에 차이가 있는 이유는 각 프레임워크에 자연스러운 좌표계를 적용하였기 때문인데요.
SwiftUI는 점 단위로 Y축이 위에서 아래로 진행이 되고 원점이 좌측 상단입니다. 앱 화면을 생각해보면 이렇게 구성이 된게 매우 자연스럽습니다.
반면 RealityKit은 미터 단위이며 Y축이 아래에서 위로, 원점이 중앙입니다. 이는 현실과 매치가 되기 때문에 자연스럽습니다.
이렇게 좌표계의 차이가 있기 때문에 각 좌표계들에 대한 이해를 하고 변환하는 API를 사용할 수 있어야 합니다.
이후에 더 좋은 세션들이 진행되었지만.. 일정이 있어서 이번 세션은 여기까지만 참석했었습니다 🥲