ARSCNViewでZoomの真似をする
アプリとソースコード公開しています。
ARCamera.
AppStore:https://apps.apple.com/us/app/id1488699740
GitHub:https://github.com/john-rocky/ARCamera
@IBOutlet var sceneView: ARSCNView!
var virtualBackgroundNode = SCNNode()
人物を手前に残す(People Occlution)##
ARSessionにPeople Occlutionを設定しないと、ARコンテンツが人物をオーバーラップしてしまいます。
let config = ARFaceTrackingConfiguration()
if ARFaceTrackingConfiguration.supportsFrameSemantics(.personSegmentation) {
config.frameSemantics.insert(.personSegmentation)
} else {
presentAlert(NSLocalizedString("この端末/OSではピープルオクルージョンを利用できません", comment: ""))
}
sceneView.session.run(config, options: [])
SCNNodeでバーチャル背景をつくる
SCNPlaneをつくり、画像や動画を貼りつけます。
貼り付けるコンテンツはSpriteKitのSKSceneとしてつくります。
動画の場合
let avPlayer = AVPlayer(url: videoUrl)
//画像の縦横比が歪まないように調整しています
var mediaAspectRatio: Double!
guard let track = AVURLAsset(url: url).tracks(withMediaType: AVMediaType.video).first else { return (nil,nil) }
let size = track.naturalSize.applying(track.preferredTransform)
let resolution = (CGSize(width: abs(size.width), height:abs(size.height)),track.preferredTransform)
let width = resolution.0?.width
let height = resolution.0?.height
mediaAspectRatio = Double(width! / height! )
avPlayer.actionAtItemEnd = AVPlayer.ActionAtItemEnd.none;
NotificationCenter.default.addObserver(self,
selector: #selector(ViewController.didPlayToEnd),
name: NSNotification.Name("AVPlayerItemDidPlayToEndTimeNotification"),
object: avPlayer.currentItem)
let skScene = SKScene(size: CGSize(width: 1000 * mediaAspectRatio, height: 1000))
if resolution.1?.b != 0{
skScene.size = CGSize(width: 1000, height: 1000 )
skScene.zRotation = 1.5708
} else if resolution.1?.a != 1.0 {
skScene.zRotation = 1.5708 * 2
}
let skNode = SKVideoNode(avPlayer: avPlayer)
skNode.position = CGPoint(x: skScene.size.width / 2.0, y: skScene.size.height / 2.0)
skNode.size = skScene.size
skNode.yScale = -1.0
if resolution.1?.b != 0{
skNode.zRotation = 1.5708
} else if resolution.1?.a != 1.0 {
skNode.zRotation = 1.5708 * 2
}
skNode.play()
skScene.addChild(skNode)
SCNNodeにコンテンツを貼り付けます。
virtualBackgroundNode.geometry = SCNPlane(width: size, height: size)
let material = SCNMaterial()
material.diffuse.contents = skScene
virtualBackgroundNode.geometry?.materials = [material]
virtualBackgroundNode.scale = SCNVector3(1.7 * mediaAspectRatio, 1.7, 1)
sceneView.scene.rootNode.addChildNode(node)
バーチャル背景をカメラの前に置く
let cameraPosition = sceneView.pointOfView?.scale
let position = SCNVector3(cameraPosition!.x, cameraPosition!.y, cameraPosition!.z - 10)
virtualBackgroundNode.position = position
バーチャル背景の位置を固定する
端末を動かすと、バーチャル背景がずれるので、カメラを追いかけるようにさせます。
rendererメソッドでバーチャル背景にカメラ前ポジションを伝えます。
var frontOfCamera = SCNVector3()
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
let position = SCNVector3(x: 0, y: 0, z: -10.0) // ノードの位置は、左右:0m 上下:0m 奥に50cm
if let camera = sceneView.pointOfView {
virtualBackgroundNode.position = camera.convertPosition(position, to: nil)
virtualBackgroundNode.eulerAngles = camera.eulerAngles
}
}
バーチャル背景の大きさを変えられるようにする
ユーザーがピンチ・ジェスチュアで背景の大きさをちょうど良いサイズに変えられるようにします。
var lastGestureScale:Float = 1
@objc func scenePinchGesture(_ recognizer: UIPinchGestureRecognizer) {
switch recognizer.state {
case .began:
let logation = recognizer.location(in: sceneView)
let hitResults = sceneView.hitTest(logation, options: [SCNHitTestOption.ignoreHiddenNodes:true])
if hitResults.count > 0 {
guard let node = hitResults.first?.node else {return}
materialNode = node
}
lastGestureScale = 1
case .changed:
let newGestureScale: Float = Float(recognizer.scale)
let diff = newGestureScale - lastGestureScale
let currentScale = virtualBackgroundNode.scale
virtualBackgroundNode.scale = SCNVector3Make(
currentScale.x * (1 + diff),
currentScale.y * (1 + diff),
currentScale.z * (1 + diff)
)
lastGestureScale = newGestureScale
default :break
}
}
let pinch = UIPinchGestureRecognizer(
target: self,
action: #selector(type(of: self).scenePinchGesture(_:))
)
pinch.delegate = self
sceneView.addGestureRecognizer(pinch)
ピンチ・ジェスチュアでSCNNodeを操作する方法は、天才プログラマーK-Boyさんのコードをお借りしました。ありがとうございます。
こんな感じで機械学習やARに関する情報を発信しています。
https://twitter.com/JackdeS11