[iOS11][ARKit] オブジェクトの位置と回転「常にこっちを向いている怪獣」
1 はじめに
ARLKitでは、空間に自由にオブジェクトを配置することができます。そして、このオブジェクトを配置する位置は、3D空間上の座標(ワールド座標)で指定します。また、オブジェクト自体の向きや傾きも指定することが可能です。
今回は、この位置や向き・傾きの指定についてまとめて見ました。
2 固定位置への配置
以下のコードは、画面をタップしたタイミングで、色の違ったキューブを生成し、シーンの中に配置しているコードです。
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { let node = SCNNode() // ノードを生成 node.geometry = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0) // 一片が10cmのキューブ let material = SCNMaterial() // マテリアル(表面)を生成する material.diffuse.contents = randomColor() // 表面の色は、ランダムで指定する node.geometry?.materials = [material] // 表面の情報をノードに適用 node.position = SCNVector3(0, 0, -0.5) // ノードの位置は、原点から左右:0m 上下:0m 奥に50cmとする sceneView.scene.rootNode.addChildNode(node) // 生成したノードをシーンに追加する }
キューブの位置 position は、カメラを原点として、左右0、上下0、そして奥に50cmとなっています。( SCNVector3(0, 0, -0.5) )
そして、これを実行しているようすです。
起動時は、カメラが原点にいるので、指定した位置(カメラの中央)にキューブが配置されていますが、カメラを移動しても、キューブは同じ位置に生成されるため、カメラの中央では無くなります。
これは、ワールド座標が、起動時(初期化時)に決定され、その後も変化しないことが理由です。
指定した位置(SCNVector3(0, 0, -0.5))は、常に同じ場所を指しているわけです。
3 カメラの中央に配置
起動時(原点)から移動しても、常にカメラ画面の中央にキューブを配置するには、現在のカメラの位置を基準として、キューブ位置を計算する必要があります。
現在のカメラの位置は、sceneView.pointOfViewで取得可能なので、それを基準にconvertPosition(_:to:)メソッドで位置を計算します。
func convertPosition(_ position: SCNVector3, to node: SCNNode?) -> SCNVector3
常にカメラの中央にキューブを配置するコードは、以下のとおりです。
let position = SCNVector3(x: 0, y: 0, z: -0.5) // 偏差のベクトルを生成する if let camera = sceneView.pointOfView { // カメラを取得 node.position = camera.convertPosition(position, to: nil) // カメラ位置からの偏差で求めた位置をノードの位置とする }
そして、こちらを実行するとこんな感じです。
4 カメラの向きに合わせる
常にカメラの中央にキューブを配置することができるようになりましたが、よく見てみるとキューブは、カメラに正対していません。 これも、先ほどの理由と同じで、起動時のZ軸を元にキューブが生成されるため、すべてのキューブが同じ方向に向くのです。
ノードのオイラー角は、eulerAnglesで指定できるので。生成したキューブを、現在のカメラと同じにしてみます。
let position = SCNVector3(x: 0, y: 0, z: -0.5) if let camera = sceneView.pointOfView { node.position = camera.convertPosition(position, to: nil)// カメラ位置からの偏差で求めた位置 node.eulerAngles = camera.eulerAngles // カメラのオイラー角と同じにする }
これを実行すると、常にカメラに正対して、キューブが生成されていることを確認できます。
5 回転させる
上記では、カメラのeulerAnglesを元に、オブジェクトの向きを変えましたが、数値などで直接オブジェクトの回転を指定する場合は、rotationの方が分かりやすいかも知れません。
// X軸を中心に45度回転させる node.rotation = SCNVector4(1, 0, 0, 0.25 * Double.pi)
// Y軸を中心に45度回転させる node.rotation = SCNVector4(0, 1, 0, 0.25 * Double.pi)
// Z軸を中心に45度回転させる node.rotation = SCNVector4(0, 0, 1, 0.25 * Double.pi)
rotationは SCNVector4で指定されます。 SCNVector4は x, y, z, w それぞれの角度(ラジアン)で指定しますが、合成ができないため、複数軸に対する回転を指定するためには、やはりeulerAnglesが必要です。
6 常にこっちを向いている怪獣
最後に、eulerAnglesを使用して、常にカメラの動きに合わせて向きを変える怪獣を作って見ました。
違いが分かりやすいように、2匹の怪獣を生成し、左の怪獣だけを追従させています。
7 最後に
今回は、ノードの位置や回転について纏めてみました。ワールド座標が、シーンの初期化時に決定されるため、カメラの動きに応じた動作を考えると、常に変換が必要になります。ちょっとややこしいですが、慣れるしかないですね。
コードは、下記に置きました。参考になれば幸いです。
[GitHub] https://github.com/furuya02/ARKitPointOfViewpointSample
怪獣のモデルは、下記のものを利用させて頂きました。
https://free3d.com/3d-model/charizard-85299.html
8 参考リンク
Introducing ARKit
Apple Developer > Documentation > ARKit
[iOS 11] はじめてのARKit #WWDC2017
[iOS 11][ARKit] 距離の計測について #WWDC2017
[iOS 11][ARKit] 平面の検出について #WWDC2017
[iOS 11][ARKit] 物理衝突を実装して、キューブを落として見る #WWDC2017
[iOS 11][ARKit] 空間に3Dテキストを表示してみる #WWDC2017
[iOS 11] ARKitでソファー設置からあの子の身長測定まで色々やってみた
[iOS 11][ARKit] 近所の駐車場で、大型ディスプレイでビデオを見る!