我正在ARKit中玩ARReferenceImages,我试图在识别参考图像时添加一个SCNNode,然后将该节点保留在原位,而不管是否在其他地方识别相同的参考图像。
我可以正确添加我的 SCNode,但是如果我移动我的标记,它会再次拾取它并将我放置的节点移动到标记的位置。
我要添加的代码如下:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
guard let imageAnchor = anchor as? ARImageAnchor else { return }
let referenceImage = imageAnchor.referenceImage
print("MAPNODE IS NIL = (self.mapNode == nil)")
updateQueue.async {
if self.mapNode == nil {
// Create a plane to visualize the initial position of the detected image.
let plane = SCNPlane(width: 1.2912,
height: 1.2912)
let planeNode = SCNNode(geometry: plane)
planeNode.opacity = 1
/*
`SCNPlane` is vertically oriented in its local coordinate space, but
`ARImageAnchor` assumes the image is horizontal in its local space, so
rotate the plane to match.
*/
planeNode.eulerAngles.x = -.pi / 2
self.mapNode = planeNode
/*
Image anchors are not tracked after initial detection, so create an
animation that limits the duration for which the plane visualization appears.
*/
// Add the plane visualization to the scene.
node.addChildNode(planeNode)
}
}
}
阅读此处的文档 https://developer.apple.com/documentation/arkit/recognizing_images_in_an_ar_experience#2958517 它指出
应用最佳实践
此示例应用仅可视化 ARKit 检测到每个引用的位置 图像,但你的应用可以执行更多操作。跟随 以下提示用于设计能够很好地使用图像检测的 AR 体验。
使用检测到的图像为 AR 场景设置参考框架。 而不是要求用户为虚拟内容选择一个位置, 或任意将内容放置在用户的环境中,使用检测到 用于锚定虚拟场景的图像。您甚至可以使用多个检测到的 图像。例如,零售商店的应用程序可以制作虚拟 角色似乎通过识别从商店的前门出现 海报放在门的两侧,然后计算 角色的位置直接在海报之间。
注意
使用 ARSession setWorldOrigin(relativeTransform:) 方法将 重定义世界坐标系,以便可以放置所有定位点 以及相对于您选择的参考点的其他内容。
设计您的 AR 体验以使用检测到的图像作为起点 对于虚拟内容。ARKit 不会跟踪位置或 每个检测到的图像的方向。如果您尝试放置虚拟 保留附加到检测到的图像的内容,该内容可能不会 似乎正确保持原位。相反,使用检测到的图像作为 启动动态场景的参考框架。例如,您的应用 可能会认出科幻电影的剧院海报,然后有 虚拟宇宙飞船似乎从海报中出现并飞来飞去 环境。
所以我尝试将我的世界变换设置为等于图像定位点的变换
self.session.setWorldOrigin(relativeTransform: imageAnchor.transform)
但是,我的mapNode跟随imageAnchor移动到哪里。我还没有实现renderer update
方法,所以我不确定为什么它会继续前进。
我假设setWorldOrigin
方法不断更新到 imageAnchor.transform,而不仅仅是那个时刻,这很奇怪,因为代码只调用一次。有什么想法吗?
如果要在ARImageAnchor
的位置添加mapNode,则可以在ARImageAnchor
的变换处设置mapNode的位置,并将其添加到场景中,但如果有意义,则不链接到参考图像。
这可以像这样完成:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
//1. If Out Target Image Has Been Detected Than Get The Corresponding Anchor
guard let currentImageAnchor = anchor as? ARImageAnchor else { return }
//2. An ImageAnchor Is Only Added Once For Each Identified Target
print("Anchor ID = (currentImageAnchor.identifier)")
//3. Add An SCNNode At The Position Of The Identified ImageTarget
let nodeHolder = SCNNode()
let nodeGeometry = SCNBox(width: 0.02, height: 0.02, length: 0.02, chamferRadius: 0)
nodeGeometry.firstMaterial?.diffuse.contents = UIColor.cyan
nodeHolder.geometry = nodeGeometry
nodeHolder.position = SCNVector3(currentImageAnchor.transform.columns.3.x,
currentImageAnchor.transform.columns.3.y,
currentImageAnchor.transform.columns.3.z)
augmentedRealityView?.scene.rootNode.addChildNode(nodeHolder)
}
在问题的另一部分中,您似乎暗示要检测同一图像的多次出现。我可能是错的,但我认为唯一的方法是删除参考图像的相应ARImageAnchor
,这可以像这样完成(通过在最后一个代码片段的末尾添加它):
augmentedRealitySession.remove(anchor: currentImageAnchor)
这里的问题是,一旦删除了ARImageAnchor
,每当再次检测到它时,您都必须处理是否应该添加内容,这很棘手,因为referenceImage
的ARImageAnchor.identifier
始终相同,无论它是否被删除然后重新添加,因此很难存储在dictionary
等中。因此,根据您的需要,您需要找到一种方法来确定该位置是否存在内容以及是否重新添加它等。
你关于setWorldOrigin
的问题的最后一部分似乎有点奇怪,就像你说的那样,但也许你可以添加一个布尔值来防止它发生潜在的变化,例如:
var hasSetWorldOrigin = false
然后基于此,您可以确保它只设置一次,例如:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
//1. If Out Target Image Has Been Detected Than Get The Corresponding Anchor
guard let currentImageAnchor = anchor as? ARImageAnchor else { return }
//2. If We Havent Set The World Origin Set It Based On The ImageAnchorTranform
if !hasSetWorldOrigin{
self.augmentedRealitySession.setWorldOrigin(relativeTransform: currentImageAnchor.transform)
hasSetWorldOrigin = true
//3. Create Two Nodes To Add To The Scene And Distribute Them
let nodeHolderA = SCNNode()
let nodeGeometryA = SCNBox(width: 0.04, height: 0.04, length: 0.04, chamferRadius: 0)
nodeGeometryA.firstMaterial?.diffuse.contents = UIColor.green
nodeHolderA.geometry = nodeGeometryA
let nodeHolderB = SCNNode()
let nodeGeometryB = SCNBox(width: 0.04, height: 0.04, length: 0.04, chamferRadius: 0)
nodeGeometryB.firstMaterial?.diffuse.contents = UIColor.red
nodeHolderB.geometry = nodeGeometryB
if let cameraTransform = augmentedRealitySession.currentFrame?.camera.transform{
nodeHolderA.simdPosition = float3(cameraTransform.columns.3.x,
cameraTransform.columns.3.y,
cameraTransform.columns.3.z)
nodeHolderB.simdPosition = float3(cameraTransform.columns.3.x + 0.2,
cameraTransform.columns.3.y,
cameraTransform.columns.3.z)
}
augmentedRealityView?.scene.rootNode.addChildNode(nodeHolderA)
augmentedRealityView?.scene.rootNode.addChildNode(nodeHolderB)
}
}
希望我的回答能为你提供一个有用的起点,假设我当然正确地解释了你的问题,