- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在使用 SceneKit 进行测试,所以我决定制作一个虚拟现实测试应用程序。我将从设备运动中获取数据,然后根据数据更改摄像机角度。我在 iPhone 6 上进行测试,所以没问题。当我在 iPhone 5 和 friend 的 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=MlDdKtHkrYo
代码如下:
// 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)
})
最佳答案
好吧,这只是一种预感,但我想它是正确的,所以让我们把它正式化吧!
您的问题似乎是有两个 60Hz 计时器/循环在主线程上争用时间 — CoreMotion 更新队列和 SceneKit 渲染循环。您正在有效地从一个到另一个进行通信,因为您在 CoreMotion 更新处理程序中设置 SceneKit 状态,并希望 SceneKit 渲染循环在同一帧上拾取它。
(我怀疑硬件差异在于 iPhone 6 有足够的性能开销,以至于时序恰好可以正常工作,而较旧的硬件则不然——所以 SceneKit 正在拾取比你的模型落后一两帧的模型位置运动数据。)
相反,在同一个 60Hz 循环中执行所有操作。 (实际上,这是一个很好的一般性建议,无论您的其他 60Hz 事件源是 CoreMotion 还是其他东西 — 在游戏引擎或类似的实时渲染器中,您应该让渲染的目标帧率决定您所做的一切。)
这意味着您应该轮询运动数据,而不是将其推送给您——您只关心您正在渲染的帧的时间戳的运动状态,而不是来自的样本之前 1/60 秒,或者如果丢帧,最后几个样本。使用 scene renderer delegate 连接到 SceneKit 渲染循环, 阅读 CoreMotion 的 deviceMotion
在您的 renderer:updateAtTime:
方法中并在那里设置您的模型旋转。请注意,您仍然需要调用 startDeviceMotionUpdatesUsingReferenceFrame:
在开始轮询运动数据之前。
此外,SceneKit 通常仅在知道场景内容需要动画时才运行其渲染循环——例如如果您已将动画附加到场景中的某物,或在事务中设置动画属性,或使用 Action 或物理。 (这样,如果渲染的下一帧与上一帧相同,它就不会耗尽设备的电池一次又一次地绘制相同的东西。)但是当您希望在动画循环期间进行更改时,你需要确保它一直在运行。
设置playing
将 View 上的属性设置为 true
实际上是正确的方法——它告诉 SceneKit 你希望它继续渲染,而不是在动画停止时停止。 (是的,文档在这一点上可能会更清楚......如果你 let Apple know 他们可能会修复它。)
最后,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)
你可以这样做:
cameraRollNode.eulerAngles.z = -roll
cameraPitchNode.eulerAngles.x = pitch
cameraYawNode.eulerAngles.y = yaw
关于ios - iPhone 5 上的 SceneKit 和 CoreMotion "lagging"但在 iPhone 6 上正常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29283877/
我正在尝试使用 CoreMotion 获取设备加速。我有这个代码: 用于设置 if (motionManager == nil) motionManager = [[CMMotionM
我正在使用 CoreMotion 获取罗盘航向,我注意到罗盘航向存在一些问题。 首先我初始化了 CoreMotion。我得到了一个 CMMotionManager 对象 locationManager
以下是我在 vievDidLoad 中的代码 CMMotionManager *motionmanager = [[[CMMotionManager alloc]init]autorelease];
我试图使用内置加速度计在 x 轴上移动播放器,但出了点问题。当我在我的 iPhone 上模拟应用程序时,节点会向各个方向移动,只有在我关闭应用程序并再次启动它 2-3 次后,节点才会从左向右移动,这正
import UIKit import CoreMotion class ViewController: UIViewController { @IBOutlet weak var label
startDeviceMotionUpdatesUsingReferenceFrame CMAttitudeReferenceFrame 有什么区别 XArbitraryZVertical XArbi
我一直在我编写的应用程序中使用一些 CoreMotion(计步器)数据。早些时候,我授予了应用程序数据访问权限,一切运行良好。 现在我要编写请求用户许可的部分,但由于我已经授予了权限,所以对话框永远不
是否可以使用 CoreMotion 的数据计算 iPhone 移动时的高度差? 例如,保存 iPhone 的初始位置,然后移动 iPhone,从而得到新的位置。我有兴趣检测 iPhone 的高度是否从
借助最新 iOS 设备中的 M7 芯片,当用户使用 CMMotionActivityManager 从静止状态变为运行、步行等状态时,可以通过编程方式获得通知。 Stava 和 Runkeeper 都
在 iOS CoreMotion Framework 中,我可以设置加速度计、磁力计等的频率间隔,并以指定的间隔捕获数据。但文档中提到,最小和最大频率取决于设备的硬件。我怎么知道我可以提供的最小和最大
这是我所做的: motion_manager.startAccelerometerUpdates(to: OperationQueue.current! , withHandler: { (
我需要使用 Core Motion 获取用户在后台的事件。我通过将位置更新添加为后台模式并启用后台位置获取来实现此目标。但由于我对用户位置不感兴趣,这会导致电池浪费,并且会出现一个蓝色标志(iPhon
当在 iPhone 5S 上使用来自 M7 运动协处理器的数据时,我看到一些类让用户授予应用程序权限,(有点像他们对 GPS 使用或照片库所做的) 有谁知道哪些核心运动类要求用户允许运动访问,因为我想
我正在尝试编写一个简单的应用程序,让我可以使用 CoreMotion API 跟踪我在设定天数内的平均步行时间。 CMPedometer API 允许访问上次 session 的开始日期和结束日期。我
我想使用 CoreMotion(如果可能,不是 CoreLocation)计算指南针指向真北的航向。我找到了一些公式,但只有当手机平放在 table 上时才有效。谁能帮我找到一种计算罗盘航向的方法,它
在Info.plist中添加“Privacy - Motion Usage Description”后 我运行了它并且成功了,甚至在第一次运行时请求了许可,但我拒绝了许可,现在我卡住了,因为我找不到如
我正在注册以接收来自 CMMotionManager 的更新,如下所示: motionManager.startDeviceMotionUpdatesToQueue(deviceMotionQueue
是否可以使用 CoreMotion 计算小距离? 例如,用户向上或向下、向左和向右移动他的 iOS 设备并面向他面前的设备(横向)。 最佳答案 编辑 按照 promise 链接... https://
我正在制作类似增强现实应用程序的东西,其中我有一个 OpenGL 场景,无论 iOS 设备如何移动,我都希望它与重力保持一致。我以为我已经通过 CMDeviceMotion.attitude.pitc
Apple 的文档CMAttitudeReferenceFrame说一些引用系“可能需要移动设备来校准磁力计”但没有详细说明。 如何确定磁力计当前是否需要校准? 最佳答案 CMDeviceMotion
我是一名优秀的程序员,十分优秀!