31
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ARKitAdvent Calendar 2017

Day 20

ARKitで空間上に写真を置く

Last updated at Posted at 2017-12-20

ARKitを使ってiPhoneのカメラロールに入っている写真を空間上に置いてみます!

IMB_1dDqIg.GIF

今回サンプルで作ってみたViewControllerはgithubに置きましたので、全体はそちらをご確認ください。

手順

空間上に写真を置くためには以下のステップがあります。

    1. UIImagePickerControllerを使ってカメラロールの写真を取得する
    1. 写真のUIImageを持ったSCNNodeを作る
    1. そのnodeをsceneViewに貼る

それぞれ順番に解説していきます。

UIImagePickerControllerを使ってカメラロールの写真を取得する

まずは、UIImagePickerControllerを作ってpresentします。

    private func showUIImagePicker() {
        if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
            let pickerView = UIImagePickerController()
            pickerView.sourceType = .photoLibrary
            pickerView.delegate = self
            pickerView.modalPresentationStyle = .overFullScreen
            self.present(pickerView, animated: true, completion: nil)
        }
    }

pickerViewでのアクションを受け取るためにViewConteollerはdelegateに準拠させます。

pickerView.delegate = self
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
            setImageToScene(image: image)
        }
        picker.dismiss(animated: true, completion: nil)
    }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true, completion: nil)
    }
}

これで、カメラロールのUIImageを取得できましたので、あらかじめ作っておいた

func setImageToScene(image: UIImage)

メソッドでSceneViewに貼っていきます。

写真のUIImageを持ったSCNNodeを作る

とその前に、SCNNodeを作るメソッドを用意しときましょう。

    private func createPhotoNode(_ image: UIImage, position: SCNVector3) -> SCNNode {
        let node = SCNNode()
        let scale: CGFloat = 0.3
        let geometry = SCNPlane(width: image.size.width * scale / image.size.height,
                                height: scale)
        geometry.firstMaterial?.diffuse.contents = image
        node.geometry = geometry
        node.position = position
        return node
    }

ARKit登場以前からあるSceneKitには様々なSCNNodeが用意されていますが、今回はSCNPlaneを作って写真として空間に貼っていくことにしました。

ポイントは、

geometry.firstMaterial?.diffuse.contents = image

で、これやらないとただの白い面ができるだけになるので、要注意!

(ぶっちゃけですが、ここであるscaleはいい感じになるようにチューニングしただけです。笑)

そのnodeをsceneViewに貼る

最後に、sceneViewにnodeを追加していきます。

先ほど作った

func createPhotoNode(_ image: UIImage, position: SCNVector3) -> SCNNode

メソッドを呼んでnodeを作っていますが、その引数に渡しているpositionによって写真がどこに貼られるかが決まります。

今回は、https://dev.classmethod.jp/smartphone/iphone/ios11-arkit-pointofview/ を参考にさせてもらって、カメラの中央、カメラから50cm先に置かれるようにしています。

    private func setImageToScene(image: UIImage) {
        if let camera = sceneView.pointOfView {
            // カメラから見て50cm先の座標
            let position = SCNVector3(x: 0, y: 0, z: -0.5) 
            // 世界座標系に変換
            let convertedPosition = camera.convertPosition(position, to: nil)
            let node = createPhotoNode(image, position: convertedPosition)
            self.sceneView.scene.rootNode.addChildNode(node)
        }
    }

以上で、カメラロールで選択した写真をカメラの中央部分に面として貼ることができました!

IMB_1dDqIg.GIF

参考

##関連APP

github

31
28
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?