我遇到ARKit轮换问题。我正在创建一个包含My3DPlayer:SCNNode
的节点videoNode:SKVideoNode
。我遇到的问题是它会随机旋转(滚动)。它不会产生任何倾斜或偏航问题,但是,每次我打开应用程序时,它都会沿随机方向旋转。我希望方向正好在我正在使用的锚点上。我有想要的正确尺寸,但是我对旋转有点困惑。
import UIKit
import ARKit
import AVKit
class My3DPlayer: SCNNode {
var player:AVPlayer!
init(geometry: SCNGeometry?) {
super.init()
self.geometry = geometry
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
convenience init(anchor: ARImageAnchor, currentFrame:ARFrame) {
self.init(geometry: nil)
self.createPlayer(anchor, currentFrame)
}
//Returns a 3d Player of a set size
private func createPlayer(_ anchor:ARImageAnchor, _ frame:ARFrame) {
let physicalSize = anchor.referenceImage.physicalSize
print("Init Player W/ physicalSize: \(physicalSize)")
//Create video
let path = Bundle.main.path(forResource: "Bear", ofType: "mov")
let asset = AVAsset(url: URL(fileURLWithPath: path!))
let track = asset.tracks(withMediaType: AVMediaType.video).first!
let playerItem = AVPlayerItem(asset: asset)
self.player = AVPlayer(playerItem: playerItem)
var videoSize = track.naturalSize.applying(track.preferredTransform)
videoSize = CGSize(width: abs(videoSize.width), height: abs(videoSize.height))
print("Init Video W/ size: \(videoSize)")
//Do something when video ended
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying(note:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
//Add observer to determine when Player is ready
player.addObserver(self, forKeyPath: "status", options: [], context: nil)
//Create video Node
let videoNode = SKVideoNode(avPlayer: player)
//Create 2d scene to put 2d player on - SKScene
let scene = SKScene(size: videoSize)
videoNode.position = CGPoint(x: videoSize.width/2, y: videoSize.height/2)
videoNode.size = scene.size
//To adjust to landscape and portrait weird af
videoNode.zRotation = CGFloat(-Double.pi)*90/180
print(videoNode.zRotation * 180/CGFloat(Double.pi))
let width = videoNode.size.width
videoNode.size.width = videoNode.size.height
videoNode.size.height = width
//Add videoNode to scene
scene.addChild(videoNode)
//Get ratio difference from physicalsize and video size
let widthRatio = Float(physicalSize.width)/Float(videoSize.width)
let heightRatio = Float(physicalSize.height)/Float(videoSize.height)
let finalRatio = [widthRatio, heightRatio].min()!
//Create a Plane (SCNPlane) to put the SKScene on
let plane = SCNPlane(width: videoSize.width, height: videoSize.height)
plane.firstMaterial?.diffuse.contents = scene
plane.firstMaterial?.isDoubleSided = true
//Set Self.geometry = plane
self.geometry = plane
//Show Node
self.transform = SCNMatrix4(anchor.transform)
let appearanceAction = SCNAction.scale(to: CGFloat(finalRatio), duration: 0.4)
appearanceAction.timingMode = .easeOut
//Set initial scale to 0 then use action to scale up
self.scale = SCNVector3Make(0, 0, 0)
self.runAction(appearanceAction)
//This rotates it to lay down
self.eulerAngles = SCNVector3(Double.pi*90/180, 0, 0)
}
}
这是我参考图像的方式(我不得不删除用于生成AR图像的真实图像。这是玩起来最方便且易于访问的对象)。
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
guard let imageAnchor = anchor as? ARImageAnchor else {
return
}
guard let currentFrame = self.sceneView.session.currentFrame else {
return
}
DispatchQueue.main.async {
self.videoPlayer3D = My3DPlayer(anchor: imageAnchor, currentFrame: currentFrame)
self.sceneView.scene.rootNode.addChildNode(self.videoPlayer3D)
}
}
以下是一些示例,与垂直的示例相比,有时它是完全水平的。似乎是随机的。