GBF*_*iel 5 ios core-motion scenekit swift
我正在使用SceneKit测试,所以我决定制作一个虚拟现实测试应用程序.我将从设备运动中获取数据,然后根据数据更改摄像机角度.我在iPhone 6上测试,所以没问题.当我在iPhone 5和朋友的iPhone 5S上运行它时,事情变得奇怪,相机将需要一些延迟旋转,与iPhone 6上的瞬间完全不同.Xcode上的FPS在两个设备上保持大约60 FPS,我添加了一些时间测试,并且两个设备上的运动数据也在60Hz左右.我迷路了.
代码的基础是这个项目:https://github.com/stevenjs/VR-iOS-Experiment
如果可能的话,我想了解一些如何修复它的提示,而不仅仅是准备复制和粘贴的代码.我想学.
我无法用文字解释,所以我录制了一些视频来告诉你发生了什么:
iPhone 6:https://www.youtube.com/watch?v = pdyTEwvsR1I
iPhone 5:https://www.youtube.com/watch?v = Dr.DdKtHkrYo
这是代码:
// Create Scene
var scene = SCNScene()
scnView.scene = scene
//scnView.autoenablesDefaultLighting = true
//Add camera to scene.
let camera = SCNCamera()
camera.xFov = 45
camera.yFov = 45
let camerasNode = SCNNode()
camerasNode.camera = camera
camerasNode.position = SCNVector3(x: 0, y: 0, z: 0)
// The user will be holding their device up (i.e. 90 degrees roll from a flat orientation)
// so roll the camera by -90 degrees to orient the view correctly
// otherwise the object will be created "below" the user
camerasNode.eulerAngles = SCNVector3Make(degreesToRadians(-90.0), 0, 0)
let cameraRollNode = SCNNode()
cameraRollNode.addChildNode(camerasNode)
let cameraPitchNode = SCNNode()
cameraPitchNode.addChildNode(cameraRollNode)
let cameraYawNode = SCNNode()
cameraYawNode.addChildNode(cameraPitchNode)
scene.rootNode.addChildNode(cameraYawNode)
scnView.pointOfView = camerasNode
// Ambient Light
let ambientLight = SCNLight()
ambientLight.type = SCNLightTypeAmbient
ambientLight.color = UIColor(white: 0.1, alpha: 1.0)
let ambientLightNode = SCNNode()
ambientLightNode.light = ambientLight
scene.rootNode.addChildNode(ambientLightNode)
// Omni Light
let diffuseLight = SCNLight()
diffuseLight.type = SCNLightTypeOmni
diffuseLight.color = UIColor(white: 1.0, alpha: 1.0)
let diffuseLightNode = SCNNode()
diffuseLightNode.light = diffuseLight
diffuseLightNode.position = SCNVector3(x: -30, y: 30, z: 50)
scene.rootNode.addChildNode(diffuseLightNode)
let material = SCNMaterial()
material.diffuse.contents = UIColor.redColor()
material.locksAmbientWithDiffuse = true
let material2 = SCNMaterial()
material2.diffuse.contents = UIColor.whiteColor()
material2.locksAmbientWithDiffuse = true
let material3 = SCNMaterial()
material3.diffuse.contents = UIColor.blueColor()
material3.locksAmbientWithDiffuse = true
let material4 = SCNMaterial()
material4.diffuse.contents = UIColor.purpleColor()
material4.locksAmbientWithDiffuse = true
let material5 = SCNMaterial()
material5.diffuse.contents = UIColor.yellowColor()
material5.locksAmbientWithDiffuse = true
let material6 = SCNMaterial()
material6.diffuse.contents = UIColor.orangeColor()
material6.locksAmbientWithDiffuse = true
//Create the box
let baseBox = SCNBox(width: 5, height: 5, length: 5, chamferRadius: 0)
baseBox.materials = [material, material2, material3, material4, material5, material6]
let boxNode = SCNNode(geometry: baseBox)
boxNode.position = SCNVector3(x: 0, y: 3, z: -10)
scene.rootNode.addChildNode(boxNode)
// Respond to user head movement
motionManager = CMMotionManager()
motionManager?.deviceMotionUpdateInterval = 1.0 / 60.0
motionManager?.startDeviceMotionUpdatesUsingReferenceFrame(CMAttitudeReferenceFrameXArbitraryZVertical,
toQueue: NSOperationQueue.mainQueue(),
withHandler: { (motion: CMDeviceMotion!, error: NSError!) -> Void in
self.counter++
let currentAttitude = motion.attitude
let roll = Float(currentAttitude.roll)
let pitch = Float(currentAttitude.pitch)
let yaw = Float(currentAttitude.yaw)
//only working at 60FPS on iPhone 6... WHY
//according to documentation, SCNVector3 from a node is, (pitch, yaw, node)
cameraRollNode.eulerAngles = SCNVector3Make(0.0, 0.0, -roll)
cameraPitchNode.eulerAngles = SCNVector3Make(pitch, 0.0, 0.0)
cameraYawNode.eulerAngles = SCNVector3Make(0.0, yaw, 0.0)
})
Run Code Online (Sandbox Code Playgroud)
ric*_*ter 11
嗯,这只是一个预感,但我猜结果是正确的,所以让它正式!
您的问题似乎是在主线程上有两个60Hz定时器/循环争用时间 - CoreMotion更新队列和SceneKit渲染循环.你有效地从一个到另一个进行通信,因为你在CoreMotion更新处理程序中设置了SceneKit状态,并希望SceneKit渲染循环在同一帧上拾取它.
(我怀疑硬件的不同之处在于iPhone 6有足够的性能开销,时间恰好可以正常运行,旧硬件没有 - 所以SceneKit正在拾取模型位置,这些位置是运动数据背后的一两帧. )
相反,在相同的60Hz循环中做所有事情.(实际上,这是一个很好的一般建议,无论你的其他60Hz事件源是CoreMotion还是别的东西 - 在游戏引擎或类似的实时渲染器中,你应该让目标帧率用于渲染来决定你做的其他事情.)
这意味着您应该轮询运动数据,而不是将其推送给您 - 您只关心您正在渲染的帧的时间戳的运动状态,而不是之前1/60秒的样本,或者最后几个丢帧时的样本.使用场景渲染器委托挂钩到SceneKit渲染循环,deviceMotion在您的renderer:updateAtTime:方法中读取CoreMotion 并在那里设置模型旋转.请注意,startDeviceMotionUpdatesUsingReferenceFrame:在开始轮询运动数据之前,仍需要调用.
此外,SceneKit通常仅在知道场景内容需要动画时才运行其渲染循环 - 例如,如果您已将动画附加到场景中的某些内容,或者在事务中设置动画属性,或使用动作或物理.(这样,如果渲染的下一帧与最后一帧相同,它将不会在你的设备的电池中一次又一次地绘制相同的东西.)但是当你期望在动画循环期间进行更改时,你需要确保它一直在运行.
playing在视图上设置属性true实际上是正确的方法 - 它告诉SceneKit你希望它保持渲染,而不是在动画停止时停止.(是的,文档在这一点上可能更清楚......如果你让Apple知道他们可能会修复它.)
最后,一个Swift技巧:您可以直接分配给具有结构类型的属性中的成员,而无需构造一个全新的值,因此不要这样做:
cameraRollNode.eulerAngles = SCNVector3Make(0.0, 0.0, -roll)
cameraPitchNode.eulerAngles = SCNVector3Make(pitch, 0.0, 0.0)
cameraYawNode.eulerAngles = SCNVector3Make(0.0, yaw, 0.0)
Run Code Online (Sandbox Code Playgroud)
你可以这样做:
cameraRollNode.eulerAngles.z = -roll
cameraPitchNode.eulerAngles.x = pitch
cameraYawNode.eulerAngles.y = yaw
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1345 次 |
| 最近记录: |