Swift中基于ARKit稳定USDZ模型位置:漂移问题解决方案求助
ARKit USDZ模型与实物对齐的漂移问题咨询
我正在用Swift开发一款基于ARKit的质量检测APP,需求是将USDZ模型和现实中的对应实物精准对齐(效果类似通过图像锚点辅助的实时对齐视频)。
试过图像跟踪和平面检测两种方法,初始对齐能实现,但存在漂移问题:用户围绕物体移动时,模型会随时间偏移。我想尝试先通过平面检测放置模型(这似乎是锚定物体的最佳方式),再在检测到图像锚点时重置模型位置。但我搞不懂视频里随意放置的扑克牌怎么发挥作用——我能理解它们可以用于Z方向重锚定,但它们本身没有已知坐标,真的能帮助校准X和Y方向吗?
恳请各位提供建议或方案,或许我忽略了更适合这个任务的其他方法。
更新
我采用了基于状态的流程,需要用户完成以下操作:
- 选择平面
- 在平面上选择第一个点
- 在平面上选择第二个点
之后会把模型添加到所选平面,并根据两点间的角度旋转模型。
USDZ模型的原点位于中心线,但用户通常希望将对应表面与所选平面对齐,因此需要通过GUI控件手动上下左右移动模型来调整到最终位置。
以下是我目前用于初始放置模型的代码:
选择目标平面
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) { guard let updatedAnchor = anchor as? ARPlaneAnchor, let selectedAnchor = selectedPlaneAnchor, updatedAnchor.identifier == selectedAnchor.identifier else { return } self.selectedPlaneAnchor = updatedAnchor }
获取定义旋转的第一和第二点
@objc func handleTap(_ gestureRecognizer: UITapGestureRecognizer) { // 获取点击在sceneView中的位置 let tapLocation = gestureRecognizer.location(in: sceneView) // 执行命中测试,找到点击位置的ARPlaneAnchor let hitTestResults = sceneView.hitTest(tapLocation, types: .existingPlaneUsingExtent) if let result = hitTestResults.first { if let detectedPlaneAnchor = result.anchor as? ARPlaneAnchor { let p3 = result.worldTransform.columns.3 switch currentState { case .initial, .loading, .ready: break case .surface: if selectedPlaneAnchor == nil { selectedPlaneAnchor = detectedPlaneAnchor currentState = .point1 } case .point1: if detectedPlaneAnchor.identifier == selectedPlaneAnchor?.identifier { firstPoint = SCNVector3(p3.x,p3.y,p3.z) addPointNode(location: firstPoint!) currentState = .point2 } case .point2: if detectedPlaneAnchor.identifier == selectedPlaneAnchor?.identifier { secondPoint = SCNVector3(p3.x,p3.y,p3.z) addPointNode(location: secondPoint!) addAssemblyNode() currentState = .ready } } } } }
将模型添加到平面并相应旋转
func addAssemblyNode() { guard let usdzURL = Bundle.main.url(forResource: "art.scnassets/assembly", withExtension: "usdz"), let p1 = firstPoint, let p2 = secondPoint else { return } let assemblyScene = try! SCNScene(url: usdzURL, options: nil) let directionVector = SCNVector3(p2.x - p1.x, p2.y - p1.y,p2.z - p1.z) let rotationAngle = atan2f(directionVector.z, directionVector.x) if let node = assemblyScene.rootNode.childNode(withName: "main", recursively: true) { node.name = "main" node.position = p1 node.eulerAngles.y = -rotationAngle //node.scale = SCNVector3(x: 0.125, y: 0.125, z: 0.125) sceneView.scene.rootNode.addChildNode(node) assemblyNode = node } }
另有视频展示了漂移效果:当回到初始位置时,末端的蓝色大平板会回到原位。
内容的提问来源于stack exchange,提问作者Joel S.
相关产品推荐
相关产品推荐

