Apple Engine

Apple, iPhone, iOS, その周辺のことについて

iOS で SceneKit を試す(Swift 3) その20 - ビルトインジオメトリ SCNFloor(無限の大きさを持つ平面)

Y軸 0、XZ 軸が無限の大きさを持つ平面。 初期値では原点に配置される。

f:id:x67x6fx74x6f:20170711161008p:plain

 

Scene Editor でのパラメーター

オブジェクトライブラリの Floor を Scene Editor にドラッグ&ドロップして、Attributes Inspector を開く(Command + Option + 4)

1番上の Floor の項目で設定値が変更できる

f:id:x67x6fx74x6f:20170711161036p:plain

 

Reflectivity

0 〜 1 の範囲の値で反射率を表す。 1 が完全に反射し 0 が反射なしとなり、デフォルトは 0.25

 

デフォルト値 0.25

f:id:x67x6fx74x6f:20170711161106p:plain

 

値 1

f:id:x67x6fx74x6f:20170711161143p:plain

 

Falloff start / Falloff end

反射の減退の開始と終わり。 デフォルトは共に 0 減退はしない。

start 0、end 0.6 にするとこのシーンの場合は以下のようになる。

f:id:x67x6fx74x6f:20170711161207p:plain

 

start、end の間が少なすぎると急に減退し違和感が出るので注意。

 

Resolution factor

鏡面反射はシーンをオフスクリーンでシーンをレンダリング後、さらに床のテクスチャーをレンダリングして、 最終的にそれらを合わせたものを画面にレンダリングする。 この値は鏡面反射のレンダリング画質で 0 〜 1 の間で設定する。 デフォルトは iOS は 0.5、macOS は 1 となっており、iOS は負荷が少ないように設定されている。

値 0.1(反射画像の球の輪郭が荒い)

f:id:x67x6fx74x6f:20170711161401p:plain

 

値 1.0(反射画像の球の輪郭が綺麗)

f:id:x67x6fx74x6f:20170711161451p:plain

 

コード

コードで設定できる値で、幅、長さ、反射用のビットマスクがあるが、ほとんどの場合で使用する必要がないため割愛。

// シーン設定
let scnView = self.view as! SCNView
scnView.showsStatistics = true
scnView.allowsCameraControl = true

let scene = SCNScene()
scene.background.contents = UIColor.white
scnView.scene = scene

// カメラ設定
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(2.372,1.473,2.399)
cameraNode.eulerAngles = SCNVector3(-Float.pi * 0.125,Float.pi * 0.25,0)
scene.rootNode.addChildNode(cameraNode)

// ライト設定
let lightNode = SCNNode()
let omniLight = SCNLight()
omniLight.type = .omni
lightNode.light = omniLight
lightNode.position = SCNVector3(0,5,0)
scene.rootNode.addChildNode(lightNode)

// SCNFloor
let floor = SCNFloor()
floor.reflectivity = 0.25
floor.reflectionFalloffStart = 0
floor.reflectionFalloffEnd = 0
floor.reflectionResolutionScaleFactor = 0.5

let floorNode = SCNNode(geometry: floor)
scene.rootNode.addChildNode(floorNode)

// 鏡面反射用の球
let ball = SCNSphere(radius: 0.5)
let ballNode = SCNNode(geometry: ball)
ballNode.position = SCNVector3(0,1,0)
scene.rootNode.addChildNode(ballNode)

 

今回はここまで。

iOS で SceneKit を試す(Swift 3) その19 - ジオメトリについて

SceneKit で言うジオメトリは平面や立体の物体を指し、 プログラムで形を作り、法線やテクスチャ情報、マテリアルなどその他の情報を付加して物体を表示している。

 

SceneKit でのジオメトリの使用方法

使用方法は以下のもの。

  • ビルトインのジオメトリを使用する
  • Model I/O 経由で 3D オブジェクトファイルを読み込みジオメトリとして使用する
  • scn ファイルにあるジオメトリを使用する
  • SpriteKit を表示する
  • 自前でジオメトリを作る

 

ビルトインのジオメトリ

f:id:x67x6fx74x6f:20170711142608p:plain

すでに過去の記事で使用しているが、
ビルトインのジオメトリとは特定の形を描画するジオメトリのクラスで、
以下のものが用意されている。

  • 無限平面(SCNFloor)
  • 立方体(SCNBox)
  • カプセル型(SCNCapsule)
  • 円錐(SCNCone)
  • 円柱(SCNCylinder)
  • 平面(SCNPlane)
  • 三角錐(SCNPyramid)
  • 球(SCNSphere)
  • ドーナツ型(SCNTorus)
  • チューブ型(SCNTube)
  • テキスト(SCNText)
  • パスからの図形(SCNShape)

シーンエディタでは SCNShape は使用できない。
Core Gpraphics のパスを使用するため。

 

今回はここまで。

次回から、ビルトインのジオメトリの設定について見ていく。

ARKit を SpriteKit で試す

注意ベータ版で公開されているドキュメントを元に記事を作成しているため、API や動作が製品版と異なる可能性あり

 

SceneKit や Unity、Unreal Engine でほぼ制作されると思われるが、
一応、SpriteKit の 2DCG を使用した ARKit アプリを作成することができる。

 

WWDC 2017 Going Beyond 2D with SpriteKit セッションでのデモ画像。
絵文字をアンカーとして現実空間に貼り付けている。

f:id:x67x6fx74x6f:20170707184811p:plain

 

平面の認識を必要としないのであれば、
リソースの制作時間が圧倒的に少ない 2DCG で ARKit をやるという割り切り方もありだと思っている。

また、カメラやセンサを使ったロジックなので
HoloLens や Tango のように平面の認識が必ず認識できるというわけではないので。

 

どのようにして SpriteKit で ARKit を実現していのか?

ドキュメントの ARSKViewDelegate あたりを見てみると、
どうやら内部で SceneKit 上の板ポリゴンのマテリアルに SpriteKit を貼り付け、
ビルボードコンストレイントのようなものを使用してカメラを向くように設定している模様。

ちなみに、SceneKit で SpriteKit を使用する機能は初期のころからあり、その逆もできる。

 

Game テンプレートからつくってみる

Xcode 9 のテンプレートについては NDA 上、あんまし触れられないので Xcode 8 の方法で作成してみる。

Xcode 9 を起動し、
いつも通りの iOS の Game テンプレートを選び、Game Technology を SpriteKit にしてプロジェクト作成。

Actions.sks は使わないので削除し、GameScene.sks の helloLabel も削除。

 

その1: カメラを使いので info.plist をいじる

info.plist を開いて「Privacy - Camera Usage Description」を追加。
今回は試すだけなので値は空でも可。
例のごとく、これをしないとアプリが落ちて起動しない。

 

その2: Main.storyboard の View を変更する

Game View Controller > View を選択し、Identity Inspector (Command + Option + 3) のクラスを SKView から ARSKView に変更する。

 

その3: GameScene.swift の変更

以下のコードに変更

import SpriteKit
import ARKit

class GameScene: SKScene {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let sceneView = self.view as? ARSKView else {
            return
        }
        
        if let currentFrame = sceneView.session.currentFrame {
            var translation = matrix_identity_float4x4
            translation.columns.3.z = -0.2
            let transform = simd_mul(currentFrame.camera.transform, translation)
            
            let anchor = ARAnchor(transform: transform)
            sceneView.session.add(anchor: anchor)
        }
    }
}

 

GameViewController.swift

以下のコードに変更

import UIKit
import SpriteKit
import ARKit

class GameViewController: UIViewController, ARSKViewDelegate {
    
    var sceneView:ARSKView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        sceneView = self.view as! ARSKView
        
        sceneView.delegate = self
        sceneView.showsFPS = true
        sceneView.showsNodeCount = true
        
        if let scene = SKScene(fileNamed: "GameScene") {
            sceneView.presentScene(scene)
        }
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        let configuration = ARWorldTrackingSessionConfiguration()
        
        sceneView.session.run(configuration)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        sceneView.session.pause()
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    // MARK: - ARSKViewDelegate
    
    func view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? {
        let labelNode = SKLabelNode(text: "👾")
        labelNode.horizontalAlignmentMode = .center
        labelNode.verticalAlignmentMode = .center
        return labelNode;
    }
    
    func session(_ session: ARSession, didFailWithError error: Error) {}
    func sessionWasInterrupted(_ session: ARSession) {}
    func sessionInterruptionEnded(_ session: ARSession) {}
}

 

ビルドして実機で実行

平面認識をさせていないので即動作し、画面タップで絵文字が出る。

 

中身は何をしているのか

基本はドキュメント通りの作り方

Providing 2D Virtual Content with SpriteKit | Apple Developer Documentation

 

GameScene.swift

タップイベント後 ARSKView がない場合は即 return で命令を止める。
その後、ARSession の currentFrame があれば、タッチした位置と Z 軸方向 -0.2 を新しく追加されたメソッド simd_mul で SCNMatrix4 の値を掛け合わし、アンカーをシーン上に置く。

 

GameViewController.swift

viewDidLoad で ARSKViewDelegate を含む初期設定。
viewWillAppear で表示された時 ARKit の設定を行い、run で ARKit の開始。
viewWillDisappear でバックグラウンドに戻った際は必ず pause 止める。

デリゲートである func view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? はアンカーが置かれた時に SKNode を返す。

今回はタップ時に呼ばれる。

 

セッションようにランダムで絵文字を置く

アンカーは SKLabelNode なのでただランダムで文字を渡せば良い。

GameViewController.swift のデリゲートを以下のように変更

func view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? {
    let emojiArray:[String] = [
        "🍣","🌍","🐶","🍱","🙅","📱","👾"
    ]

    let labelNode = SKLabelNode(text: emojiArray[Int(arc4random_uniform(UInt32(emojiArray.count)))])
    labelNode.horizontalAlignmentMode = .center
    labelNode.verticalAlignmentMode = .center

    return labelNode;
}

 

画像を置いてみる

せっかくなので SKAction でアニメーションさせてみたいのだが問題がある。

上の方で説明した通り、SceneKit のビルボードコンストレイントを使用しているため、そのままだとアニメーションが反映されない。

なぜなら、ビルボードコンストレイントが SCNMatrix4 で変形を行なっているため、SKAction の変形が反映されないためだ。

ということで、空のノードをつけてから SKNode を返すことで解決できる。

 

以下の画像を LogoARKit.png としてプロジェクトに追加。

f:id:x67x6fx74x6f:20170707185201p:plain

 

GameViewController.swift のデリゲートを再度変更

func view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? {
    let spriteNode = SKSpriteNode(imageNamed: "LogoARKit.png")
    spriteNode.xScale = 0.025
    spriteNode.yScale = 0.025
    
    let rotateAnimation = SKAction.rotate(byAngle: CGFloat(Float.pi * 2.0), duration: 1)
    rotateAnimation.timingMode = .easeIn
    
    spriteNode.run(
        SKAction.repeatForever(
            SKAction.sequence([
                SKAction.wait(forDuration: 3),
                rotateAnimation
            ])
        )
    )
    
    let returnNode = SKNode()
    returnNode.addChild(spriteNode)
    
    return returnNode
}

試しに return spriteNode にすると微妙な動きをすると思われる。

 

SpriteKit シーンファイルに何もないのはなぜ?

予想ではあるが SpriteKit 自体にちゃんとした奥行きの情報がないためだと思われ UI(HUD)などで使用するものだと思われる。

そのため GameScene.sks に SKNode を置くとカメラにノードが張り付いて表示される。

 

まとめ

ひとまず、上記のものの SKNode の中身変更するだけで SpriteKit の配置は通りできると思われる。
今回はやらなかったが ARSKView 自体 SKView と同等なので hitTest で SKNode いじることもできる。

このレベルのものでもそこそこ面白さはあるので、
この夏、お暇な方は ARKit で何かつくってみてわというところ。

iOS で SceneKit を試す(Swift 3) その18 - Scene Editor の Constraints を試す

3DCG ではオブジェクトの動きなどに制約を与えるコンストレイントというものがある。

SceneKit では SCNConstraint というスーパークラスがあり、サブクラスで機能が割り当てられている。
一応、SCNTransformConstraint というクラスが用意されており、カスタムのコンストレイントを作成することもできる。

 

SceneKit で使用できるコンストレイントは以下のもの。

名称 機能
Look At コンストレイント 指定したノードの方向へ必ず回転するように維持する
Billboard コンストレイント 現在のカメラへ指定した方向に必ずなるように回転を維持する
IK コンストレイント インバース・キネマティックを行うために使用する

 

IK コンストレイント は Scene Editor では設定できないようなので、オブジェクト読み込みかボーンの際、説明しようと思う。

 

下準備

カメラ

シーンファイル (.scn) のカメラを選択。
Node Inspector を開き(Command + Option + 3)を開き、
以下に設定

X Y Z
Position 0 2 0
Eular -20 0 0
Scale 1 1 1

 

f:id:x67x6fx74x6f:20170706193532p:plain  

オブジェクトライブラリから Floor を Scene Editor にドラッグ&ドロップして配置。

初期値は位置と回転 0 だが、違っていたら 0 にする。

X Y Z
Position 0 0 0
Eular 0 0 0
Scale 1 1 1

 

f:id:x67x6fx74x6f:20170706193548p:plain  

スポットライト

オブジェクトライブラリから Floor を Scene Editor にドラッグ&ドロップして配置し以下に設定を変更。

X Y Z
Position 0 5 0
Eular -90 0 0
Scale 1 1 1

 

f:id:x67x6fx74x6f:20170706193601p:plain

 

空のノードと球

オブジェクトライブラリから Empty Node を Scene Editor にドラッグ&ドロップ、
もしくは Scene Graph View の左下「+」のアイコンを押して、 空のノードを追加し原点に設定。

X Y Z
Position 0 0 0
Eular 0 0 0
Scale 1 1 1

 

f:id:x67x6fx74x6f:20170706193639p:plain  

オブジェクトライブラリから Sphere を Scene Editor にドラッグ&ドロップして配置し以下に設定を変更。

X Y Z
Position -1.5 0.4 0
Eular 0 0 0
Scale 0.4 0.4 0.4

 

Scene Graph View で球が先ほどつくった空のノードの下になるよドラッグ。

f:id:x67x6fx74x6f:20170706193701p:plain

 

空のノードを回転させるアニメーションをつける

空のノードを選択。
セカンダリエディタを開き、オブジェクトライブラリから RotateTo Action をタイムラインにドラック&ドロップ。

Start Time を 0、Duration を 2、Y軸を -360 にして時計回りにする。

f:id:x67x6fx74x6f:20170706193741p:plain

 

スポットライトの影を落とす

必要がなければこれは設定しなければよい。

スポットライトを選択し、Attributes Inspector を開く(Command + Option + 4)

Shadow の項目の Casts shadows にチェックを入れると球に影が床に落ちる

f:id:x67x6fx74x6f:20170706193828p:plain

 

準備完了。

 

Look At コンストレイント

スポットライトの向きを Look At コンストレイントを使ってボールにあわせてみる。

スポットライトを選択して、 Node Inspector を開き(Command + Option + 3)を開き一番下の Constraints から「Look At」を選択。

f:id:x67x6fx74x6f:20170706193855p:plain

 

Constraints Settings 内容が表示されるようになるので、Target Node を作成した Sphere に合わせてみる。

f:id:x67x6fx74x6f:20170706193940p:plain

 

再生すると以下のようになる。

f:id:x67x6fx74x6f:20170706194021g:plain

 

Billboard コンストレイント

適当な場所にオブジェクトライブラリから Plane を Scene Editor にドラッグ&ドロップして配置。

f:id:x67x6fx74x6f:20170706194308p:plain

 

今回設定するテクスチャの問題で Plane の高さを Attributes Inspector で変更。

f:id:x67x6fx74x6f:20170706194327p:plain

 

Material Inspector を開き(Command + Option + 4)を Diffuse に適当な画像を適応。

f:id:x67x6fx74x6f:20170706194431p:plain

  f:id:x67x6fx74x6f:20170706194505p:plain

 

そのままだとスポットライトの関係上、影で映らないので、Illumination を白色にする。

f:id:x67x6fx74x6f:20170706194543p:plain

 

Node Inspector から Billboard コンストレイント適応。

f:id:x67x6fx74x6f:20170706194612p:plain

 

カメラを移動、回転させても
画面上に Plane がある場合は、必ずカメラの方向に向く。

 

注意点

Look At もそうだが Billboard は親のノードの回転の影響を受ける場合があるので、できるだけルートノードで使うべし。

 

必ず前面に Billboard を表示したい

UI 的なものだとどんなにオブジェクトが前にあっても、最前面に表示したい場合がある。

f:id:x67x6fx74x6f:20170706194731p:plain

 

そんな時は Material Inspector の Settings > Options > Reads Depth を外す。 チェックを外すとこのマテリアルは SceneKit の奥行き情報を無視する。

f:id:x67x6fx74x6f:20170706194748p:plain

 

iOS11 SDK で増えるもの

  • Distance Constraint
  • Occluder Constraint
  • Acceleration Constraint
  • Slider Constraint
  • Replicator Constraint

 

今回はここまで

iOS で SceneKit を試す(Swift 3) その17 - SCNNode の worldTransform

前回 Scene Editor で World 座標での設定箇所にふれた。
今回はコード上から行ってみる。

 

その前に 4x4 の行列 SCNMatrix4 での移動方法

SCNMatrix4 は 4x4 になっているため、設定できる値は16個ある。 以下のようにし、移動させる場合は m41, m42, m43 の値変更を修正。

var m = SCNMatrix4(
    m11: 1.0, m12: 0.0, m13: 0.0, m14: 0.0,
    m21: 0.0, m22: 1.0, m23: 0.0, m24: 0.0,
    m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0,
    m41: 0.0, m42: 0.0, m43: 0.0, m44: 1.0
)

 

見たままだけど一応書いてみる

パラメータ XYZ軸
m41 X
m42 Y
m43 Z

 

試しに移動させてみる。

変更させたい SCNMatrix4 の値をノードの transform に入れて移動させてみる。

// 先ほどの SCNMatrix4 の m を Y軸方向 2 に移動させてみる
m.m42 = 2.0

let node = SCNNode()
node.transform = m

 

コードで World 座標を調べたり、移動させてみる

Scene Editor 上ではあまり World 座標は使わないかもしれないが、 コードで操作する場合、複雑に階層化されたオブジェクトを World 座標に移動させたいこともあると思う。

ノードの worldTransform で 4x4 の行列で現在の移動値が返ってくるのでそれを操作する。

 

以下のコードでは、前回の親ノードが Y 軸 2 にあり、 その子の球(名前を sphere )が Y 軸 0 あるものを World 座標の 0 に移動させてみる。

let sphere = scene?.rootNode.childNode(withName: "sphere", recursively: true)!

var m:SCNMatrix4 = (sphere?.worldTransform)!

print((sphere?.position.x)!) // 0.0
print(m.m42) // 2.0

m.m42 = -2.0 // Y を -2.0 で移動させる

sphere?.transform = m

 

今回、transform に SCNMatrix4 を入れて移動させているが、これまでで使用している SCNVector3 を position 入れる方法でも問題はない。

唯一の注意点としては worldTransform は get のプロパティなので値を代入することはできない。

 

ちなみに、iOS 11 SDK ではもっと便利なノードの操作の API が追加されているので試してみるのも良いのかもしれない。

 

今回はここまで。

iOS で SceneKit を試す(Swift 3) その16 - Scene Editor の Node Inspector

今回はノードに関する属性を設定できる Node Inspector 部分をもうちょっと詳しく見てみる。

 

Node Inspector の中身は何?

Node Inspector は名前の通り SCNNode で設定できる値になっているが、
オブジェクトの中心軸を決める pivot など、設定できない値がいくつかある。

 

設定項目

  • ノードの名前
  • 位置、回転、拡大縮小、編集時の座標(world/local)
  • 透過、表示・非表示、影の設定
  • ノードの属性(ジオメトリ、カメラ、ライト、ボーンなど)
  • アニメーション設定
  • コンストレイント(制約)設定

 

アニメーションはオブジェクトデータの読み込みの際、 コンストレイントは別記事で紹介。

 

f:id:x67x6fx74x6f:20170706153033p:plain

 

Identity

f:id:x67x6fx74x6f:20170706153852p:plain

Name

オブジェクト取得するための名前。

初期値は nil になっており、コード、Scene Editor でオブジェクトを表示する際に名前は必須ではない。

主に scn ファイルを読み込んだシーンをコードから変更を加えたい場合に使う。

例えば Xcode のゲームテンプレートの GameViewController.swift は、
SCNScene に ship.scn ファイルを設定し、
設定したシーンから ship のノードを名前から調べて回転のアニメーションを追加している。

let scene = SCNScene(named: "art.scnassets/ship.scn")!

// ... 中略 ... 

// retrieve the ship node
let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!

// animate the 3d object
ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))

 

Transform

f:id:x67x6fx74x6f:20170706153938p:plain

ノードに対して移動、回転、拡大縮小を設定できる

 

Editing Space

設定が Local と World があり、デフォルトは Local。

今まで使用してきたものが Local の空間となっており、 移動など自分を中心に行うため、親のノードをが移動をするとこのノードは全体の空間での座標と異なる座標になる。

World で移動させた場合、オブジェクトがどの構造になっていても、必ず 0 を原点とした座標で移動できる。

 

空のノード作成。
XYZ を 0, 0, 0 座標に置いた空のノードを親ノードにし、
球を空のノードの子にして XYZ を 0, 0, 0 に設定する。

f:id:x67x6fx74x6f:20170706152630p:plain

 

親を Y 軸方向に 2 に設定。

f:id:x67x6fx74x6f:20170706152731p:plain

 

球は自分の座標をもつため 0 を位置する。

f:id:x67x6fx74x6f:20170706152911p:plain

 

Editing Space を World に変更すると原点からの座標になるため球の座標は 2 になる。

f:id:x67x6fx74x6f:20170706152825p:plain

 

コードで World 座標に移動させる方法は長くなるので別の記事で。

 

Position, Euler, Scale

位置、回転、拡大縮小を X、Y、Z の値で設定変更可能。

位置の初期状態は Local 座標、
回転はラジアンではなく角度、 拡大縮小は 1 が初期値、マイナスでオブジェクトが反転する。

 

Bounding Box

オブジェクトの周りを立方体で囲んだ時の、幅、高さ、奥行きを表し編集はできない。
オブジェクトの初期値から取るため、回転、拡大縮小しても変わらない。

Bounding Box の表示を見たい場合は、 Editor > Display > Show Bounding Box。

拡大縮小させる Bounding Box の表示も変更されるため Bounding Box の値と変わるので注意。

f:id:x67x6fx74x6f:20170706152054p:plain

 

Visibility

f:id:x67x6fx74x6f:20170706154012p:plain

一時的にオブジェクトを非表示にする場合や影についての設定。

 

Opacity

オブジェクトの透明度を 0 〜 1 で設定。
基本、ジオメトリとパーティクルにしか適応できない。

let node = SCNNode()
node.opacity = 0.5 // 半透明になる

 

Visibility

Hidden にチェックを入れるとノードが非表示になる。

チェックを入れると描画されないため、ドローコールやポリンゴン描画、シェーダー、アニメーション、ライトなどでマシンパワーを使用することがなくなる。

let node = SCNNode()
node.isHidden // 表示されなくなる

 

シーンからノードを完全に消したい場合は、
以下のものを使用する。

node.removeFromParentNode()

 

Shadows

デフォルトで Cast Shadow のチェックが入っていている。
Directional、Spot、IES ライトを使用していて、かつこのジオメトリの影を落とせる他のジオメトリがあった場合、このジオメトリの影が対処のジオメトリに描画される。

影を描画する必要がない場合はチェックを外すことで処理を低減できる。

 

Rendering Order

レンダリングする順番。
デフォルトが 0 で値が高いほど後にレンダリングの評価がされる。
パーティクルより前面にジオメトリを表示したいときなど。

 

Category BitMask

描画の際にビットマスクで判別する値。
カメラ、ライト、 SCNTechnique(画面全体に対しての画像処理)に対してこのノードを対象にするかという値。 デフォルトが 1。0 にするといかなる場合でも描画対象から外れる。

物理ボディと物理フィールドの物理判定のビットマスクとは異なるので注意。

 

Attributes

f:id:x67x6fx74x6f:20170706154040p:plain

SCNNode の持つ Node Attributes とは異なり、このノードのチルドノードの種類を指し、
空のチルドノード以外が複数ある場合はここに列挙される。

Node Inspector からは削除はできるが追加はできず、Scene Graph View からノードを移動させて変更する。

以下、変更できるもの。

  • ジオメトリ
  • カメラ
  • ライト
  • ボーン
  • スキナー
  • パーティクル
  • 物理ボディ
  • 物理フィールド

 

Animations

f:id:x67x6fx74x6f:20170706154109p:plain

Scene Editor 上で作成はできない。

外部ファイルを変換する際に自動的に追加されるか、scnanim ファイルを読み込むしかない。
詳しくはオブジェクトデータの読み込みの記事で紹介予定。

ちなみに scnanim はバイナリの plist なのでやろうと思えば自分でつくることができる。
(設定値がめっちゃ多いけど)

 

Constraints

f:id:x67x6fx74x6f:20170706154134p:plain

現状、設定できるのは以下のもの
(Xcode 9 では結構増える)

  • Look At
  • Billboard

詳しくは別記事で紹介する。

 

今回はここまで

ARKit の UI と設計で注意すべき点

UI

基本的には自由だが、3点だけ注意した方よいと思われる。

 

その1 : 起動時

カメラが起動し ARKit 関連の命令が動作するまで数秒かかるので、 それを何らかの方法で伝える。

 

その2 : 平面認識時

平面が認識された時、使い手にはわからないので 平面を認識した何かを表示する。

 

WWDC 2017 Keynote でのデモアプリの UI の動き
状態 画面 平面認識画像
起動時 f:id:x67x6fx74x6f:20170704143642p:plain f:id:x67x6fx74x6f:20170704144010p:plain
ARKit動作 f:id:x67x6fx74x6f:20170704143720p:plain f:id:x67x6fx74x6f:20170704144039p:plain
平面認識アニメーション f:id:x67x6fx74x6f:20170704143748p:plain f:id:x67x6fx74x6f:20170704144744p:plain
平面認識完了 f:id:x67x6fx74x6f:20170704143932p:plain f:id:x67x6fx74x6f:20170704144805p:plain

 

その3 : UI

仮想空間の中に UI をできるだけ配置しない方が良いかも。
自分が動かなければ操作できないし、状況によっては操作不能になる可能性があるのため。

つくるコンテンツによるので何とも言えないが、
オブジェクトの移動やタップぐらいのインタラクションがちょうど良いのではというところ。

 

WWDC 2017 Keynote でのデモアプリでは、オブジェクトを変更する場合は仮想空間の中ではなく、アプリ上の UI から変更する。

f:id:x67x6fx74x6f:20170704143947p:plain

ARKit はヘッドマウントディスプレイをかぶるものとは違う。

現実空間で手で持っているスマートフォンの中という状況や画面の大きさから操作的にわかりづらいことを考慮しているかもしれない。

 

設計

AR としてのコンテンツなので VR 的な表現が主軸になるものは避けた方が良いかもしれない。
見せ方の部分もあるが、単純 ARKit 自体センサーを使いまくるので、バッテリーを食うし発熱するのを防ぐことはできないだろう。
状況によっては VR 用のライブラリを使用した方が端末に優しい可能性がある。

できることなら、Metal 2 の Direct to Display の都合上 View は半透明やマスクはなくフルスクリーンで実行すべし。

 

まとめ

個人的には ARKit は世界に字幕やアノテーションをつけて、見落としがちな身の回りを情報やエンターテイメントとして提供してくれるものだと思っている。

 

現実世界にアノテーションをつける良い例

www.youtube.com