Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create parametric 3D room scans with RoomPlan #42

Open
Chaeho-Min opened this issue Aug 25, 2022 · 0 comments
Open

Create parametric 3D room scans with RoomPlan #42

Chaeho-Min opened this issue Aug 25, 2022 · 0 comments

Comments

@Chaeho-Min
Copy link
Member

Chaeho-Min commented Aug 25, 2022

RoomPlan

roomplan-128x128_2x

새 프레임워크!
방을 스캔할 수 있으며, LiDAR를 지원하는 iPhone이나 iPad에서 사용할 수 있다.
방과 방을 정의하는 물체들의 매개 변수 3D 모델을 앱에서 사용할 수 있도록 생성해준다.

RoomPlan은...

  • ARKit을 사용하여 → 벽, 창문, 개구부, 문뿐만 아니라 방을 정의하는 물체들인 벽난로, 소파, 탁자, 진열정까지 감지.
  • RealityKit 사용하여 → 스캐닝과 동시에 렌더링.
  • 스캔이 완료되면 사용하기에 적합한 후처리 결과를 제공.
    → 기계 학습과 컴퓨터 비전 알고리즘을 복잡하게 구현하지 않고도 본인의 방을 스캔하고 렌더링할 수 있게 됐다!

적용할만한 예시

  • Interior design

    인테리어 디자인 앱으로 벽의 색상 변화를 미리 보고 방을 다시 칠하는 데 필요한 페인트 양을 정확히 계산할 수 있다.

  • Architecture

    건축 앱을 통해 자기 방의 구조를 실시간으로 미리 보고 편집할 수 있다.

  • Real estate

    부동산 앱을 통해 중개인은 이제 매물의 평면도와 3D 모델을 완벽하게 포착할 수 있다.

  • E-commerce

    전자 상거래 앱은 실제 공간에서 제품 시각화를 통해 고객을 끌어들일 수 있다.


사용하기

RoomPlan은 두 가지 API를 제공한다.

  1. Scanning experience API

    RoomPlan을 앱에서 사용하는 방법.

  2. Data API

    스캔의 실시간 매개 변수 데이터를 앱이 사용할 수 있도록 처리하는 방법.

1. Scanning Experience API

RoomCaptureView

  • RoomCaptureView를 활성화하면 감지한 벽과 창 등 방을 정의하는 물체들을 실시간으로 표시하는 애니메이션이 나타난다.

  • RoomCaptureView 하단에 생성된 대화형 3D 모델을 통해 스캔 진행률을 한눈에 볼 수 있다.

  • 최상의 스캔 결과물을 낼 수 있도록 상단에 텍스트 코칭이 표시된다.

Code

이제 RoomCaptureView를 앱에서 사용할 수 있도록 코드를 작성하는 방법을 알아보자

  1. 먼저 RoomPlan을 import한다.
import UIKit
import RoomPlan
  1. ViewController에 RoomCaptureView 레퍼런스와 RoomCaptureSession의 Configuration 레퍼런스를 생성한다.
class RoomCaptureViewController: UIViewController {

    var roomCaptureView: RoomCaptureView!
    var captureSessionConfig: RoomCaptureSession.Configuration = RoomCaptureSession.Configuration()

    private func setupRoomCaptureView() {
        roomCaptureView = RoomCaptureView(frame: view.bounds)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        setupRoomCaptureVIew()
    }
}
  1. 스캔 세션을 시작하고 끝낼 메서드를 만든다.
class RoomCaptureViewController: UIViewController {

    private func startSession() {
        roomCaptureView?.captureSession.run(configuration: captureSessionConfig)
    }
    
    private func stopSession() {
        roomCaptureView?.captureSession.stop()
    }
}
  1. 스캔 세션을 시작하고 끝내는 메서드를 적절한 시기에 호출한다.
class RoomCaptureViewController: UIViewController {

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        startSession()
    }
    
    override func viewWillDisappear(_ flag: Bool) {
        super.viewWillDisappear(flag)
        stopSession()
    }
}

이렇게 하면 스캔 과정을 앱에 적용할 수 있다.
이제 스캔 결과를 어떻게 내보내게 할지를 알아보자.

  1. ViewController가 RoomCaptureViewDelegate를 준수하도록 만든다.
extension RoomCaptureViewController: RoomCaptureViewDelegate {

}
  1. captureView(shouldPresent roomDataForProcessing: CapturedRoomData, error: Error?) 메서드를 구현한다.
extension RoomCaptureViewController: RoomCaptureViewDelegate {
    
    func captureView(shouldPresent roomDataForProcessing: CapturedRoomData, error: Error?) -> Bool {
        return true
    }
}

이 함수가 true를 반환하면 스캔이 중지됐을때 스캔 결과를 보여주는 화면을 표시하게 된다.

  1. captureView(didPresent processedResult: CapturedRoom, error: Error?) 메서드를 구현한다.
extension RoomCaptureViewController: RoomCaptureViewDelegate {

    func captureView(didPresent processedResult: CapturedRoom, error: Error?) {
        finalResults = processedResult
    }
}

이 함수의 processedResult가 바로 스캔 결과를 담는다.
이를 이용하여 스캔 결과물을 어디로, 어떤 형식으로 내보낼 것인지 정할 수 있다.

func exportResults() {
    let destinationURL = FileManager.default.temporaryDirectory.appending(path: "Room.usdz")
    do {
        try finalResults?.export(to: destinationURL, exportOptions: .parametric)
    } catch {
        // ...
    }
}
  • .parametric: An export option that formats the output file as a collection of independent, size-agnostic polygonal units.
  • .mesh: A export option that formats the output file as a collection of size-dependent triangles that connect to form a mesh.

2. Data API

스캔 중에 기본 데이터 구조에 접근할 수 있게 하고, 스캔 환경의 맞춤형 시각화를 처음부터 구축하는 걸 도와준다.

기본 워크플로우 3단계.

Scan

Untitled

  • 캡처 세션을 설정하고 시작하는 단계.
  • 캡처 프로세스를 표시하고 모니터링할 수 있다.

Untitled

  • RoomCaptureSession은 기본 AR 세션에 대한 핸들을 제공해 앱이 증강 현실 화면에 평면과 물체 경계 상자를 그릴 수 있게 한다.

  • RoomCaptureSession은 delegate 패턴을 사용하여 뷰컨을 captureSession의 delegate로 할당할 수 있다.
    이렇게 되면 뷰컨이 RoomCaptureSession에서 실시간 업데이트를 가져올 수 있게 된다.

  • 뷰컨이 delegate 역할을 하여 실시간 업데이트를 가져오려면 RoomCaptureSessionDelegate를 준수하고 두 가지 메서드를 구현해야 한다.

Untitled

  • captureSession(_ session: didUpdate room:) 메서드로 CapturedRoom 데이터 구조를 실시간으로 얻게 된다.
    Visualizer는 이걸 사용해서 process에 실시간 피드백을 제공하는 3D 모델의 AR 화면을 업데이트할 수 있게 된다.
    이 메서드는 스캔하는 방에 대해 업데이트가 감지될 때 호출된다.

Untitled

  • captureSession(_ session: didProvide instruction:) 메서드는 텍스트 코칭같은 실시간 피드백을 포함하는 instruction 구조체를 제공한다.
  • Visualizer는 이 instruction을 사용해 스캔하는 동안 사용자를 안내한다.

Process

Untitled

  • 스캔 데이터를 처리하고 최종 모델을 수신하는 단계.
  • RoomBuilder 클래스를 사용해 스캔한 데이터를 처리하고 최종 3D 모델을 생성한다.

Untitled

  • 캡처한 데이터를 처리하는 첫 단계는 ViewController 클래스의 RoomBuilder 인스턴스를 시작하는 것이다.

Untitled

  • 다음은 캡처 과정 이후 센서 데이터를 수신하기 위해 captureSession(_ session: didEndWith data: error:) 메서드를 구현해야 한다.
  • stop() 메서드가 호출되거나 에러 발생으로 인해 RoomCaptureSession이 멈추면, 이 함수는 CapturedRoomData object나 에러를 반환하기 위해 호출된다.

Untitled

  • 마지막으로 캡처한 데이터를 처리하기 위해 roomBuilder의 비동기 메서드 roomModel(from:)을 await으로 호출한다.
  • 스캔한 데이터를 처리하고 최종 3D 모델을 구축하기 위해 비동기로 실행된다.

Untitled

  • 비동기 함수가 완료되면 최종 모델을 받을 수 있다.

Export

Untitled

  • CapturedRoom 데이터 구조에 대한 세부 사항을 알아보고
  • 앱에서 사용할 수 있도록 출력 USD 파일을 생성하고 내보낼 수 있는 방법을 알아본다.

Untitled

  • 최상위 레벨에는 CapturedRoom이 있다.
  • 이 CapturedRoom은 Surface와 Object로 구성되어 있다.

Untitled

  • Surface는 curve, edge, 그리고 건축 category로 구성되어 있다.

Untitled

  • Object는 가구 category로 구성되어 있다.

Untitled

  • Surface와 Object는 dimensions(치수), confidence(스캔한 표면 또는 물체에 대한 세 단계의 신뢰도), transform(3D 변형 매트릭스), 그리고 identifier(고유 식별자)와 같은 공통 속성을 몇 가지 공유한다.

Untitled

  • CapturedRoom 구조체는 방의 요소를 온전히 매개변수로 표현한다.

Untitled

  • 처음 4개 요소인 walls, doors, windows, openings는 2D 평면 건축 구조인 Surface 구조를 대표한다.
  • Surface 구조체를 보면 앞서 말한 Surface의 속성들이 정의되어 있는 것을 확인할 수 있다.

Untitled

  • CapturedRoom에 정의된 마지막 요소는 Object이며, Object 구조체도 마찬가지이다.

Untitled

  • RoomPlan에서 지원하는 Object 타입.

Untitled

  • export 메서드로 방을 캡처한 데이터인 이 CapturedRoom 구조체를 USD나 USDZ 파일로 내보낼 수 있다.

Untitled

  • 내보낸 USD/USDZ 파일을 C4D같은 프로그램에서 바로 열 수 있다.

Untitled

  • 방의 요소를 온전히 매개변수로 표현하기 때문에 이렇게 스캔 결과가 한 덩어리(mesh)로 저장되지 않고 인식한 카테고리가 USD/USDZ 파일에도 구분되어 있는 것을 확인할 수 있다.

Untitled

  • 따라서 각 카테고리별로 3D 모델을 수정할 수 있다.

Best practices

Roomplan에서 좋은 결과를 얻을 수 있도록 보여주는 몇 가지 모범 사례들.

Recommended conditions

  • Single residential rooms
    • 일반적인 가정의 가장 일반적인 구조와 물체
  • Room size: 최대 9m x 9m
  • Lighting: 최소 50 lux
    • 일반적인 가정의 밤일 때 조도가 보통 이정도이다.
  • 하드웨어: LiDAR가 있는 아이폰, 아이패드

Room selection

스캔이 어려운 조건들.

  • Full-height mirrors or glass
  • High ceilings
  • Dark surfaces

모두 LiDAR가 스캔하기 힘들어하는 조건들이다.

Scanning considerations

더 나은 스캔 결과를 얻기 위해 고려할 사항들.

  • 사전준비
    • 커튼 열어놓기
    • 문 닫아놓기
  • 스캔 도중 나오는 질감, 거리, 속도나 조명 조건 등에 대한 지시 따르기

Thermal considerations

스캔이 어려운 조건들.

  • 반복적인 스캔
  • 5분이 넘어가는 스캔

배터리가 방전되고 발열 떄문에 앱의 사용자 경험에 영향을 줄 수 있다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant