[iOS 11][ARKit] 空間に3Dテキストを表示してみる #WWDC2017

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

iOS 11で追加されたARKitを利用して、道路上に巨大な文字「ARKit is awesome」が出現して居る動画が、Youtubeに公開されています。

ARKitを使用すると、簡単にこのような表現が可能です。今回は、3D空間に、文字列を表示する要領について確認して見たいと思います。

本記事は Apple からベータ版として公開されているドキュメントを情報源としています。 そのため、正式版と異なる情報になる可能性があります。ご留意の上、お読みください。

2 SCNText

SCNTextは、NSString又は、NSAttributedString及び、深さ(押し出してテキストに厚みを加える)を指定するだけで、簡単に3Dの文字列オブジェクトが作成できます。

convenience init(string: Any?, extrusionDepth: CGFloat)
let text = SCNText(string: "文字列", extrusionDepth: depth)
let textNode = SCNNode(geometry: text)

あとは、通常のNodeオブジェクトを同じように、シーンに追加するだけです。

3 原点座標

SCNTextを使用する場合は、座標に注意が必要です。

下図は、Xcode8.3.3の、Gomeプロジェクト(Game TechnologySceneKitを選択)で作成したSceneKit Scene Fileで、3DTextを作成している例です。

004 001

左下に、ローカルの原点座標が表示されていますが、見てわかるように、オブジェクトの中心ではありません。

テキスト全体の左下、なおかつ、テキスト下辺より更に下になっています。なお、奥行き(Z軸)に関しては、押し出されたテキストの中央になっています。

002

このため、Nodepositionに、X=0, Y=0, Z=-20 を設定して(20mほど前方に置いたつもり)、シーンに追加しても、下図のように、ちょっと予想外の位置に配置されてしまいます。 実際に表示してみると分かりますが、恐らく、予想以上に右上に存在しているのではないでしょうか。

003

4 サイズ

SCNTextは、サイズについても、ちょっとイメージアップが必要です。

特に指定しないでSCNTextを生成すると、fontプロパティは、次のようになっています。

name:"SFUIText"; font-weight: normal; font-style: normal; font-size: 12.00pt

この時のオブジェクトのサイズを確認する下記のコードの結果は、約75mでした。

let str = "本日は晴天なり"
let depth:CGFloat = 10 // 奥行き10m
let text = SCNText(string: str, extrusionDepth: depth)
let textNode = SCNNode(geometry: text)
let (min, max) = (textNode.boundingBox)
let w = CGFloat(max.x - min.x)
print("\(str) = \(w)m") // 本日は晴天なり = 75.6931686401367m

もし、もう少し、小さな文字列オブジェクトが必要であれば、フォント指定で調整します。

text.font = UIFont(name: "HiraKakuProN-W6", size: 0.5);

// 本日は晴天なり = 3.39199995994568m

5 諸々調整して文字列オブジェクトを中央に配置する

文字列オブジェクトをスマフォ画面に左右の中央に持ってくるためには、ノードのバウンディングボックスから横幅を求め、その半分だけ左に寄せれば良いことになります。

上下のサイズもバウンディングボックスから取得することは可能ですが、最初に紹介した通り、原点は、実際のテキストの底辺より下になっているので、それだけでは中央には来ません。この差分の調整は、ちょっと分かりませんでしたの、とりあえず、1mほど下げました。 

let depth:CGFloat = 0.5
let text = SCNText(string: str, extrusionDepth: depth)
text.font = UIFont(name: "HiraKakuProN-W6", size: 0.5);
let textNode = SCNNode(geometry: text)

let (min, max) = (textNode.boundingBox)
let x = CGFloat(max.x - min.x)
let y = CGFloat(max.y - min.y)
textNode.position = SCNVector3(-(x/2), -1, -2)

print("\(str) width=\(x)m height=\(y)m depth=\(depth)m")

sceneView.scene.rootNode.addChildNode(textNode)
本日は晴天なり width=3.39199995994568m height=0.462499976158142m depth=0.5m

これで、幅3m 高さ40cm 奥行き50cmの文字オブジェクトが、画面の正面に現れます。

6 最後に

今回は、文字列Nodeをシーンに追加する要領について確認して見ました。 フォントサイズと原点座標に注意すれば、扱いは、それほど難しくないかもしれません。

試したコードは、下記に置きました。不明な点があればご参照ください。
github [GitHub] https://github.com/furuya02/ARKit3DTextSample

7 参考リンク


Introducing ARKit
Apple Developer > Documentation > ARKit
WWDC2017 Session 602 Introducing ARKit: Augmented Reality for iOS
SCNText
[iOS 11] はじめてのARKit #WWDC2017
[iOS 11][ARKit] 距離の計測について #WWDC2017
[iOS 11][ARKit] 平面の検出について #WWDC2017
[iOS 11][ARKit] 物理衝突を実装して、キューブを落として見る #WWDC2017