본 포스팅은 WWDC23의 Get started with building apps for spatial computing를 요약하여 정리한 것입니다.
Get started with building apps for spatial computing
공간컴퓨팅 앱을 구축하는 방법에 대해서 알아보자.
Fundamentals
공간컴퓨팅 앱을 구성하는 기본적인 요소 및 개념들에 대해 알아보자.
Shared Space
기본적으로 앱은 ‘Shared Space’라는 공간에서 실행된다. 이 공간에서 다양한 앱들이 실행되며, 이는 Mac에서 여러 앱이 동시에 실행되는 것과 같다고 볼 수 있다. 사람들은 Passthrough를 통해 주변과의 연결성을 유지한다.
Window
각 앱에는 하나 이상의 Window가 있다. 이는 일반적으로 macOS에서 사용하던 앱의 Window와 동일하게 크기조절, 흐름조절이 가능하다. 기존에 존재하던 2D 컨텐츠를 포함해 3D 컨텐츠도 보유할 수 있어 2D와 3D를 믹스 앤 매치할 수 있다.
Volume
사람들은 자신의 편의에 따라 앱의 크기를 줄이고 위치를 옮기는 등의 작업을 할 것이다. Volume은 이러한 상황에서 3D 컨텐츠의 범위를 제한하며 다른 앱들과 공간을 공유하도록 도와준다. Volume 또한 SwiftUI의 scene이며, RealityKit을 활용해 3D 컨텐츠를 표시한다.
Full Space
때때로 게임을 하거나 영화를 보는 등의 상황에서는 앱 자체의 몰입도(Level of Immersion)을 조절하고 싶을 수도 있을 것이다. 그럴 때 사용하는 것이 전용 Full Space이다. 이 공간에서는 앱의 Window, Volume, 3D 오브젝트만 표시된다. Full Space에서는 ARKit의 API도 사용할 수 있다. 예를 들면 시스템이 제공하는 기본 제스처 외에도 Skeletal Hand Tracking을 사용해 손의 구조를 제스처에 직접적으로 사용할수 있다. (Skeletal Hand Tracking : AR기술을 이용해 손의 구조를 실시간으로 감지 및 추적하여 컴퓨터와 상호작용하는데에 사용하는 것)
Passthrough, Fully Immersive
Passthrough를 이용해 콘텐츠를 현실 세계에 배치하고 사람들이 주변환경과도 여전히 상호작용하도록 한다. Fully Immersive를 사용할 수도 있다. 이는 가상 오브젝트의 조명을 커스터마이징하고 오디오 특성을 선택하는 등 앱을 창의적으로 만들 수 있다.
Windows, Volumes, Spaces
지금까지 살펴본거처럼 공간 컴퓨팅의 기본요소에는 Windows, Volumes, Spaces가 있다. 이들은 앱에 연속적으로 몰입할 수 있도록 여러가지 도구와 함께 동작한다.
눈이나 손을 통해 간단하게 앱과 상호작용할 수 있다. 예를 들면 버튼을 바라보고 손가락을 탭하는 동작으로 버튼을 작동시킬 수 있다. 심지어 3D 공간에 팔을 뻗어 직접 터치하는 것도 가능하다. 기존 아이폰에서 하는 것과 유사하게 탭, 롱프레스, 드래그, 로테이션, 줌 등의 제스처를 제공한다. 시스템이 이를 알아서 감지하고 이벤트를 생성한다. 제스처는 SwiftUI와 잘 통합된다. (스유자랑 한번더..) 또 RealityKit의 Entity와도 원활하게 작동한다. 이를 통해 사람들은 3D Scene 요소와 쉽게 상호작용할 수 있다. 키보드나 트랙패드같은 접근성 하드웨어와도 잘 동작한다. GameController 프레임워크는 무선게임 컨트롤러 지원도 한다.
SharePlay, Shared Context
AR경험을 함께하는 것은 매우 중요하다. SharePlay와 GroupActivities 프레임워크로 이를 가능하게 할 수 있다. 특정 모델을 공유하고 있으면 방향이나 애니메이션 처리를 공유하여 다른 위치에서도 쉽게 함께하는 경험을 느낄 수 있도록 도와준다.
시스템에 ‘Shared Context’라는 개념을 추가했다. 시스템은 이 컨텐스트를 관리해서 사람들이 동일한 콘텐츠를 경험할 수 있도록 돕는다. ‘Spatial Persona Templates’를 활용해 각 사용자의 경험을 커스텀할 수도 있다. 이에 관해 더 알고 싶다면 다른 세션인 ‘Design spatial SharePlay experiences’와 ‘Build spatial SharePlay experiences’를 감상해보자.
Privacy
Vision Pro는 주변환경의 모든 정보를 수집하고 이를 기반으로 동작한다. 따라서 프라이버시적인 문제가 발생할 수밖에 없는데, 애플은 이를 위해 많은 아키텍처를 배치했다고 한다. 앱이 센서로부터 데이터에 직접 접근을 하는 대신 시스템이 이를 간접적으로 수행한다. 그리고 시스템이 이벤트와 시각적 신호 등을 제공하는 로직인 것이다. 사용자가 특정 화면을 바라보면 호버 이펙트가 작동해 이 사실을 사용자가 알 수 있지만, 앱에 직접적으로 전달되지는 않는다.
많은 경우에는 시스템이 제공하는 동작만으로 앱과 상호작용할 수 있다. 더 민감한 정보에 접근해야하는 경우엔 시스템은 이에대한 허락을 구한다.
그 외 추가요소 및 정보
SwiftUI의 Preview 3D 지원 업데이트 완료했다고 한다. SwiftUI와의 결합성이 더 좋다는 것을 시사하는듯.
현재 시뮬레이터에서는 3가지 공간의 밤, 낮 환경을 제공해 다양한 공간에서의 경험을 테스트해볼 수 있다.
Instruments에 RealityKit Trace라는 새로운 템플릿이 추가되어 특정 동작들에 대해 많은 인사이트를 제공한다. 이를 통해 프레임병목을 관찰할 수 있고 더 나아가 제출된 총 Triangle의 수, RealityKit Entity 개수같은 중요한 지표를 확인할 수 있다. 이에 대한 자세한 정보는 ‘RealityKit Trace’ 세션을 참고하자.
Reality Composer Pro라는 새로운 개발자 도구도 개발되었다. 이를 통해 앱을 위한 3D 콘텐츠를 미리 확인하고 수정할 수 있다. 여기서 3D 에셋이 얼마나 기존의 것과 잘 어울리는지 확인할 수 있는 것이다. 새롭게 추가된 기능은 Particles이다.
- MaterialX라는Open Standard를 통해 메테리얼을 관리할 수 있다. 코드를 만지지 않고 노드 그래프를 통해 뷰포트를 빠르게 훑어본다. 더 많은 정보를 알아보고싶으면 ‘Explore materials in Reality Composer Pro’ 세션을 살펴보자.
- 생성된 혹은 불러온 3D 콘텐츠가 맘에 든다면 씬을 바로 기기에 전송해 테스트해볼 수도 있다. 이는 앱을 빌드할 필요가 없다. 더 알아보고 싶다면 ‘Meet Reality Composer Pro’ 세션을 살펴보자.
- Unity를 사용할수도 있다. 어떠한 플러그인도 없이 공간 컴퓨팅용 앱을 만들 수 있다. 기존 콘텐츠를 가져와 몰입형 경험을 불어넣을 수도 있다. Unity에 대해 알고싶다면 ‘Bring your Unity VR app to a fully immersive space’ 세션과 ‘Create immersive Unity apps’ 세션을 살펴보자.
Where to start
공간 컴퓨팅 앱을 만드는 방법은 두가지이다.
- 처음부터 공간용으로 제작하던가,
- 기존앱을 공간으로 불러와서 앱을 만드는 것이다.
공간 컴퓨팅 앱 만들기
먼저 공간용 앱을 한번 만들어보자.
xrOS의 App을 선택해 프로젝트를 시작한다. (확인해보진 않았지만 아마 VisionOS로 업데이트 되었을 것임)
Initial Scene Type을 Window와 Volume중에 선택한다. 이를 기반으로 초기코드가 자동으로 생성된다.
Immersive Scene Type을 통해 앱의 Immersive Space로 들어가는 Entry Point 설정이 가능하다. Default는 Shared Spcae에서 실행되는 것이다. 이를 Space로 설정하면 앱에 두번째 씬이 추가된다. 두번째 씬에서는 Full Space으로 실행하는 방법을 보여주는 예시 버튼이 표시된다.
더 궁금하면 ‘Develop your first immersive app’ 세션을 감상해라.
여러 샘플코드도 공개했다. Destination Video에서는 3D 영상과 Spatial Audio를 통합한 몰입형 재생환경을 구축하는 방법을 보여준다. Happy Beam은 Custom Hand Gesture를 포함해 친구들과 즐길 수 있는 몰입형 공간에서 이루어지는 게임이다. Hello World에서는 동일한 3D 지구본을 기반으로 다른 Visual Mode로 전환하는 것을 보여준다.
기존 앱을 공간으로 불러오기
기존 앱을 실행하는 것은 간단하다. iPhone보다는 iPad 형태의 앱이 좀더 적절하다. 화면 회전도 지원된다. 더 궁금하면 ‘Run your iPad and iPhone apps in the Shared Space’ 세션을 봐라. 시스템 기본동작, 기능적 차이, 시뮬레이터에서 테스트하는 방법 등에 대해 배울 수 있다.
그런데 기존에 존재하던 앱을 실행하는 것은 시작에 불과하다. Supported Destinations에 기기를 추가하고 컴파일하면 된다.
이렇게 리컴파일되면 좀 더 가상공간에 맞는 형태로 재생성된다.
How to build
완전 몰입형이란 주변 공간을 배제하고 마치 VR처럼 그래픽 공간속에 들어가는 것. 패스스루를 희미하게해 주변에 시선을 뺏기지 않고 콘텐츠에 집중하게해준다. (오른쪽)
Window, Volume, Space라는 다양한 요소가 있는데, 이는 사용자 경험에 무엇이 중요한지에 따라 조절될 수 있는 일종의 스펙트럼이라고 보면 된다. (More Presence ~ Deeper Immersion) 여러개의 앱을 동시에 배치하고 현실공간과 함께 사용하느냐, 앱이 공간 전체를 차지하도록해 몰입도를 높으니냐의 선택인 것이다. 가장 적절한 요소를 골라 배치하는 것이 공간 컴퓨팅 앱을 디자인할 때 가장 중요하게 고려해야할 요소이다.
Window 더 알아보기
다음으로 Window를 어떻게 활용할지 알아보자. Window는 앱의 시작점 역할을 한다.
- SwiftUI에서 사용가능
- 2D, 3D 지원 (2D 환경에서 3D 콘텐츠를 사용하는 것도 가능)
- 크기 조절 및 위치 이동 가능
import SwiftUI
import RealityKit
struct GlobeModule: View {
var body: some View {
Model3D(named: "Satellite")
}
}
Model3D 객체를 기반으로 모델을 View에 포함시켜 불러올 수 있음
다양한 제스처
기존에 사용하던
- TapGesture / SpatialTapGesture / DragGesture / MagnifyGesture / RotateGesture / LongPressGesture / onHover / onContinuousHover / keyboardShortcut / onKeyPress
외에도
- RotateGesture3D / targeted ToEntity / SpatialTapGesture / preferredHandAction / 3D properties on spatial gestures
가 추가되어 다양한 제스처를 활용할 수 있게 되었다.
import SwiftUI
import RealityKit
struct Globe: View {
@GestureState private var myState: State? = nil
var body: some View {
ZStack(alignment: bottom) {
Model3D (named: "Satellite")
.gesture(
DragGesture ()
.targetedToAnyEntity()
.updating($myState) { value, state, _ in
...
}
)
}
}
}
이렇게하면 드래그하여 오브젝트를 조작할 수 있다.
(완성본은 이런 느낌, 오른쪽에 존재하는 위성 오브젝트를 드래그하여 회전할 수 있다.)
Volume 더 알아보기
이제 Volume에 대해서 알아보자.
- Volume은 Window의 확장판이다.
- 3D 콘텐츠에 적합한 새로운 스타일의 Window라고도 볼 수 있다.
- 2D, 3D를 포함해 다양한 SwiftUI View를 포함할 수 있다.
- Volume은 Full Space에서도 활용될 수 있지만, Shared Space를 위해 만들어진 것이다. 따라서 3D 콘텐츠는 Volume의 Bounds 안에 있어야 한다.
@main
struct WorldApp: App {
var body: some Scene {
WindowGroup {
Model3D(named: "Globe")
}
.windowStyle(.volumetric)
•defaultSize(width: 0.6, height: 0.6, depth: 0.4, in: .meters)
}
}
WindowGroup을 만들고 windowStyle을 .volumetric으로 변경한다.
또한 width, height, depth로 구성된 defaultSize를 만들어야 한다. 이는 meter 혹은 points로 표현된다.
이렇게 생성된 Volume은 우리가 지정한 크기를 가지며, 해당 Volume이 어떤 앱에 포함되는지 파악할 수 있는 Application title bar, Volume의 위치를 변경할 수 있는 Window bar, 앱을 닫을 수 있는 Close button 등의 컨트롤 도구를 함께 제공한다.
RealityView
더 다양한 콘텐츠를 추가하기 위해서는 RealityView를 활용해야 한다.
- Scene에 추가 가능한 새로운 View이다. 몇개의 Entity든 SwiftUI 내에서 관리가능하도록 도와준다.
- SwiftUI에 쉽게 통합이 가능하다. SwiftUI에서 관리중인 State와 Entity의 프로퍼티를 연결한다. 이를 통해 앱 데이터 모델의 ‘source of truth’를 기반으로 3D 모델의 동작을 이끌어낼 수 있다.
- 좌표공간을 이동하는 것도 쉽다. RealityView에서 제공하는 변환 함수가 있기 때문이다.
- 또한 첨부(attachments)를 통해 SwiftUI의 요소를 RealityView 안에 배치할 수 있다.
RealityView {
...
} update: {
...
} attachments: {
...
}
RealityView를 초기화할 때는 3개의 클로저가 사용된다.
- make closure (최상단) : Entity를 만들어 RootEntity에 첨부한다.
- update closure : View의 State가 변경될때마다 호출된다.
- attachments closure : View를 Entity로 변경해주는 Tag Property와 함께 SwiftUI의 View를 추가하는 곳이다.
@State private var pinLocation: GlobeLocation?
RealityView {
...
} update: { content, attachments in
...
if let pin = attachments.entity(for: "pin") {
content.addChild(pin)
placePin(pin)
}
} attachments: {
if let pinLocation {
GlobePin(pinLocation: pinLocation)
.tag("pin")
}
}
}
attachments에는 특정 SwiftUI 요소에 이름을 붙여서 저장해둔다. 앱에 특정 업데이트가 발생하면 이를 불러오고 현 content에 추가, 위치를 조정해 최종 반영한다.
(완성본은 이런 느낌)
RealityKit을 사용하면 이렇게 다양한 기능을 사용할 수 있다. ‘Build spatial experiences with RealityKit’와 ‘Enhance your spatial computing app with RealityKit’ 세션을 보면 RealityKit에 대해 더 잘 알 수 있다.
Space 더 알아보기
이제 마지막으로 Space에 대해 알아보자.
- 앱이 전용 Full Space를 열면 시스템은 다른 모든 앱을 숨기고 그 앱만 보이게 한다.
- 주변 어디에든 앱의 Window, Volume, Contents를 배치할 수 있게 된다.
- ARKit, RealityKit 덕분에 주변환경과도 잘 상호작용할수도 있다. 예를 들어 방에 가상공을 던지면 이게 벽을 맞고 튕겨나와 바닥으로 다시 굴러가는 것을 볼 수 있는 것이다.
- Hand Tracking 기능을 활용해 Custom Gesture와 상호작용을 설정할수도 있다. 또, Contents를 사람의 손과 연관성있게 배치하는 것도 가능하다.
이 기능중 많은 것이 ARKit에서 온 것이다. 더 자세히 알고 싶으면 ‘Meet ARKit for spatial computing’을 확인해보자.
Immersion Style
각각 .mixed, .full 로 표현된다.
- mixed : Passthrough 위에 앱 콘텐츠를 레이어링하는 형태이다.
- full : Passthrough를 숨기고 콘텐츠만 보여준다.
- 이 두가지를 결합한 progrssive도 있다. 이는 초기에 Passthrough를 허용하지만 디바이스 상단에 있는 Digital Crown(다이얼)을 돌려서 full로 전환할수도 있다.
mixed 스타일 코드
@main
struct WorldApp: App {
var body: some Scene {
...
ImmersiveSpace (id: "solar-system"') {
SolarSystem ()
}
}
}
immersion style을 지정하지 않았다. default가 mixed이기 때문이다.
full 스타일 코드
@main
struct WorldApp: App {
@State private var selectedStyle: ImmersionStyle = .full
var body: some Scene {
...
ImmersiveSpace(id: "solar-system") {
SolarSystem ()
}
.immersionStyle(
selection: $selectedStyle,
in: .full
)
}
}
State를 하나 생성해 지정해주고 이를 기반으로 immersionStyle을 full로 지정해주면 된다.
더 나아가기
공간컴퓨팅 앱을 개발하는 방법에 대해 더 자세히 알아보고 싶으면 위의 세션들을 추가적으로 살펴보면 좋다.