Q&A: visionOS용 앱 빌드하기
2024년 01월 11일
지난 몇 달 동안 Apple 전문가들은 전 세계 Apple Vision Pro 개발자 랩에서 visionOS에 관한 많은 질문을 받았습니다. 개발자들이 가장 자주 묻는 질문과 이에 대한 답변을 확인해 보고 엔티티, 몰입형 공간, 충돌 모양 등 다양한 새로운 개념에 관한 인사이트를 학습해 보세요.
제스처를 사용하여 엔티티와 어떻게 상호작용할 수 있나요?
제스처 기반 엔티티 상호작용을 활성화하려면 세 가지 핵심 조건을 충족해야 합니다.
- 엔티티에 InputTargetComponent(영문)가 있어야 합니다. 그렇지 않으면 엔티티가 제스처 입력을 수신할 수 없습니다.
- 엔티티에 CollisionComponent(영문)가 있어야 합니다. 충돌 구성요소의 모양(영문)은 제스처가 실제로 적용되는 영역을 정의합니다. 그러므로 충돌 모양을 엔티티 상호작용에 맞게 지정하세요.
- 사용하는 제스처는 반드시 상호작용하려는 엔티티(또는 기타 엔티티)에 타겟팅해야 합니다. 예를 들면 다음과 같습니다.
private var tapGesture: some Gesture {
TapGesture()
.targetedToAnyEntity()
.onEnded { gestureValue in
let tappedEntity = gestureValue.entity
print(tappedEntity.name)
}
}
사용자가 대화형 엔티티를 바라볼 때 시스템이 기본 강조 효과를 트리거할 수 있도록 해당 엔티티에 HoverEffectComponent(영문)를 제공하는 것도 좋습니다.
윈도우 그룹과 몰입형 공간은 어떤 상황에서 사용하나요?
앱의 기능마다 어떤 장면(Scene) 유형을 적용할지 결정할 때 윈도우(Window), 볼륨(Volume), 몰입형 공간(Immersive Space)의 기술적인 차이를 고려하세요.
결정 시 고려해야 할 주요 기술적 차이점은 다음과 같습니다.
- 몰입형 공간이 열리면 사용자가 열어두었던 다른 앱의 윈도우와 볼륨이 숨겨집니다.
- 윈도우와 볼륨에서 경계를 넘어가는 콘텐츠는 잘립니다.
- 사용자는 윈도우와 볼륨의 배치를 완전히 제어합니다. 몰입형 공간에서는 앱이 콘텐츠의 배치를 완전히 제어합니다.
- 볼륨의 크기는 고정되어 있으며, 윈도우는 크기를 조정할 수 있습니다.
- ARKit은 앱에 활성화된 몰입형 공간이 있는 경우에만 해당 앱에 데이터를 전달합니다.
Hello World 샘플 코드(영문)를 자세히 알아보고 visionOS 내 각 장면 유형의 동작을 학습하세요.
장면에서 충돌 모양을 어떻게 시각화할 수 있나요?
Debug Visualizations(디버그 시각화) 메뉴에서 Collision Shapes(충돌 모양) 디버그 시각화를 사용하세요. 여러 다양한 디버그 시각화 기능도 이 메뉴에서 찾을 수 있습니다. 디버그 시각화에 대한 자세한 내용은 실행 중인 앱에서 디자인 문제 진단하기(영문)에서 확인하세요.
몰입형 공간에 SwiftUI 뷰를 배치할 수 있나요?
네. offset(x:y:)(영문) 및 offset(z:)(영문) 메서드를 사용하여 몰입형 공간에 SwiftUI 뷰를 배치할 수 있습니다. 이러한 오프셋은 미터(meter)가 아닌 포인트(point) 값을 지정해야 합니다. PhysicalMetric(영문)을 활용하여 미터를 포인트로 변환할 수 있습니다.
실제 뷰의 엔티티를 기준으로 SwiftUI 뷰를 배치하려면 어떻게 해야 하나요?
RealityView Attachment API를 사용하여 SwiftUI 뷰를 생성하고 ViewAttachmentEntity로 사용할 수 있도록 설정하세요. 이 엔티티는 다른 엔티티와 마찬가지로 위치, 방향, 크기를 조정할 수 있습니다.
RealityView { content, attachments in
// Fetch the attachment entity using the unique identifier.
let attachmentEntity = attachments.entity(for: "uniqueID")!
// Add the attachment entity as RealityView content.
content.add(attachmentEntity)
} attachments: {
// Declare a view that attaches to an entity.
Attachment(id: "uniqueID") {
Text("My Attachment")
}
}
프로그래밍 방식으로 윈도우를 배치할 수 있나요?
윈도우를 배치하는 API는 없지만, 사용 사례를 Apple에 알려주시면 큰 도움이 될 것 같습니다. 개선 사항 요청을 제출해 주세요. 이 주제와 관련된 자세한 내용은 윈도우의 위치와 크기 지정하기(영문)에서 확인하실 수 있습니다.
사용자가 무엇을 보고 있는지 알 수 있는 방법이 있나요?
개인정보 보호 및 사용자 환경설정에 대한 모범 사례 적용하기(영문)에 명시된 바와 같이 시스템은 카메라 및 센서를 통해 입력되는 정보를 앱에 직접 전달하지 않고 처리합니다. 눈의 움직임이나 시선 방향 정보를 정확하게 얻을 수 있는 방법은 없습니다. 대신 사용자가 상호작용할 수 있는 인터페이스 요소를 만들어서 시스템이 그러한 상호작용을 관리하도록 하세요. 눈의 움직임 정보를 직접적으로 추적하지 않으면서 이 방법으로 해결할 수 없는 사용 사례가 있다면 개선 사항 요청을 제출해 주세요.
visionOS에서 onHover 및 onContinuousHover 동작을 어떻게 호출하나요?
onHover(영문) 및 onContinuousHover(영문) 동작은 사용자가 손가락 또는 연결된 트랙패드의 포인터를 뷰에 올릴 때 호출됩니다.
앱에 자체 제작한 몰입형 환경 텍스처를 표시할 수 있나요?
앱에 ImmersiveSpace(영문)가 활성화되어 있는 경우 UnlitMaterial(영문)로 대형 구(Sphere)를 생성하고 내부를 바라보는 구조로 확장할 수 있습니다.
struct ImmersiveView: View {
var body: some View {
RealityView { content in
do {
// Create the sphere mesh.
let mesh = MeshResource.generateSphere(radius: 10)
// Create an UnlitMaterial.
var material = UnlitMaterial(applyPostProcessToneMap: false)
// Give the UnlitMaterial your equirectangular color texture.
let textureResource = try await TextureResource(named: "example")
material.color = .init(tint: .white, texture: .init(textureResource))
// Create the model.
let entity = ModelEntity(mesh: mesh, materials: [material])
// Scale the model so that it's mesh faces inward.
entity.scale.x *= -1
content.add(entity)
} catch {
// Handle the error.
}
}
}
}
기존의 스테레오 비디오를 어떻게 MV-HEVC로 변환할 수 있나요?
AVFoundation(영문)에 비디오를 MV-HEVC 형식으로 작성하는 API가 있습니다.
비디오를 MV-HEVC로 변환하는 방법은 다음과 같습니다.
-
왼쪽 및 오른쪽 뷰에 각각 AVAsset(영문)을 생성합니다.
-
AVOutputSettingsAssistant(영문)를 사용하여 MV-HEVC에 적합한 출력 설정을 확인합니다.
-
수평 시차(Horizontal Disparity) 조정 및 시야를 지정합니다(애셋별로 다름). 다음의 예시를 참고하세요.
var compressionProperties = outputSettings[AVVideoCompressionPropertiesKey] as! [String: Any]
// Specifies the parallax plane.
compressionProperties[kVTCompressionPropertyKey_HorizontalDisparityAdjustment as String] = horizontalDisparityAdjustment
// Specifies the horizontal FOV (90 degrees is chosen in this case.)
compressionProperties[kCMFormatDescriptionExtension_HorizontalFieldOfView as String] = horizontalFOV
-
AVAssetWriter(영문)의 입력으로 AVAssetWriterInputTaggedPixelBufferGroupAdaptor(영문)를 생성합니다.
-
왼쪽 및 오른쪽 비디오 트랙에 각각 AVAssetReader(영문)를 생성합니다.
-
왼쪽 및 오른쪽 트랙을 읽은 다음 태그가 지정된 픽셀 버퍼 그룹 어댑터에 일치하는 샘플을 추가합니다.
// Create a tagged buffer for each stereoView.
let taggedBuffers: [CMTaggedBuffer] = [
.init(tags: [.videoLayerID(0), .stereoView(.leftEye)], pixelBuffer: leftSample.imageBuffer!),
.init(tags: [.videoLayerID(1), .stereoView(.rightEye)], pixelBuffer: rightSample.imageBuffer!)
]
// Append the tagged buffers to the asset writer input adaptor.
let didAppend = adaptor.appendTaggedBuffers(taggedBuffers,
withPresentationTime: leftSample.presentationTimeStamp)
visionOS에서 RealityKit 장면에 어떻게 조명을 추가할 수 있나요?
다음의 방법으로 visionOS에서 RealityKit 장면에 조명을 추가할 수 있습니다.
-
실제 주변 환경에 따라 업데이트되는 자동 시스템 조명 환경을 사용합니다.
-
ImageBasedLightComponent로 자체 이미지에 기반한 조명을 추가합니다. 예시를 보려면 새 visionOS 앱을 만들고 Immersive Space Renderer(몰입형 공간 렌더러)에서 RealityKit을 선택하고 Immersive Space(몰입형 공간)에서 Full(전체)을 선택하세요.
CustomMaterial이 visionOS에서 지원되지 않는다고 들었습니다. 맞춤형 셰이딩을 사용하여 머티리얼을 표현할 수 있는 방법이 있나요?
Reality Composer Pro의 Shader Graph로 맞춤형 셰이딩을 사용하여 새로운 머티리얼을 표현할 수 있습니다. 이렇게 만들어진 머티리얼은 앱에서 ShaderGraphMaterial(영문)로 접근할 수 있습니다. 따라서 셰이더에 입력되는 내용을 코드에서 동적으로 변경할 수 있습니다.
Shader Graph에 관한 자세한 내용은 Reality Composer Pro가 제공하는 머티리얼 살펴보기(한국어 자막)에서 확인하세요.
기기의 위치를 기준으로 엔티티를 배치하려면 어떻게 해야 하나요?
ImmersiveSpace에서 queryDeviceAnchor(atTimestamp:)(영문) 메서드를 사용하여 디바이스를 배치할 수 있습니다.
visionOS용 앱 개발에 대해 자세히 알아보기
Q&A: visionOS를 위한 공간 디자인
View nowSpotlight on: Developing for visionOS
View nowSpotlight on: Developer tools for visionOS
View now해당 페이지에 포함된 샘플 코드는 Apple Sample Code License(영문)에 따라 제공되었습니다.