ARKit入門 / 平面の検出(1)
iOSの「ARKit」で「平面」を検出するプログラムを作ります。
1. 平面の検出
「平面」を検出し、検出領域を青い矩形で表示します。
import UIKit
import SceneKit
import ARKit
//平面の検出(1)
class ViewController: UIViewController, ARSCNViewDelegate {
@IBOutlet var sceneView: ARSCNView!
//ロード時に呼ばれる
override func viewDidLoad() {
super.viewDidLoad()
//シーンの作成
sceneView.scene = SCNScene()
//特徴点とワールド原点の表示
sceneView.debugOptions = [
ARSCNDebugOptions.showFeaturePoints,
ARSCNDebugOptions.showWorldOrigin]
//光源の有効化
sceneView.autoenablesDefaultLighting = true;
//ARSCNViewデリゲートの指定
sceneView.delegate = self
}
//ビュー表示時に呼ばれる
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//コンフィギュレーションの生成
let configuration = ARWorldTrackingConfiguration()
//平面検出の有効化
configuration.planeDetection = .horizontal
//セッションの開始
sceneView.session.run(configuration)
}
//ビュー非表示時に呼ばれる
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
//セッションの一時停止
sceneView.session.pause()
}
//ARアンカー追加時に呼ばれる
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
DispatchQueue.main.async {
//ARPlaneAnchorの時
if let planeAnchor = anchor as? ARPlaneAnchor {
//位置とサイズによる平面ノードの追加
let planeNode = SCNNode()
let geometry = SCNPlane(
width: CGFloat(planeAnchor.extent.x),
height: CGFloat(planeAnchor.extent.z))
geometry.materials.first?.diffuse.contents = UIColor(red: 0, green: 0, blue: 1, alpha: 0.5)
planeNode.geometry = geometry
planeNode.transform = SCNMatrix4MakeRotation(-Float.pi / 2.0, 1, 0, 0)
node.addChildNode(planeNode)
}
}
}
//ARアンカー更新時に呼ばれる
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
DispatchQueue.main.async {
//ARPlaneAnchorの時
if let planeAnchor = anchor as? ARPlaneAnchor {
//位置とサイズの更新
guard let planeNode = node.childNodes.first,
let geometry = planeNode.geometry as? SCNPlane else {fatalError()}
planeNode.simdPosition = float3(planeAnchor.center.x, 0, planeAnchor.center.z)
geometry.width = CGFloat(planeAnchor.extent.x)
geometry.height = CGFloat(planeAnchor.extent.z)
}
}
}
}
◎光源の追加
追加するオブジェクトを表示するため、光源を有効化します。
//光源の有効化
sceneView.autoenablesDefaultLighting = true;
◎コンフィギュレーションの設定
コンフィギュレーションの設定で平面検出を有効化するには、planeDetectionに.horizontalを指定します。
//平面検出の有効化
configuration.planeDetection = .horizontal
コンフィギュレーションで可能な設定は次の通りです。
・planeDetection: 水平面(.horizontal)と垂直面(.vertical)を認識するかどうか
・detectionImages: 画像マーカーの指定
・detectionObjects: 3Dオブジェクトのマーカーの指定
・environmentTexturing: 環境マッピングの有効化
・isAutoFocusEnabled: カメラのオートフォーカスの有効化
◎ARSCNViewデリゲートの設定
ARアンカーとARアンカーの子ノードの同期を行うためのデリゲートです。
//ARSCNViewデリゲートの指定
sceneView.delegate = self
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor)
ARアンカー追加時(新規に平面検出時)に呼ばれる。
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode?
追加されたARアンカーに対応するノードを提供。
func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor)
ARアンカー削除時(平面検出解除時)に呼ばれる。
func renderer(_ renderer: SCNSceneRenderer, willUpdate node: SCNNode, for anchor: ARAnchor)
ARアンカーの位置をARアンカーに対応するノードに反映する前に呼ばれる。
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor)
ARアンカーの位置をARアンカーに対応するノードに反映した後に呼ばれる。
◎位置とサイズによる平面ノードの追加
平面検出を有効にしているので、検出時には「ARPlaneAnchor」が「renderer(_:didAdd node:for anchor:)」に通知されます。可視化するために、SCNPlaneのジオメトリを持つ平面ノードを生成して追加します。
//ARアンカー追加時に呼ばれる
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
DispatchQueue.main.async {
//ARPlaneAnchorの時
if let planeAnchor = anchor as? ARPlaneAnchor {
//位置とサイズによる平面ノードの追加
let planeNode = SCNNode()
let geometry = SCNPlane(
width: CGFloat(planeAnchor.extent.x),
height: CGFloat(planeAnchor.extent.z))
geometry.materials.first?.diffuse.contents = UIColor(red: 0, green: 0, blue: 1, alpha: 0.5)
planeNode.geometry = geometry
planeNode.transform = SCNMatrix4MakeRotation(-Float.pi / 2.0, 1, 0, 0)
node.addChildNode(planeNode)
}
}
}
◎位置とサイズの更新
検出した平面の情報更新の検出時には「ARPlaneAnchor」が「renderer(_:nodeFor anchor:)」に通知されます。検出情報に応じて位置とサイズを更新します。
//ARアンカー更新時に呼ばれる
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
DispatchQueue.main.async {
//ARPlaneAnchorの時
if let planeAnchor = anchor as? ARPlaneAnchor {
//位置とサイズの更新
guard let planeNode = node.childNodes.first,
let geometry = planeNode.geometry as? SCNPlane else {fatalError()}
planeNode.simdPosition = float3(planeAnchor.center.x, 0, planeAnchor.center.z)
geometry.width = CGFloat(planeAnchor.extent.x)
geometry.height = CGFloat(planeAnchor.extent.z)
}
}
}
2. ARアンカー
検出したARアンカーの位置と向きは「anchor」、ARアンカーの情報を元に表示するノードは「node」として渡されます。
・anchor: 検出したARアンカーの位置と向き。
・node: ARアンカーの情報を元に表示するノードのジオメトリと位置と向きとスケール。
ARアンカーの種類は次の通りです。
・ARPlaneAnchor: 平面のARアンカー
・ARImageAnchor: 画像のARアンカー
・ARObjectAnchor: 3DオブジェクトのARアンカー
・AREnvironmentProbeAnchor: 環境照明のARアンカー
・ARFaceAnchor: 顔の表情のARアンカー(フロントカメラ)
・ARBodyAnchor: 身体の3D空間での動きを追跡するARアンカー
・ARParticipantAnchor: マルチユーザーARエクスペリエンスの別のユーザーを表すARアンカー
この記事が気に入ったらサポートをしてみませんか?