ARKit - ARRreference图像跟踪
ARKit - ARRreferenceImage tracking
我在 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 它指出
Apply Best Practices
This example app simply visualizes where ARKit detects each reference
image in the user’s environment, but your app can do much more. Follow
the tips below to design AR experiences that use image detection well.
Use detected images to set a frame of reference for the AR scene.
Instead of requiring the user to choose a place for virtual content,
or arbitrarily placing content in the user’s environment, use detected
images to anchor the virtual scene. You can even use multiple detected
images. For example, an app for a retail store could make a virtual
character appear to emerge from a store’s front door by recognizing
posters placed on either side of the door and then calculating a
position for the character directly between the posters.
Note
Use the ARSession setWorldOrigin(relativeTransform:) method to
redefine the world coordinate system so that you can place all anchors
and other content relative to the reference point you choose.
Design your AR experience to use detected images as a starting point
for virtual content. ARKit doesn’t track changes to the position or
orientation of each detected image. If you try to place virtual
content that stays attached to a detected image, that content may not
appear to stay in place correctly. Instead, use detected images as a
frame of reference for starting a dynamic scene. For example, your app
might recognize theater posters for a sci-fi film and then have
virtual spaceships appear to emerge from the posters and fly around
the environment.
所以我尝试将我的世界变换设置为等于我的图像锚点的变换
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
被删除,任何时候再次检测到它时,您都必须处理是否应该添加内容,这很棘手,因为 ARImageAnchor.identifier
总是referenceImage
相同,无论它是否被删除,然后 re-added 因此很难存储在 dictionary
等中。因此,根据您的需要,您需要找到一个确定该位置是否存在内容以及是否重新添加等的方法
你关于 setWorldOrigin
的问题的最后一部分似乎有点像你说的那样奇怪,但也许你可以添加一个 Bool 来防止它可能发生变化,例如:
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)
}
}
希望我的回答能为您提供一个有用的起点,当然假设我已经正确解释了您的问题,
我在 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 它指出
Apply Best Practices
This example app simply visualizes where ARKit detects each reference image in the user’s environment, but your app can do much more. Follow the tips below to design AR experiences that use image detection well.
Use detected images to set a frame of reference for the AR scene. Instead of requiring the user to choose a place for virtual content, or arbitrarily placing content in the user’s environment, use detected images to anchor the virtual scene. You can even use multiple detected images. For example, an app for a retail store could make a virtual character appear to emerge from a store’s front door by recognizing posters placed on either side of the door and then calculating a position for the character directly between the posters.
Note
Use the ARSession setWorldOrigin(relativeTransform:) method to redefine the world coordinate system so that you can place all anchors and other content relative to the reference point you choose.
Design your AR experience to use detected images as a starting point for virtual content. ARKit doesn’t track changes to the position or orientation of each detected image. If you try to place virtual content that stays attached to a detected image, that content may not appear to stay in place correctly. Instead, use detected images as a frame of reference for starting a dynamic scene. For example, your app might recognize theater posters for a sci-fi film and then have virtual spaceships appear to emerge from the posters and fly around the environment.
所以我尝试将我的世界变换设置为等于我的图像锚点的变换
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
被删除,任何时候再次检测到它时,您都必须处理是否应该添加内容,这很棘手,因为 ARImageAnchor.identifier
总是referenceImage
相同,无论它是否被删除,然后 re-added 因此很难存储在 dictionary
等中。因此,根据您的需要,您需要找到一个确定该位置是否存在内容以及是否重新添加等的方法
你关于 setWorldOrigin
的问题的最后一部分似乎有点像你说的那样奇怪,但也许你可以添加一个 Bool 来防止它可能发生变化,例如:
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)
}
}
希望我的回答能为您提供一个有用的起点,当然假设我已经正确解释了您的问题,