LoginSignup
0
1

More than 3 years have passed since last update.

[ARKit]水平面の検出

Posted at

水平面を検出するためのコンフィグレーションを設定

現実世界の水平面を検出するためにの設定をします。
sceneViewの型はARSCNViewクラスです。デフォルトでは、平面検出は行われません。必要な機能はプログラマーが各自設定する必要があります。

   let configuration=ARWorldTrackingConfiguration()
//水平面の時は.horizontalで垂直面の時は.verticalになります。
   configuration.planeDetection = .horizontal
   sceneView.session.run(configuration)

検出した平面をどのように扱うのか?

ARSessionDelegateを処理したいクラスに批准させて、そのクラスをARSceneView.session.delegateに代入して、デリゲートメソッドを利用します。

sceneView.session.delegate=self

ここで、selfを代入させたので、このクラス(Viewcontroller)上でデリゲートメソッドを利用できます。

//アンカーがセッションに追加されたときに呼ばれる
func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {

    }
//アンカーが更新されたときに呼ばれる
func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {

    }

アンカーとは検出物体の位置や向きを表すクラスです。
ARanchorクラスはプロパティとしてindentifierとtransformを持っています。
indentifierはそのアンカーの名前です。人間でも名前で他人と区別するように、アンカーにも名前をつけて他のアンカーと区別をします。つまり、アンカーを一意に定めるものです。transformは、位置や大きさを表すプロパティで4×4行列です。
ここで、anchorのままでは使いにくいので,サブクラスであるARPlaneAnchorにキャストします。

//アンカーがセッションに追加されたときに呼ばれる
func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
     guard let planeAnchors=anchor as? [ARPlaneAnchor] else {return}

    }

ARPlaneanchorクラスは,centerプロパティとextentプロパティを持ちます。
centerプロパティは平面アンカーの中心の位置で、extent(simd_float3型)は,平面の大きさを表しますが、平面なのでyの値は0になります。
検出した平面に色を塗りたいときこのメソッドは使いません。
AR機能はセッション単位で管理しています。
上のメソッドでは、平面に限らず、seceViewにアンカーが追加されたり、更新されたりするときに呼ばれだけで検出した平面のアンカーの位置や大きさを所得して、色を変えたりするのは別のメソッドで行います。

平面検出したときに呼ばれるメソッド

ARSCNViewDelegateプロトコルのデリゲートメソッドを使います。

//平面アンカーのノードがシーンに追加されたときに呼ばれる
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
//      アンカーを平面アンカーにキャストする
        guard let planeAnchor=anchor as? ARPlaneAnchor else {return}
//      アンカーから平面形状(geometry)の平面を作成
        let geometry=SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))
//      平面に黄色を付ける
     geometry.materials.first?.diffuse.contents=UIColor.yellow.withAlphaComponent(0.8)
//      平面からノードを作成する。        
        let planeNode=SCNNode(geometry: geometry)
//     なんか知らんけど、平面がx-y平面上に作られるので,平面をx軸(1,0,0)を軸に90°回す
        planeNode.transform=SCNMatrix4MakeRotation(-Float.pi/2, 1, 0, 0)
//      メインスレッドでnodeに追加する
        DispatchQueue.main.async(execute:{
            node.addChildNode(planeNode)
        })
    }

nodeは平面アンカーに対応したnodeです。

0
1
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
0
1