스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
iOS용 Object Capture 만나보기
물체를 3D 모델로 바로 전환할 수 있도록 엔드투엔드 Object Capture 경험을 iOS 앱에서 직접 제공할 수 있는 방법을 알아보세요. 샘플 앱을 통해 완전 자동 Object Capture 스캔 흐름을 만들 수 있는 방법과 사용자가 모델의 최적 콘텐츠를 자동 캡처할 수 있도록 돕는 방법을 배워 보세요. LiDAR 데이터에 대해서도 논의하고 물체 스캔에 대한 우수 사례도 살펴봅니다.
리소스
관련 비디오
WWDC23
-
다운로드
♪ 부드러운 기계 힙합 음악 ♪ ♪ 안녕하세요, Object Capture 팀의 Lei라고 합니다 이번 세션에서는 제 동료 Mona와 함께 iOS용 Object Capture에 대해 소개해 드리겠습니다 시작하기 전에 Object Capture가 뭔지 이게 어떻게 작동하는지 우선 살펴보겠습니다 Object Capture는 최첨단 시각 기술을 이용해 다양한 각도에서 찍힌 일련의 이미지들로부터 실제와 같은 3D 모델을 만들어내는 API인데요 이미지들은 Mac으로 이동되어 이 API를 사용해 단 몇 분 만에 3D 모델로 재구성합니다 Mac에서의 API가 공개된 이후로 이 API를 이용한 수 많은 앱에서 고품질 3D 모델을 만들어내는 걸 목격했는데요 여러분들로부터 피드백도 많이 받았습니다 그리고 이제 더 큰 단계로 나아가서 이 API의 완전한 경험을 iOS에도 가져오게 됐죠! 이건 우리가 사용자 친화적인 환경에서 캡처도 할 수 있고 온디바이스 모델 재구성을 손 안에서 할 수 있다는 겁니다 iOS에서 이 작업 흐름이 어떻게 이루어지는지 샘플 앱도 제공하고요 작동 중인 샘플 앱을 한번 살펴보죠 우리는 샘플 앱을 사용해 이 아름다운 꽃병의 3D 모델을 아주 간편하게 만들 겁니다 먼저 샘플 앱을 열고 물체 쪽을 향하게 하세요 캡처를 시작하기 전에 바운딩 박스가 자동 생성되는 걸 보실 수 있을 겁니다 Object Capture가 제대로 된 이미지를 캡처할 수 있도록 물체 주변을 둥글게 돌아주세요 이미지가 더 필요한 영역에 관해서는 시각적 지침을 제공하고 최고 품질 샷을 캡처할 수 있도록 추가 피드백 메시지도 제공합니다 한 바퀴를 다 돌았으면 바닥을 캡처하기 위해 물체를 뒤집습니다 3면 스캔이 완성되면 재구성 단계로 진행될텐데 이제 iOS 기기에서 작동하게 됩니다 단 몇 분 만에 USDZ 모델 사용 준비가 완료되죠 개발자 문서의 일부로 이 앱의 소스 코드를 제공하고 있는데요 바로 다운로드하셔서 직접 해 보시길 바랍니다 이걸 여러분만의 애플리케이션을 만드는 시작점으로 사용하실 수도 있어요 새로운 샘플 앱에서 Object Capture의 데모를 살펴 보았으니 이제 올해 추가된 새 기능들을 살펴보도록 하죠 먼저 Object Capture의 개선 내용부터 소개하겠습니다 이제 LiDAR를 사용해 더 많은 물체 스캔을 지원한다는 거고요 다음으로는 Guided Capture 기능을 설명해 드릴게요 물체의 데이터 캡처를 단순화하는 기능이죠 그 다음 이 iOS에서 Object Capture의 흐름이 어떻게 이루어지는지 설명해 드리겠습니다 마지막으로는 모델 재구성 능력에 새롭게 추가된 내용들을 보여드릴 거고요 먼저 LiDAR를 통한 더 많은 물체 지원을 살펴보죠 고품질 3D 모델을 만들어내기 위해 좋은 특성을 갖춘 물체를 선정하는 것이 중요합니다 Object Capture 시스템은 충분한 텍스처 디테일을 갖춘 물체에 대해서 최적으로 작동하기는 하지만 올해 새롭게 추가 개선을 이루어 냈습니다 LiDAR Scanner 이용으로 로우 텍스처 물체의 재구성도 지원하게 된 건데요 이 의자를 예로 들어보죠 텍스처 디테일이 부족해서 Object Capture가 좋은 모델을 만들기가 굉장히 어려운데요 하지만 LiDAR가 있어 더 나은 품질로 재구성할 수 있습니다 캡처할 때 이 의자의 RGB 사진을 찍는데요 하지만 좌석과 등 부분에 텍스처가 없기 때문에 완성 모델 그대로 복구할 수는 없습니다 RGB 이미지 외에도 LiDAR는 포인트 클라우드 테이터를 수집합니다 그러면 범위와 밀도가 향상됨으로써 물체의 3D 모양의 포괄적인 재현이 가능해집니다 마지막으로 퓨전 클라우드 데이터에서 완성 3D 모델이 생성되죠 LiDAR 기반 시스템으로 품질이 개선된 다른 로우 텍스처 물체의 모델입니다
이제 로우 텍스처 물체를 지원하기는 하지만 이런 물체는 여전히 문제를 제시하는데요 빛을 반사하거나 투명한 물체 아주 얇은 구조를 가진 물체는 피하는 게 가장 좋죠 어떤 물체가 지원되는지 지금까지 살펴보았으니 더 쉬운 물체 스캔을 위해 Guided Capture를 사용하는 방식에 대해 자세히 살펴봅시다 Guided Capture는 이미지와 LiDAR 데이터를 자동으로 캡처하는데요 캡처 프로세스가 진행되는 동안 도움이 되는 피드백도 제공하죠 또한 물체를 뒤집어야 할지 지침도 제공합니다 사용자가 좋은 시야각을 직접 선택해 버튼을 누르게 하는 대신 우리는 데이터 캡처 경험을 자동화했는데요 물체 주변을 둥글게 돌면 우리 시스템은 아주 좋은 첨예도, 선명도, 노출을 갖춘 이미지 샷 선정을 자동으로 해주고 다양한 시야각에서 LiDAR 포인트를 수집합니다 물체의 모든 디테일을 캡처하기 위해서 가능한 한 많은 각도에서 사진을 찍으실 것을 권장합니다 물체의 어떤 영역이 적절한 이미지를 보여주는지 알려주는 캡처 다이얼도 제공되는데요 물체를 모든 각도에서 스캔함으로써 캡처 다이얼을 완전히 채워주시길 바랍니다 자동 캡처 외에도 캡처 과정에서 여러분을 도와줄 수 있는 실시간 피드백 또한 제공하죠 먼저, 주변 환경의 조명을 제대로 유지해 주세요 정확한 색상 재현이 가능하도록 말이죠 너무 어두울 경우에는 조명 상태를 조정하라는 알림을 받게 될 겁니다 빛 분산을 사용해 빛 반사를 최소화하거나 물체 표면에 하이라이트를 주실 것을 권장합니다 두 번째로, 물체 주변을 천천히, 부드럽게 움직이면서 흐릿한 이미지를 피할 수 있게 카메라가 흔들리지 않게 하세요 너무 빨리 움직이는 경우에는 자동 캡처가 중단되고 속도를 늦추라고 알려줍니다 세 번째, 카메라와 물체 사이의 적절한 거리를 유지해서 물체가 카메라 프레임에 적절하게 맞도록 해주세요 거리가 너무 멀거나 가까우면 텍스트 알림창이 나타납니다 마지막으로, 물체를 항상 프레임 내에 두세요 물체가 시야 범위 밖으로 나가게 되면 자동 캡처가 중단되고 화살표 심벌이 나타나 시야 방향을 조절하라고 알려줍니다
물체의 완성 3D 모델을 얻기 위해서 모든 측면을 캡처하는 것이 특히 중요합니다 물체 뒤집기도 여기에 도움이 될 수 있죠 하지만 뒤집기가 좋을지의 여부는 물체 속성에 달려 있습니다 물체가 고정되어 있다면 뒤집기는 좋은 아이디어이지만 물체가 변형 가능하다면 내버려두는 게 더 낫습니다 모양이 쉽게 변할 수 있으니까요 텍스처가 풍성한 물체는 뒤집어 주는 게 좋지만 대칭적이거나 반복적인 텍스처를 가진 물체는 뒤집기를 피하는 게 좋습니다 시스템에 오해를 불러일으킬 수 있거든요 텍스처가 없는 물체을 뒤집으면 Object Capture에게 어려울 수 있습니다 여러 구획을 봉합하려면 충분한 텍스처가 필요하니까요 우리의 API는 여기에 도움을 주려고 물체가 뒤집기에 충분한 텍스처를 가졌는지 물어보죠 물체를 뒤집기로 했다면 세 방향에서 스캔하는 것이 권장됩니다 모든 면의 이미지를 얻을 수 있도록 말이죠 그림자와 물체 표면 반사를 최소화하기 위해서 빛 분산을 사용하는 것도 가장 좋은 방법이고요 여러 스캔 과정에서 이미지가 겹치는 것도 중요합니다 스캔 과정에 있는 물체의 일부분이 이전 과정에서 캡처되어야 한다는 겁니다 물체를 제대로 뒤집는 방식의 시각적 지침도 제공되는데요 물체가 뒤집힐 수 없다면 다양한 각도에서 이미지를 얻기 위해 세 개의 다른 각도에서 캡처할 것을 제안합니다 거의 텍스처가 없는 물체는 이들이 두드러질 수 있는 텍스처가 있는 배경 앞에 두는 것이 좋고요 이 API는 iPhone 12 Pro iPad Pro 2021 이후의 모델에서 이용 가능합니다 여러분 기기의 Object Capture 지원 여부를 확인하기 위해 검증이 쉬운 API를 제공합니다 이제 제 동료 Mona가 Object Capture API에 대해 더 자세하게 알려드릴 겁니다 Lei, 고마워요! 지금까지 작동 중인 샘플 앱을 봤으니 이 앱을 만들기 위한 이 API의 활용 방식을 봅시다 데모에서 보셨다시피 Object Capture에는 이미지 캡처와 모델 재구성 두 단계가 있는데요 이미지 캡처부터 먼저 살펴보겠습니다 Image Capture API에는 두 부분이 있는데 바로 하나의 세션과 SwiftUI 뷰인데요 세션은 이미지 캡처가 진행되는 동안 상태 기계의 흐름을 관찰 및 통제하게 합니다 SwiftUI 뷰는 카메라 피드를 보여주고 카메라 피드가 보여주는 UI 요소를 세션 상태를 기반으로 자동 적응시키죠 우리의 SwiftUI에는 2D 텍스트나 버튼이 없습니다 그래서 여러분 앱의 모습을 커스터마이징하고 Object Capture를 기존의 앱에 더 쉽게 통합할 수 있죠 Object Capture 상태 기계를 더 자세히 볼게요 세션이 만들어지면 초기화 상태로 시작됩니다 그 다음 상태 진전을 위해 함수를 호출하게 되죠 세션은 전환을 하게 되는데 준비, 감지 캡처, 완료가 그 순서입니다 완료 상태가 되면 세션은 자동으로 완성 상태로 이동하죠 이때, 여러분은 안전하게 이걸 해체하고 온디바이스 재구성을 계속해 나갈 수 있습니다 이제 실제 사용 방식을 함께 살펴보죠 RealityKit과 SwiftUI를 임포팅하는 것으로 시작하는데요 그 다음 ObjectCaptureSession 인스턴스를 만듭니다 이게 참조형이다보니 세션이 완료될 때까지 이 세션을 유지 상태의 지상 실측 데이터 모델 내부에 저장할 것을 권장합니다 이렇게 하면 세션은 초기화 상태에서 시작됩니다 세션에게 캡처된 이미지를 어디에 저장할지 말해주는 디렉토리와 함께 start() 함수를 호출하여 계속 진행하게 됩니다 환경 설정 안에 체크 포인트 디렉토리를 제공해 추후 재구성 과정 속도를 빠르게 할 때도 사용 가능하죠 세션은 이 호출 이후 준비 상태로 이동합니다 다음은 ObjectCaptureView로 이 세션을 사용하는 방식입니다 이건 다른 SwiftUI 뷰처럼 사용하면 됩니다 다른 뷰의 바디 안에 배치해 우리가 방금 만든 지상 실측 세션에 보내고요 ObjectCaptureView는 항상 세션의 현재 상태에 일치하는 UI를 보여줍니다 여기 준비 상태를 보시면 레티클이 있는 카메라 피드를 보여줌으로써 캡처할 물체 선택을 가이드하죠 앱에는 상태 진전을 위해 물체 감지를 시작하라고 세션에 말하는 UI가 제공되어야 합니다 여기서 ObjectCaptureView 위에 '계속' 버튼이 스택되죠 버튼을 누르면 startDetecting() 함수를 호출해 바운딩 박스 감지 상태로 이동합니다 감지 상태의 뷰는 자동으로 변화하여 현재 감지된 물체 주변에 바운딩 박스를 보여줍니다 필요할 경우 바운딩 박스의 크기와 방향은 직접 조절할 수도 있습니다 샘플 앱에는 리셋 버튼도 제공하여 다른 물체를 선택하고자 하는 경우 물체 선택 과정을 재시작할 수 있고요 이건 세션을 준비 상태로 되돌립니다 준비에서 감지로 전환될 때와 유사하게 물체 선정이 마음에 들 경우 캡처를 시작하라고 세션에 말해주는 버튼을 제공해야 합니다 여기서 '캡처 시작' 버튼을 사용하는데요 이건 startCapturing() 함수를 호출합니다 세션은 이 호출 이후 캡처 상태로 이동하고요 세션은 캡처 상태에서 여러분이 물체 주변을 천천히 돌 때 자동으로 이미지를 찍습니다 뷰에는 포인트 클라우드와 캡처 다이얼이 나타나죠 우리가 어디에 있어야 물체의 충분한 이미지를 수집할 수 있는지와 어디를 더 캡처해야 할지를 보여주죠 캡처 다이얼이 완전히 채워지면 스캔 과정은 완료됩니다 세션은 캡처 다이얼이 완성되면 userCompletedScanPass 프로퍼티를 true로 설정합니다 여기서 우리 샘플 앱은 세션을 끝낼지 아니면 더 많은 이미지를 계속 캡처할지 선택권을 줍니다 각 옵션에 대하여 버튼을 할당하죠 최고의 모델 재구성을 위해 세 번의 스캔 과정을 완료할 것을 권장합니다 다음 스캔 과정으로 이동하는 법을 살펴봅시다 새 스캔 과정 시작은 두 가지 방식으로 가능한데요 물체 뒤집기 여부에 따라 방식은 달라집니다 물체를 뒤집으면 현재 과정에서 물체의 바닥과 같이 눈에 보이지 않는 면을 캡처하게 해줍니다 이를 위해 우리는 beginNewScanPassAfterFlip()을 호출하죠 이건 다시 준비 상태로 이동하는 겁니다 그 다음 새로운 방향에서 박스 선택을 해야 하죠 물체를 뒤집지 않을 거라면 대신 다양한 높이에서 이미지를 더 찍을 수 있습니다 이를 위해 우리는 beginNewScanPass()를 호출하고요 이건 캡처 다이얼을 리셋하지만 바운딩 박스가 바뀌지 않아 세션이 캡처 상태를 유지합니다 모든 과정이 완료되면 샘플 앱은 '완료' 버튼을 제공합니다 이 버튼은 finish() 함수를 호출하죠 이 함수는 세션에게 이미지 캡처를 끝냈다고 말해서 완료 과정을 시작할 수 있게 됩니다 완료 상태에 있으면 세션은 모든 데이터가 저장되기를 기다립니다 세션은 일단 완료되면 자동으로 완성 상태로 넘어가죠 그럼 이걸 해체하고 온디바이스 재구성을 시작할 수 있습니다 복구 불가한 오류가 발생할 경우도 있는데요 이미지 디렉토리가 갑자기 이용 불가할 때처럼요 그럼 세션은 실패 상태로 전환합니다 이렇게 되면 새로운 세션이 만들어져야 하죠 마지막으로, 처음에 배치되거나 마지막에 뒤집히기 때문에 물체의 어느 부분이 스캔됐는지 미리 보여주기 위해 포인트 클라우드를 보여줄 수도 있습니다 ObjectCapturePointCloudView를 ObjectCaptureView로 바꾸면 가능한데요 그럼 캡처 세션이 중단되고 포인트 클라우드와 상호작용함으로써 모든 각도에서 미리 보기가 가능합니다 여기서 우리는 이 뷰를 텍스트 및 버튼과 함께 보여주고 있지만 여러분은 포인트 클라우드 풀 스크린으로 보여줄 수 있죠 물체의 이미지를 캡처해 보았으니 이제 3D 모델이 만들어지는 방식을 살펴봅시다 올해부터 iOS에서도 재구성 API 작동이 가능합니다 그래서 동일한 기기에서 이미지 캡처와 재구성이 둘 다 가능하죠 비동기 재구성 API를 어떻게 사용하는지 다시 한번 살펴보세요 iOS에서도 macOS에서와 똑같이 작동합니다 먼저 task 제어자를 우리가 만든 뷰에 추가하는 것으로 시작하죠 우리는 task 제어자에서 사진 측량 세션을 만들고 이걸 이미지에 가리킬 수 있습니다 재구성 과정 속도를 높이기 위해서 이미지 캡처 동안 사용한 것과 동일한 체크 포인트 디렉토리를 제공할 수도 있고요 그 다음 modelFile을 요청하는 process() 함수를 호출합니다 마지막으로 반복되는 메시지 스트림을 기다리고 메시지 스트림이 도착하면 출력 메시지를 처리합니다 자세한 내용은 다음 WWDC21 세션을 확인하세요 모바일 기기에서 모델 생성 및 보여주기를 최적화하기 위해 iOS에서는 축소된 디테일 레벨만 제공합니다 재구성된 모델에는 분산, 앰비언트 어클루전 노멀 텍스처 맵을 제공하고 모두 모바일 디스플레이용입니다 다른 디테일 레벨로 모델을 생성하고 싶다면 이미지를 Mac으로 보내 재구성할 수 있습니다 올해 Mac 재구성에서도 우리가 이미지에 저장한 LiDAR 데이터를 이용하게 됐는데요 새로운 Object Capture 세션에서는 이 흐름도 지원합니다 그 방식을 살펴봅시다 기본적으로 Object Capture 세션은 iOS 기기의 재구성 한도에 도달했을 때 이미지 캡처를 중단합니다 macOS 재구성의 경우 온디바이스 재구성이 사용할 수 있는 것보다 더 많은 이미지를 찍을 수 있습니다 그렇게 하기 위해서는 세션 환경 설정 내에 있는 isOverCaptureEnabled를 true로 설정해야 합니다 이 추가 샷들은 온디바이스 재구성에서는 사용되지 않지만 '이미지' 폴더에는 저장됩니다 Mac에서 이미지를 재구성하기 위해 코드를 쓸 필요도 없죠 Object Capture는 Reality Composer Pro라는 새로운 macOS 앱에 통합됩니다 이미지를 앱으로 임포팅하여 디테일 레벨을 선택하면 모델을 얻을 수 있죠 이 앱에 대해 더 알고 싶으시다면 Reality Composer Pro에 대한 세션을 시청해 보세요 이제 새로운 iOS API로 3D 모델을 만드는 방식을 함께 살펴 보았으니 많은 요청이 있었던 재구성 개선 사항 몇 가지를 빠르게 훑어보도록 하겠습니다 우리는 Mac에서 모델 품질과 재구성 속도를 개선했습니다 진행 % 외에도 예상 재구성 시간도 제공하고요 두 가지 추가 사항을 좀더 살펴보려고 하는데요 '포즈 출력'과 '커스텀 디테일 레벨'입니다 이제 각 이미지에 대해 고품질 포즈를 요청할 수 있습니다 컴퓨터 비전 알고리즘을 기반으로 해당 이미지에 대한 카메라의 예상 위치와 방향이 각 포즈에 포함되죠 그 포즈를 얻기 위해 poses 요청을 process() 함수 호출에 추가합니다 그 다음 출력 메시지 스트림에 포즈가 도착하면 poses 출력을 처리하죠 포즈는 모델이 생성되기 전 재구성 과정에서 일찍 반환될 겁니다 올해 우리는 macOS에 대해 새 커스텀 레벨 디테일을 추가했고 여러분은 재구성된 모델에 대해 모든 통제를 하실 수가 있게 됩니다 이전에는 디테일 레벨이 축소, 중간, 완전 개요 중에서 선택할 수 있었는데요 커스텀 디테일 레벨에서는 메쉬 데시메이션의 양과 텍스처 맵 해상도, 포맷 그리고 어떤 텍스터 맵을 포함할지를 직접 통제할 수가 있습니다 iOS용 Object Capture에 대한 정리는 여기까지입니다 Object Capture는 이제 LiDAR 지원으로 더 많은 물체를 스캔할 수 있습니다 iOS 기기만으로 모델을 캡처하고 재구성하고 볼 수 있는 방식을 이렇게 보여드렸는데요 iOS용 Object Capture는 이커머스, 디자인 교육, 게임 분야 등 다양한 애플리케이션에 대해 새로운 작업 흐름을 가능하게 할 겁니다 Object Capture를 여러분의 앱에 어떻게 통합하실지 정말 기대되네요 시청해 주셔서 감사합니다 ♪
-
-
10:03 - Instantiating ObjectCaptureSession
import RealityKit import SwiftUI var session = ObjectCaptureSession()
-
10:25 - Starting the session
var configuration = ObjectCaptureSession.Configuration() configuration.checkpointDirectory = getDocumentsDir().appendingPathComponent("Snapshots/") session.start(imagesDirectory: getDocumentsDir().appendingPathComponent("Images/"), configuration: configuration)
-
10:50 - Creating ObjectCaptureView
import RealityKit import SwiftUI struct CapturePrimaryView: View { var body: some View { ZStack { ObjectCaptureView(session: session) } } }
-
11:20 - Transition to detecting state
var body: some View { ZStack { ObjectCaptureView(session: session) if case .ready = session.state { CreateButton(label: "Continue") { session.startDetecting() } } } }
-
11:36 - Showing ObjectCaptureView
var body: some View { ZStack { ObjectCaptureView(session: session) } }
-
12:04 - Transition to capturing state
var body: some View { ZStack { ObjectCaptureView(session: session) if case .ready = session.state { CreateButton(label: "Continue") { session.startDetecting() } } else if case .detecting = session.state { CreateButton(label: "Start Capture") { session.startCapturing() } } } }
-
12:27 - Showing ObjectCaptureView
var body: some View { ZStack { ObjectCaptureView(session: session) } }
-
12:50 - Completed scan pass
var body: some View { if session.userCompletedScanPass { VStack { } } else { ZStack { ObjectCaptureView(session: session) } } }
-
14:03 - Transition to finishing state
var body: some View { if session.userCompletedScanPass { VStack { CreateButton(label: "Finish") { session.finish() } } } else { ZStack { ObjectCaptureView(session: session) } } }
-
15:00 - Point cloud view
var body: some View { if session.userCompletedScanPass { VStack { ObjectCapturePointCloudView(session: session) CreateButton(label: "Finish") { session.finish() } } } else { ZStack { ObjectCaptureView(session: session) } } }
-
15:50 - Reconstruction API
var body: some View { ReconstructionProgressView() .task { var configuration = PhotogrammetrySession.Configuration() configuration.checkpointDirectory = getDocumentsDir() .appendingPathComponent("Snapshots/") let session = try PhotogrammetrySession( input: getDocumentsDir().appendingPathComponent("Images/"), configuration: configuration) try session.process(requests: [ .modelFile(url: getDocumentsDir().appendingPathComponent("model.usdz")) ]) for try await output in session.outputs { switch output { case .processingComplete: handleComplete() // Handle other Output messages here. }}}}
-
17:02 - Capturing for Mac
// Capturing for Mac var configuration = ObjectCaptureSession.Configuration() configuration.isOverCaptureEnabled = true session.start(imagesDirectory: getDocumentsDir().appendingPathComponent("Images/"), configuration: configuration)
-
18:40 - Pose output
// Pose output try session.process(requests: [ .poses .modelFile(url: modelURL), ]) for try await output in session.outputs { switch output { case .poses(let poses): handlePoses(poses) case .processingComplete: handleComplete() } }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.