嘿,我想弄清楚。如何保持一个简单的节点到位。当我在 ARKit 中四处走动时
代码:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
if let planeAnchor = anchor as? ARPlaneAnchor {
if planeDetected == false { // Bool only allows 1 plane to be added
planeDetected = true
self.addPlane(node: node, anchor: planeAnchor)
}
}
}
这添加了 SCNNode
func addPlane(node: SCNNode, anchor: ARPlaneAnchor) {
// We add the anchor plane here
let showDebugVisuals = Bool()
let plane = Plane(anchor, showDebugVisuals)
planes[anchor] = plane
node.addChildNode(plane)
// We add our custom SCNNode here
let scene = SCNScene(named: "art.scnassets/PlayerModel.scn")!
let Body = scene.rootNode.childNode(withName: "Body", recursively: true)!
Body.position = SCNVector3.positionFromTransform(anchor.transform)
Body.movabilityHint = .movable
wrapperNode.position = SCNVector3.positionFromTransform(anchor.transform)
wrapperNode.addChildNode(Body)
scnView.scene.rootNode.addChildNode(wrapperNode)
我尝试添加一个平面/ anchor 节点并将“主体”节点放入其中,但它仍然会移动。我想这可能与更新功能有关。
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
}
或者最有可能的位置设置
wrapperNode.position = SCNVector3.positionFromTransform(anchor.transform)
我查看了互联网上的每个源/项目文件/视频,但没有人对这个简单的问题有简单的解决方案。
最佳答案
这里可能会发生两种“移动”。
一个是 ARKit 不断完善其对设备在现实世界中的位置如何映射到您放置虚拟内容的抽象坐标空间的估计。例如,假设您将虚拟对象放在 (0 , 0, -0.5)
,然后将设备向左移动 10 厘米。仅当 ARKit 精确跟踪移动时,虚拟对象才会出现在物理空间中。但是视觉惯性里程计并不是一门精确的科学,所以 ARKit 可能认为你向左移动了 10.5 厘米——在这种情况下,你的虚拟对象看起来会向右“滑动”5 毫米,即使它是ARKit/SceneKit 坐标空间中的位置保持不变。
除了希望 Apple 制造配备更好的传感器、更好的相机或更好的 CPU/GPU 并改进世界跟踪科学的设备外,您对此无能为力。 (在适当的时候,这可能是一个安全的选择,尽管这可能对您当前的项目没有帮助。)
由于您还要处理平面检测,因此还有另一个问题。 ARKit 不断完善其对检测到的平面所在位置的估计。因此,即使飞机在现实世界中的位置没有改变,它在 ARKit/SceneKit 坐标空间中的位置却在改变。
这种运动通常是一件好事——如果您希望虚拟对象看起来锚定在真实世界的表面上,您需要确定该表面的位置。随着平面检测更加确定表面的位置,您会看到一些移动,但在短时间后,当您移动相机以寻找平面锚定的虚拟对象时,您应该看到比那些只是漂浮在世界中的虚拟对象更少的“滑动”空间。
但是,在您的代码中,您没有利用平面检测来使您的自定义内容(来自“PlayerModel.scn”)固定在平面 anchor 上:
wrapperNode.position = SCNVector3.positionFromTransform(anchor.transform)
wrapperNode.addChildNode(Body)
scnView.scene.rootNode.addChildNode(wrapperNode)
此代码使用平面 anchor 的初始 位置在世界空间中定位wrapperNode
(因为您要使它成为根节点的子节点)。如果您改为将 wrapperNode
设为平面 anchor 节点(您在 renderer(_:didAdd:for:)
中收到的节点)的子节点,它将保持附加到平面,因为 ARKit 改进了它对平面位置的估计。最初你会得到更多的运动,但随着平面检测“稳定”,你的虚拟对象将“滑动”得更少。
(当你使节点成为平面的子节点时,你不需要设置它的位置——位置为零意味着它就在平面所在的位置。在任何情况下,你只需要设置它相对于平面——即在它之上/之下/沿着它有多远。)
关于ios - 如何将 ARKit SCNNode 保持在原位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45020192/